AOP的底层实现-CGLIB动态代理和JDK动态代理


      AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础。它是一种面向切面编程的思想。关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来讲解下AOP的核心功能的底层实现机制:如何用动态代理来实现切面拦截。

        AOP的拦截功能是由java中的动态代理来实现的。说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行。不同的切入时机对应不同的Interceptor的种类,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。

        那么动态代理是如何实现将切面逻辑(advise)织入到目标类方法中去的呢?下面我们就来详细介绍并实现AOP中用到的两种动态代理。

        AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。

一、jdk动态代理实现AOP拦截(代码中的关键地方都添加了注释)


1、为目标类(target)定义统一的接口类Service,这个是jdk动态代理必须的前提。

[java] view plain copy


1 package jdkproxy;  

2   

3 /** 

4  * 该类是所有被代理类的接口类,jdk实现的代理要求被代理类基于统一的接口 

5  *  

6  * @author typ 

7  *  

8  */  

9 public interface Service {  

10     /** 

11      * add方法 

12      */  

13     public void add();  

14   

15     /** 

16      * update方法 

17      */  

18     public void update();  

19 }  

2、目标类AService,我们的实验目标就是在AService中add和update方法的前后实现拦截,加入自定义切面逻辑advise

[java] view plain copy


1 package jdkproxy;  

2   

3 /** 

4  * 被代理类,即目标类target 

5  *  

6  * @author typ 

7  *  

8  */  

9 public class AService implements Service {  

10     /* 

11      * (non-Javadoc) 

12      *  

13      * @see jdkproxy.Service#add() 

14      */  

15     public void add() {  

16         System.out.println("AService add>>>>>>>>>>>>>>>>>>");  

17     }  

18   

19     /* 

20      * (non-Javadoc) 

21      *  

22      * @see jdkproxy.Service#update() 

23      */  

24     public void update() {  

25         System.out.println("AService update>>>>>>>>>>>>>>>");  

26     }  

27 }  

3、实现动态代理类MyInvocationHandler,实现InvocationHandler接口,并且实现接口中的invoke方法。仔细看invoke方法,就是在该方法中加入切面逻辑的。目标类方法的执行是由mehod.invoke(target,args)这条语句完成。

[java] view plain copy


1 package jdkproxy;  

2   

3 import java.lang.reflect.InvocationHandler;  

4 import java.lang.reflect.Method;  

5   

6 /** 

7  * @author typ 

8  * 

9  */  

10 public class MyInvocationHandler implements InvocationHandler {  

11     private Object target;  

12   

13     MyInvocationHandler() {  

14         super();  

15     }  

16   

17     MyInvocationHandler(Object target) {  

18         super();  

19         this.target = target;  

20     }  

21   

22     public Object invoke(Object proxy, Method method, Object[] args)  

23             throws Throwable {  

24         // 程序执行前加入逻辑,MethodBeforeAdviceInterceptor  

25         System.out.println("before-----------------------------");  

26         // 程序执行  

27         Object result = method.invoke(target, args);  

28         // 程序执行后加入逻辑,MethodAfterAdviceInterceptor  

29         System.out.println("after------------------------------");  

30         return result;  

31     }  

32   

33 }  

4、测试类,其中增强的目标对象是由Proxy.newProxyInstance(aService.getClass().getClassLoader(), aService.getClass().getInterfaces(), handler);来生成的。

[java] view plain copy


1 package jdkproxy;  

2   

3 import java.lang.reflect.Proxy;  

4   

5 /** 

6  * @author typ 

7  * 

8  */  

9 public class Test {  

10     public static void main(String[] args) {  

11         Service aService = new AService();  

12         MyInvocationHandler handler = new MyInvocationHandler(aService);  

13         // ProxyInvocationHandler实现类动态创建一个符合某一接口的代理实例  

14         Service aServiceProxy = (Service) Proxy.newProxyInstance(aService  

15                 .getClass().getClassLoader(), aService.getClass()  

16                 .getInterfaces(), handler);  

17         // 由动态生成的代理对象来aServiceProxy 代理执行程序,其中aServiceProxy 符合Service接口  

18         aServiceProxy.add();  

19         System.out.println();  

20         aServiceProxy.update();  

21         // 以下是对B的代理  

22         // Service bService = new BService();  

23         // MyInvocationHandler handler = new MyInvocationHandler(bService);  

24         // Service bServiceProxy = (Service) Proxy.newProxyInstance(bService  

25         // .getClass().getClassLoader(), bService.getClass()  

26         // .getInterfaces(), handler);  

27         // bServiceProxy.add();  

28         // System.out.println();  

29         // bServiceProxy.update();  

30     }  

31 }  

自此,jdk动态代理来实现AOP拦截机制的代码已经实现,下面我们看一下拦截的结果,程序输出结果如下:

before-----------------------------

AService add>>>>>>>>>>>>>>>>>>

after------------------------------


before-----------------------------

AService update>>>>>>>>>>>>>>>

after------------------------------

可以看到,在目标类AService的add和update方法前后已经加入了自定义的切面逻辑,AOP拦截机制生效了。


二、cglib动态代理实现AOP拦截(代码中的关键地方都添加了注释


1、目标类,cglib不需要定义目标类的统一接口

[java] view plain copy


1 package cglibproxy;  

2   

3 /** 

4  * 被代理类,即目标对象target 

5  *  

6  * @author typ 

7  *  

8  */  

9 public class Base {  

10     /** 

11      * 一个模拟的add方法 

12      */  

13     public void add() {  

14         System.out.println("add ------------");  

15     }  

16 }  

2、实现动态代理类CglibProxy,需要实现MethodInterceptor接口,实现intercept方法。该代理中在add方法前后加入了自定义的切面逻辑,目标类add方法执行语句为proxy.invokeSuper(object, args);

[java] view plain copy


1 package cglibproxy;  

2   

3 import java.lang.reflect.Method;  

4 import net.sf.cglib.proxy.MethodInterceptor;  

5 import net.sf.cglib.proxy.MethodProxy;  

6   

7 /** 

8  * 此为代理类,用于在pointcut处添加advise 

9  *  

10  * @author typ 

11  *  

12  */  

13 public class CglibProxy implements MethodInterceptor {  

14   

15     public Object intercept(Object object, Method method, Object[] args,  

16             MethodProxy proxy) throws Throwable {  

17         // 添加切面逻辑(advise),此处是在目标类代码执行之前,即为MethodBeforeAdviceInterceptor  

18         System.out.println("before-------------");  

19         // 执行目标类add方法  

20         proxy.invokeSuper(object, args);  

21         // 添加切面逻辑(advise),此处是在目标类代码执行之后,即为MethodAfterAdviceInterceptor  

22         System.out.println("after--------------");  

23         return null;  

24     }  

25   

26 }  

3、获取增强的目标类的工厂Factory,其中增强的方法类对象是有Enhancer来实现的,代码如下所示:

[java] view plain copy


1 package cglibproxy;  

2   

3 import net.sf.cglib.proxy.Enhancer;  

4   

5 /** 

6  * 工厂类,生成增强过的目标类(已加入切入逻辑) 

7  *  

8  * @author typ 

9  *  

10  */  

11 public class Factory {  

12     /** 

13      * 获得增强之后的目标类,即添加了切入逻辑advice之后的目标类 

14      *  

15      * @param proxy 

16      * @return 

17      */  

18     public static Base getInstance(CglibProxy proxy) {  

19         Enhancer enhancer = new Enhancer();  

20         enhancer.setSuperclass(Base.class);  

21         //回调方法的参数为代理类对象CglibProxy,最后增强目标类调用的是代理类对象CglibProxy中的intercept方法  

22         enhancer.setCallback(proxy);  

23         // 此刻,base不是单纯的目标类,而是增强过的目标类  

24         Base base = (Base) enhancer.create();  

25         return base;  

26     }  

27 }  

4、测试类

[java] view plain copy


1 package cglibproxy;  

2   

3 /** 

4  * @author typ 

5  * 

6  */  

7 public class Test {  

8     public static void main(String[] args) {  

9         CglibProxy proxy = new CglibProxy();  

10         // base为生成的增强过的目标类  

11         Base base = Factory.getInstance(proxy);  

12         base.add();  

13     }  

14 }  

自此,cglib动态代理实现的AOP拦截机制已经基本实现,下面我们来看一下拦截的效果如何,程序执行结果如下:

before-------------

add ------------

after--------------

可以看到,在目标类Base的add方法前后已经加入了自定义的切面逻辑,AOP拦截机制生效了。

此外,需要说明一下的是,cglib动态代理用到了第三方类库,需要在项目中引入两个jar包:cglib.jar和asm.jar。稍后会在csdn资源中上传这两个jar包。免积分的啊。 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值