`
wusuoya
  • 浏览: 643133 次
  • 性别: Icon_minigender_2
  • 来自: 成都
社区版块
存档分类
最新评论

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

    博客分类:
  • SSH
 
阅读更多

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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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.         // Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例  
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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包。免积分的啊。
 
总之,AOP的核心机制和基本功能已经能够通过动态代理来实现了,至于AOP中,如何从配置文档中得到目标类target、advisor的bean,如何判断拦截器类型等问题,就借助于Spring中另一个核心IOC来解决了,后续会有IOC的核心实现机制讲解。
JDK动态代理和CGLIB代理的主要区别: 
  JDK动态代理 :只能对实现了接口的类生成代理,而不能针对类 ,是Spring AOP代理的默认方式。 
  CGLIB代理: 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。 
          因为是继承,所以该类或方法最好不要声明成final 
          提供代理类的功能是为了让以前的或第三方的没有实现接口的类也能够被通知,所以这种方法应该被当作一种例会,而不是规则。被标记为final的方法不能被通知。
分享到:
评论

相关推荐

    AOP之JDK动态代理和CGLib动态代理

    Spring框架是AOP实现的一个典范,它提供了两种主要的动态代理方式:JDK动态代理和CGLib动态代理。 **JDK动态代理**: JDK动态代理基于Java的反射API实现,适用于接口代理。当目标对象实现了至少一个接口时,Spring...

    代理模式-静态动态代理-jdk动态代理-cglib动态代理

    在Java中,代理模式有多种实现方式,包括静态代理、JDK动态代理和CGLIB动态代理。 **静态代理** 静态代理是最早也是最基础的代理实现方式。在静态代理中,我们需要创建一个代理类,这个代理类与原始类(被代理类)...

    spring-cglib-repack-3.2.4.jar和spring-objenesis-repack-2.5.1.jar

    当Spring框架在进行AOP代理时,如果目标类没有实现接口,它会选择使用CGLIB来创建一个子类并动态地插入拦截器方法。CGLIB通过字节码操作技术生成代理类,这样就可以在运行时扩展或修改已有类的功能,而无需修改原始...

    浅谈JDK动态代理与CGLIB代理去区别

    在Java开发中,动态代理和CGLIB代理是两种常见的面向切面编程(AOP)实现方式,它们都用于在不修改原有代码的情况下,增强或扩展对象的功能。本篇文章将深入探讨JDK动态代理和CGLIB代理的区别,以及它们在实际应用中...

    Spring框架中JDK动态代理和cglib动态代理

    Spring 框架中 JDK 动态代理和 CGLIB 动态代理是 Spring AOP 中一个非常重要的知识点。Spring AOP 框架会根据实际情况选择使用 JDK 的动态代理还是 CGLIB 的动态代理。 JDK 动态代理是 Java 自带的动态代理机制,它...

    jdk与cglib动态代理与底层实现

    JDK和CGLIB是Java中实现动态代理的两种主要方式,它们在Spring框架中扮演着关键角色,尤其是在AOP(面向切面编程)中。 1. **JDK动态代理**: JDK动态代理基于Java的接口机制实现,因此,要使用JDK动态代理,被...

    AOP-CGLIB学习-实现简单的注解权限系统

    Spring框架提供了一种实现AOP的方式,它支持基于代理的AOP实现,包括JDK动态代理和CGLIB代理。当目标对象不实现接口时,Spring会使用CGLIB来创建代理对象。 CGLIB(Code Generation Library)是一个代码生成库,它...

    spring-cglib-repack-3.2.5.jar,spring-objenesis-repack-2.6.jar

    CGLIB和Java的内置JDK动态代理是两种常用的动态代理方式。当目标类实现了接口时,Spring会选择JDK动态代理,通过反射机制创建代理对象;反之,如果目标类没有接口,Spring就会使用CGLIB来创建代理。 4. **Spring ...

    Jdk动态代理和cglib动态代理原理

    在实际开发中,如Spring AOP框架就同时支持JDK和CGLIB动态代理,根据目标类是否实现接口自动选择合适的代理方式。 总结来说,JDK动态代理和CGLIB动态代理都是为了在运行时提供对目标对象的增强,它们通过不同的实现...

    Spring AOP 中 JDK 和 CGLib 动态代理哪个更快?.docx

    Spring AOP 中 JDK 和 CGLib 动态代理哪个更快?

    Spring-AOP-JDK动态代理

    5. **配置代理**:Spring会根据目标对象是否实现了接口来决定使用JDK动态代理还是CGLIB代理。如果目标对象实现了接口,Spring会选择JDK动态代理。动态代理类会继承自`java.lang.reflect.Proxy`,并实现目标对象的...

    hibernate-cglib-repack-2.1_3.jar

    总的来说,"hibernate-cglib-repack-2.1_3.jar"是Hibernate框架中不可或缺的一部分,它通过CGLIB库实现了对Java类的动态代理,提供了诸如懒加载、拦截器等高级功能,极大地增强了ORM的灵活性和可扩展性。在实际开发...

    Spring源码缺失的spring-cglib-repack-3.2.6.jar和spring-objenesis-repack-2.6.jar

    在Spring AOP中,有两种主要的代理方式:JDK动态代理和CGLib代理。JDK动态代理基于接口,如果目标对象实现了至少一个接口,Spring会使用JDK的Proxy类生成一个代理对象。而如果没有接口或者接口方法不能满足需求,...

    CGlib实现动态代理(承接上面JDK实现动态代理)

    在Java中,CGlib是一个非常重要的工具,特别是在AOP(面向切面编程)和ORM(对象关系映射)框架中,如Spring和Hibernate广泛使用它来实现代理功能。 CGlib动态代理的工作原理是通过继承被代理的目标类来创建子类,...

    spring 4.* 缺少jar spring-cglib-repack-3.2.5.jar_spring-objenesis-repack-2.6.jar

    在Spring框架中,CGLIB被用来创建AOP代理,尤其是当目标对象不支持JDK动态代理时(即目标对象没有实现接口)。CGLIB通过生成目标类的子类并覆盖其中的方法来实现动态代理,这样可以对方法进行拦截,实现如事务管理、...

    基于MAVEN项目的CGLib动态代理原理及实现

    它广泛用于许多AOP(面向切面编程)框架,如Spring AOP和dynaop,作为JDK动态代理的替代品,当目标类不支持接口时,CGLib能发挥重要作用。 3. CGLib工作原理 CGLib通过继承的方式创建代理对象。它会生成一个目标类的...

    Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理)

    本文主要介绍 Java 中两种常见的动态代理方式:JDK 原生动态代理和 CGLIB 动态代理。 一、 代理模式 代理模式是指程序通过代理类来访问目标对象,以达到对目标对象的控制和增强。代理模式的优点是可以在不改变目标...

    输出JDK和CGLib动态代理产生的class文件.zip

    - target/classes:编译后的class文件,包括目标接口和实现类的class文件,以及由Proxy生成的代理类class文件 - 测试代码:展示如何使用Proxy创建代理对象并调用方法 2. CGLib代理项目: - src/main/java:包含...

    day39-Spring 04-CGLIB的动态代理

    CGLIB被广泛应用于Spring AOP(面向切面编程)中,用于实现对目标对象的动态代理,以提供方法拦截、事务管理、性能监控等功能。 首先,我们要理解什么是动态代理。在Java中,动态代理是一种在运行时创建代理类的...

    Jdk动态代理,cglib动态代理,反射和拦截器(链)示例

    Java中的动态代理、反射和...总之,理解和掌握JDK动态代理、CGLIB动态代理、反射和拦截器是提升Java开发技能的关键步骤。通过实际操作这些示例,你将能够更好地应用这些技术到实际项目中,提高代码的灵活性和可维护性。

Global site tag (gtag.js) - Google Analytics