AOP是Aspect Oriented Programming的缩写,意思是面向方面编程,一种新兴的编程技术。
AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,
AOP可以说也是这种目标的一种实现。它可以解决OOP和过程化方法不能够很好解决的横切
(crosscut)问题,
如:事务、安全、日志等横切关注。当未来系统变得越来越复杂,
横切关注点就成为一个大问题的时候,AOP就可以很轻松的解决横切关注点这个问题。
比如有这样一个情景:
Java代码
1.public class AccountManager { 
2.    private static final sysLogger = Instance(); 
3.    private AuthorizationManager authMgr = new AuthorizationManager(); 
4.     
5.    public void transferFunds(String from, String to, int amount) { 
6.        sysLogger.log("transfer funds from " + from + " to " + to); 
7.        if(authMgr.accessAble(from) && authMgr.accessAble(to)) { 
8.            sysLogger.log("access successfully"); 
9.            CustomerAccount from = findAccount(from); 
10.            CustomerAccount to = findAccount(to); 
11.            from.debit(amount); 
12.            to.credit(amount); 
13.        } else { 
14.            sysLogger.log("access deny"); 
15.        } 
16.        sysLogger.log("transfer funds from " + from + " to " + to + " $" + amount + " successfully!"); 
17.    } 
18.} 
public class AccountManager {
private static final sysLogger = Instance();
private AuthorizationManager authMgr = new AuthorizationManager();
public void transferFunds(String from, String to, int amount) {
sysLogger.log("transfer funds from " + from + " to " + to);
if(authMgr.accessAble(from) && authMgr.accessAble(to)) {
sysLogger.log("access successfully");
CustomerAccount from = findAccount(from);
CustomerAccount to = findAccount(to);
from.debit(amount);
} else {
sysLogger.log("access deny");
}
sysLogger.log("transfer funds from " + from + " to " + to + " $" + amount + " successfully!");
}
}
这个例子虽然是很好的面向对象代码,但是在业务处理逻辑中夹杂这日志处理和权限判断,变得复杂混乱.
在 AOP 中,正交关注点(如安全和日志记录)被识别为系统中的常见横切关注点。说它们是横切,
是因为它们总是切入模块(如包、类和代码文件)的多个单位。也许横切关注点可能不是核心业务逻辑的一部分,但是它们是应用程序的基本部分。
AOP的实现主要是通过方法的拦截实现.在不使用AOP框架的情况下,我们可以通过JDK提供的动态代理来实现方法的拦截
注意:使用JDK提供的动态代理实现
要求我们的目标对象必须实现接口
IUserBean接口
Java代码
1.hou.aop; 
2. 
3.public interface I
UserBean { 
4.     
5.    public void getUser(); 
6.     
7.    public void addUser(); 
8.     
9.    public void updateUser(); 
10.     
11.    public void deleteUser(); 
12.} 
hou.aop;
public interface IUserBean {
public void getUser();
public void addUser();
public void updateUser();
public void deleteUser();
}
IUserBean实现类 UserBean.java
Java代码
1.hou.aop; 
2. 
3.public class UserBean implements IUserBean { 
4.     
5.    private String user = null; 
6.     
7.    public UserBean() { 
8.    } 
9. 
10.    public UserBean(String user) { 
11.        this.user = user; 
12.    } 
13.     
14.    public void setUser(String user) { 
15.        this.user = user; 
16.    } 
17. 
18.    public void addUser() { 
19.        System.out.println("this is addUser() method!"); 
20.    } 
21. 
22.    public void deleteUser() { 
23.        System.out.println("this is deleteUser() method!"); 
24.    } 
25. 
26.    public void getUser() { 
27.        System.out.println("this is getUser() method!"); 
28.    } 
29. 
30.    public void updateUser() { 
31.        System.out.println("this is updateUser() method!"); 
32.    } 
33.} 
hou.aop;
public class UserBean implements IUserBean {
private String user = null;
public UserBean() {
}
public UserBean(String user) {
this.user = user;
}
public void setUser(String user) {
this.user = user;
}
public void addUser() {
System.out.println("this is addUser() method!");
}
public void deleteUser() {
System.out.println("this is deleteUser() method!");
}
public void getUser() {
System.out.println("this is getUser() method!");
}
public void updateUser() {
System.out.println("this is updateUser() method!");
}
}spring aop应用场景
我们希望在UserBean执行方法之前先检查userName是不是为空,以此做为权限判断.
当然我们可以在没个方法里面去加这些判断,但是这需要为每个方法都添加同样的判断,维护不便.
使用JDK提供的动态代理技术可以很方便的实现上面的需求:
通过flect.Proxy;提供的
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
方法可以生成一个动态代理对象
其中
loader是类装载器
interfaces是目标对象实现的一系列接口
h是一个实现InvocationHandler接口的类,我们对代理对象的所有操作都经过它处理
这样我们就可以拦截到UserBean的方法,在方法执行前先判断是否有权限,如果有则执行方法,
没有权限的话就不执行方法.
编写我们的代理类:
JDKProxy.java
Java代码
1.hou.aop; 
2. 
3.import flect.InvocationHandler; 
4.import flect.Method; 
5.import java.lan
6. 
7.public class JDKProxy implements InvocationHandler { 
8.     
9.    private Object targetObject; 
10.     
11.    public Object createProxyObject(Object targetObject) { 
12.        this.targetObject = targetObject; 
13.        //生成代理对象 
14.        wProxyInstance(Class().getClassLoader(),Class().getInterfaces(),this); 
15.    } 
16. 
17.    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
18.        UserBean userBean = (UserBean) targetObject; 
19.        String userName = UserName(); 
20.        Object result = null; 
21.        //权限判断 
22.        if(userName!=null && !"".equals(userName)) { 
23.            //调用目标对象的方法 
24.            result = method.invoke(targetObject, args); 
25.        }   
26.        return result; 
27.    } 
28.} 
hou.aop;
import flect.InvocationHandler;
import flect.Method;
import flect.Proxy;
public class JDKProxy implements InvocationHandler {
private Object targetObject;
public Object createProxyObject(Object targetObject) {
this.targetObject = targetObject;
//生成代理对象
wProxyInstance(Class().getClassLoader(),Class().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
UserBean userBean = (UserBean) targetObject;
String userName = UserName();
Object result = null;
//权限判断
if(userName!=null && !"".equals(userName)) {
//调用目标对象的方法
result = method.invoke(targetObject, args);
}
return result;
}
}
通过调用createProxyObject可以生成代理对象,
编写测试类如下:
Java代码
1.hou.aop; 
2. 
3.public class TestProxy { 
4.     
5.    public static void main(String[] args) { 
6.        JDKProxy jProxy = new JDKProxy(); 
7.        IUserBean userBean = (IUserBean) ateProxyObject(new UserBean("royzhou")); 
8.        userBean.addUser(); 
9.    } 
10.} 
hou.aop;
public class TestProxy {
public static void main(String[] args) {
JDKProxy jProxy = new JDKProxy();
IUserBean userBean = (IUserBean) ateProxyObject(new UserBean("royzhou"));
userBean.addUser();
}
}
执行成功后输出:
this is addUser() method!
再次修改测试类:
Java代码
1.hou.aop; 
2. 
3.public class TestProxy { 
4.     
5.    public static void main(String[] args) { 
6.        JDKProxy jProxy = new JDKProxy(); 
7.        IUserBean userBean = (IUserBean) ateProxyObject(new UserBean()); 
8.        userBean.addUser(); 
9.    } 
10.} 
hou.aop;
public cla
ss TestProxy {
public static void main(String[] args) {
JDKProxy jProxy = new JDKProxy();
IUserBean userBean = (IUserBean) ateProxyObject(new UserBean());
userBean.addUser();
}
}
即当用户没有权限时,控制台不输出东西,说明我们拦截方法对其做的权限判断生效了.
从上面这个例子可以成功拦截了调用的方法并对其做了相应的处理
如果不使用JDK提供的Proxy类
通过cglib创建代理类,好处是不要求我们的目标对象实现接口
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Class());
enhancer.setCallback(this); //回调,参数是一个实现MethodInterceptor接口的类,我们对代理对象的所有操作都经过它处理
ate(); //创建代理对象
修改UserBean 去掉IUserBean接口
Java代码
1.hou.aop; 
2. 
3.public class UserBean { 
4.     
5.    private String userName = null; 
6.     
7.    public UserBean() { 
8.    } 
9. 
10.    public UserBean(String userName) { 
11.        this.userName = userName; 
12.    } 
13. 
14.    public void addUser() { 
15.        System.out.println("this is addUser() method!"); 
16.    } 
17. 
18.    public void deleteUser() { 
19.        System.out.println("this is deleteUser() method!"); 
20.    } 
21. 
22.    public void getUser() { 
23.        System.out.println("this is getUser() method!"); 
24.    } 
25. 
26.    public void updateUser() { 
27.        System.out.println("this is updateUser() method!"); 
28.    } 
29. 
30.    public String getUserName() { 
31.        return userName; 
32.    } 
33. 
34.    public void setUserName(String userName) { 
35.        this.userName = userName; 
36.    } 
37.} 
hou.aop;
public class UserBean {
private String userName = null;
public UserBean() {
}
public UserBean(String userName) {
this.userName = userName;
}
public void addUser() {
System.out.println("this is addUser() method!");
}
public void deleteUser() {
System.out.println("this is deleteUser() method!");
}
public void getUser() {
System.out.println("this is getUser() method!");
}
public void updateUser() {
System.out.println("this is updateUser() method!");
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
通过cglib创建代理类
CGLibProxy.java
Java代码
1.hou.aop; 
2. 
3.import flect.Method; 
4. 
5.import lib.proxy.Enhancer; 
6.import lib.proxy.MethodInterceptor; 
7.import lib.proxy.MethodProxy; 
8. 
9.public class CGLibProxy implements MethodInterceptor { 
10.       
11.    private Object targetObject; 
12.     
13.    public Object createProx
yObject(Object targetObject) { 
14.        this.targetObject = targetObject; 
15.        Enhancer enhancer = new Enhancer(); 
16.        enhancer.setSuperclass(Class()); //非final 进行覆盖 
17.        enhancer.setCallback(this); //回调,通过 
18.        ate(); //创建代理对象 
19.    } 
20. 
21.    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 
22.        UserBean userBean = (UserBean) targetObject; 
23.        String userName = UserName(); 
24.        Object result = null; 
25.        if(userName!=null && !"".equals(userName)) { 
26.            //调用目标对象的方法 
27.            result = methodProxy.invoke(targetObject, args); 
28.        }   
29.        return result; 
30.    } 
31.} 
hou.aop;
import flect.Method;
import lib.proxy.Enhancer;
import lib.proxy.MethodInterceptor;
import lib.proxy.MethodProxy;
public class CGLibProxy implements MethodInterceptor {
private Object targetObject;
public Object createProxyObject(Object targetObject) {
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Class()); //非final 进行覆盖
enhancer.setCallback(this); //回调,通过
ate(); //创建代理对象
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
UserBean userBean = (UserBean) targetObject;
String userName = UserName();
Object result = null;
if(userName!=null && !"".equals(userName)) {
//调用目标对象的方法
result = methodProxy.invoke(targetObject, args);
}
return result;
}
}
编写测试类:
Java代码
1.hou.aop; 
2. 
3.public class TestProxy { 
4.     
5.    public static void main(String[] args) { 
6.        CGLibProxy cProxy = new CGLibProxy(); 
7.        UserBean userBean = (UserBean) ateProxyObject(new UserBean("royzhou")); 
8.        userBean.addUser(); 
9.    } 
10.} 
hou.aop;
public class TestProxy {
public static void main(String[] args) {
CGLibProxy cProxy = new CGLibProxy();
UserBean userBean = (UserBean) ateProxyObject(new UserBean("royzhou"));
userBean.addUser();
}
}
输出:
this is addUser() method!
当取消用户权限时,控制台不输出任何东西.
说明通过CGLib成功生成代理对象,拦截了目标对象的方法.
Spring主要通过代理来实现AOP
下面是AOP的一些基本概念:
切面(Aspect):对横切关注点的抽象(类似类对对象的抽象)
连接点(JoinPoint):被拦截到的点,泛指方法
切入点(CutPoint):对哪些连接点进行拦截的定义
通知(Advice):在特
定的连接点,AOP框架执行的动作.前置/后置/例外/最终/环绕通知(调用方法之前执行,全部执行完毕之后)
引入(Introduction): 添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。
目标对象(Target Object): 包含连接点的对象。也被称作 被通知或被代理对象。
AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时 完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样, 在运行时完成织入。
Adive通知可理解如下:
Java代码
1.public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
2.        UserBean userBean = (UserBean) targetObject; 
3.        String userName = UserName(); 
4.        Object result = null; 
5.        if(userName!=null && !"".equals(userName)) { 
6.            //调用目标对象的方法 
7.            try { 
8.                //前置通知 
9.                result = method.invoke(targetObject, args); 
10.                //后置通知 
11.            } catch(Exception e) { 
12.                //例外通知 
13.            } finally { 
14.                //最终通知 
15.            } 
16.        }   
17.        //环绕通知(前置通知之后,目标对象方法调用之前执行,全部执行完毕(最终通知)之后) 
18.        return result; 
19.    } 
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
UserBean userBean = (UserBean) targetObject;
String userName = UserName();
Object result = null;
if(userName!=null && !"".equals(userName)) {
//调用目标对象的方法
try {
//前置通知
result = method.invoke(targetObject, args);
//后置通知
} catch(Exception e) {
//例外通知
} finally {
//最终通知
}
}
//环绕通知(前置通知之后,目标对象方法调用之前执行,全部执行完毕(最终通知)之后)
return result;
}
Spring提供两种方式实现AOP
一种是XML配置的方式
一种是annotation注解的方式
不管采用哪种方式,都必须在spring的配置文件中配置AOP支持:
Xml代码
1.<?xml version="1.0" encoding="UTF-8"?> 
2.<beans xmlns="/schema/beans" 
3.      xmlns:xsi="/2001/XMLSchema-instance" 
4.      xmlns:context="/schema/context"   
5.      xmlns:aop="/schema/aop"       
6.      xsi:schemaLocation="/schema/beans 
7.          htt

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。