`
xuyongping
  • 浏览: 123601 次
  • 性别: Icon_minigender_1
  • 来自: 部落格
社区版块
存档分类
最新评论

Spring 的AOP底层实现原理

阅读更多
首先,我们实现InvocationHandler接口,该接口定义了一个 invoke(Object proxy, Method method, Object[] args)的方法,proxy是代理实例,一般不会用到;method是代理实例上的方法,通过它可以发起对目标类的反射调用;args是通过代理类传入的方法参数,在反射调用时使用。

此外,我们在构造函数里通过target传入真实的目标对象,如①处所示,在接口方法invoke(Object proxy, Method method, Object[] args)里,将目标类实例传给method.invoke()方法,通过反射调用目标类方法,如②所示。

下面,我们通过Proxy结合PerformaceHandler创建ForumService接口的代理实例,如代码清单 7所示:

代码清单 7 TestForumService:创建代理实例

package com.baobaotao.proxy;import java.lang.reflect.Proxy;public class TestForumService {public static void main(String[] args) {ForumService target = new ForumServiceImpl();//①目标业务类//② 将目标业务类和横切代码编织到一起PerformaceHandler handler = new PerformaceHandler(target);//③为编织了目标业务类逻辑和性能监视横切逻辑的handler创建代理类ForumService proxy = (ForumService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);//④ 操作代理实例proxy.removeForum(10);proxy.removeTopic(1012);}}


上面的代码完成了业务类代码和横切代码编织和接口代理实例生成的工作,其中在②处,我们将ForumService实例编织为一个包含性能监视逻辑的PerformaceHandler实例,然后在③处,通过Proxy的静态方法newProxyInstance()为融合了业务类逻辑和性能监视逻辑的handler创建一个ForumService接口的代理实例,该方法的第一个入参为类加载器,第二个入参为创建的代理实例所要实现的一组接口,第三个参数是整合了业务逻辑和横切逻辑的编织器对象。

按照③处的设置方式,这个代理实例就实现了目标业务类的所有接口,也即ForumServiceImpl的ForumService接口。这样,我们就可以按照调用ForumService接口的实例相同的方式调用代理实例,如④所示。运行以上的代码,输出以下的信息:

begin monitor...模拟删除Forum记录:10end monitor...com.baobaotao.proxy.ForumServiceImpl.removeForum花费47毫秒。begin monitor...模拟删除Topic记录:1012end monitor...com.baobaotao.proxy.ForumServiceImpl.removeTopic花费26毫秒。


我们发现,程序的运行效果和直接在业务类中编写性能监视逻辑的效果一致,但是在这里,原来分散的横切逻辑代码已经被我们抽取到PerformaceHandler中。当其它业务类(如UserService、SystemService等)的业务方法也需要使用性能监视时,我们只要按照以上的方式,分别为它们创建代理对象就可以了。下面,我们用时序图描述调用关系,进一步代理实例的本质,如图1所示:



图1:代理实例的时序图

我们在上图中特别使用虚线阴影的方式对通过代理器创建的ForumService实例进行凸显,该实例内部利用PerformaceHandler整合横切逻辑和业务逻辑。调用者调用代理对象的的removeForum()和removeTopic()方法时,上图的内部调用时序清晰地告诉了我们实际上所发生的一切。

CGLib动态代理

使用JDK创建代理有一个限制,即它只能为接口创建代理,这一点我们从Proxy的接口方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)就看得很清楚,第三个入参interfaces就是为代理实例指定的实现接口。虽然,面向接口的编程被很多很有影响力人(包括Rod Johnson)的推崇,但在实际开发中,开发者也遇到了很多困惑:难道对一个简单业务表的操作真的需要创建5个类(领域对象类、Dao接口,Dao实现类,Service接口和Service实现类)吗?对于这一问题,我们还是留待大家进一步讨论。现在的问题是:对于没有通过接口定义业务方法的类,如何动态创建代理实例呢?JDK的代理技术显然已经黔驴技穷,CGLib作为一个替代者,填补了这个空缺。你可以从http://cglib.sourceforge.net/获取CGLib的类包,也可以直接从Spring的关联类库lib/cglib中获取类包。
CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并在拦截方法相应地织入横切逻辑。下面,我们采用CGLib技术,编写一个可以为任何类创建织入性能监视横切逻辑的代理对象的代理器,如代码清单 8所示:

代码清单 8 CglibProxy

package com.baobaotao.proxy;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class CglibProxy implements MethodInterceptor {private Enhancer enhancer = new Enhancer();public Object getProxy(Class clazz) {enhancer.setSuperclass(clazz); ① 设置需要创建子类的类enhancer.setCallback(this);return enhancer.create(); ②通过字节码技术动态创建子类实例}public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {PerformanceMonitor.begin(obj.getClass().getName()+"."+method.getName());Object result=proxy.invokeSuper(obj, args); ③ 通过代理类调用父类中的方法PerformanceMonitor.end();return result;}}


在上面代码中,你可以通过getProxy(Class clazz)为一个类创建动态代理对象,该代理对象是指定类clazz的子类。在这个代理对象中,我们织入性能监视的横切逻辑(粗体部分)。intercept(Object obj, Method method, Object[] args,MethodProxy proxy)是CGLib定义的Inerceptor接口的方法,obj表示父类的实例,method为父类方法的反射对象,args为方法的动态入参,而proxy为代理类实例。

下面,我们通过CglibProxy为ForumServiceImpl类创建代理对象,并测试代理对象的方法,如代码清单 9所示:

代码清单 9 TestForumService:测试Cglib创建的代理类

package com.baobaotao.proxy;import java.lang.reflect.Proxy;public class TestForumService {public static void main(String[] args) {CglibProxy proxy = new CglibProxy();ForumServiceImpl forumService = //① 通过动态生成子类的方式创建代理对象(ForumServiceImpl )proxy.getProxy(ForumServiceImpl.class);forumService.removeForum(10);forumService.removeTopic(1023);}}


在①中,我们通过CglibProxy为ForumServiceImpl动态创建了一个织入性能监视逻辑的代理对象,并调用了代理对象的业务方法。运行上面的代码,输入以下的信息:

begin monitor...模拟删除Forum记录:10end monitor...com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0.removeForum花费47毫秒。begin monitor...模拟删除Topic记录:1023end monitor...com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0.removeTopic花费16毫秒。


观察以上的输出,除了发现两个业务方法中都织入了性能监控的逻辑外,我们还发现代理类的名字是com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0,这个特殊的类就是CGLib为ForumServiceImpl所动态创建的子类。

小结

Spring AOP在底层就是利用JDK动态代理或CGLib动态代理技术为目标Bean织入横切逻辑。在这里,我们对以上两节动态创建代理对象做一个小结。

在PerformaceHandler和CglibProxy中,有三点值得注意的地方是:第一,目标类的所有方法都被添加了性能监视横切的代码,而有时,这并不是我们所期望的,我们可能只希望对业务类中的某些方法织入横切代码;第二,我们手工指定了织入横切代码的织入点,即在目标类业务方法的开始和结束前调用;第三,我们手工编写横切代码。以上三个问题,在AOP中占用重要的地位,因为Spring AOP的主要工作就是围绕以上三点展开:Spring AOP通过Pointcut(切点)指定在哪些类的哪些方法上施加横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前、方法后、方法的两端等),此外,Spring还通过Advisor(切面)组合Pointcut和Advice。有了Advisor的信息,Spring就可以利用JDK或CGLib的动态代理技术为目标Bean创建织入切面的代理对象了。

JDK动态代理所创建的代理对象,在JDK 1.3下,性能强差人意。虽然在高版本的JDK中,动态代理对象的性能得到了很大的提高,但是有研究表明,CGLib所创建的动态代理对象的性能依旧比JDK的所创建的代理对象的性能高不少(大概10倍)。而CGLib在创建代理对象时性能却比JDK动态代理慢很多(大概8倍),所以对于singleton的代理对象或者具有实例池的代理,因为不需要频繁创建代理对象,所以比较适合用CGLib动态代理技术,反之适合用JDK动态代理技术。此外,由于CGLib采用生成子类的技术创建代理对象,所以不能对目标类中的final方法进行代理。


转载:http://www.51cto.com/art/200702/39480_2.htm
分享到:
评论

相关推荐

    Spring AOP的底层实现技术

    下面我们将深入探讨Spring AOP的底层实现技术和相关知识点。 1. **代理模式** Spring AOP基于两种代理机制实现:JDK动态代理和CGLIB代理。JDK动态代理适用于实现了接口的目标对象,通过反射机制创建一个代理类来...

    Spring Aop的底层实现技术 --- Jdk动态代理原理

    Spring AOP 的底层实现技术 --- Jdk 动态代理原理 JDK 动态代理是 Spring AOP 的底层实现技术,允许开发者在运行期创建接口的代理实例。在 JDK 1.3 以后,JDK 动态代理技术提供了实现 AOP 的绝好底层技术。JDK 动态...

    springIOC及AOP底层原理Demo实现

    本教程将深入探讨这两个概念,并通过实际的代码实现来帮助你理解它们的底层原理。 首先,我们来看IoC,即控制反转。在传统的编程模式中,对象之间的依赖关系通常由对象自身来创建和管理,但在Spring中,这种控制权...

    SpringAOP的实现机制(底层原理)、应用场景等详解,模拟过程的实例

    这两种代理方式在Spring AOP中起到关键作用,用于实现横切关注点的切面编程。通过学习它们的原理和实际应用,您将能够更好地理解和利用Spring AOP来提高您的应用程序的可维护性和可扩展性。 内容亮点: JDK动态...

    spring底层的学习之路

    本资料包"Spring学习之路"深入浅出地介绍了Spring的底层原理以及如何搭建一个完整的Spring MVC项目,对于初学者来说是极好的学习资源。 首先,我们要了解Spring的核心概念——IoC(Inversion of Control)和DI...

    用xml配置的方式进行SpringAOP开发

    不过,理解XML配置方式有助于深入理解Spring AOP的底层原理。 总的来说,Spring AOP通过XML配置为我们提供了一种灵活的方式来管理横切关注点,使我们的代码更加模块化和可维护。通过定义Advisor、切点和通知,我们...

    spring-aop.rar_aop1270_spring_spring aop

    本文将围绕Spring AOP的源码分析,探讨其核心概念、工作原理以及在实际开发中的应用。 一、AOP核心概念 1. 切面(Aspect):切面是关注点的模块化,通常包含一组通知(advises)和一个切入点(pointcut)定义。 2...

    Spring实现AOP的4种方式 - Java -

    同时,了解XML配置方式可以帮助我们理解Spring AOP的底层原理。 在实际开发中,理解并掌握这四种AOP实现方式对于编写高效、灵活的代码至关重要。Spring的AOP特性使得我们能够更好地组织代码,将横切关注点与业务...

    SpringAOP原理及拦截器.docx

    Spring框架是AOP技术的一个重要实现,它提供了非侵入式的AOP支持,使得开发者无需深入理解底层细节,就能轻松地实现面向切面的编程。 首先,我们了解AOP的关键概念: 1. **方面(Aspect)**:方面是将一组相关或相互...

    Spring AOP Example – Pointcut , Advisor

    此外,AspectJ Weaver是Spring AOP的底层实现,它可以在编译时或运行时对字节码进行操作,实现切面的织入。 总之,Spring AOP是解决横切关注点的有效工具,通过Pointcut和Advisor,我们可以优雅地管理那些分散在...

    Spring-AOP(前置/后置/环绕)通知的例子

    了解了这些基础知识后,我们可以结合标签"源码"和"工具",进一步研究Spring AOP的底层实现原理。Spring AOP通过动态代理机制(JDK Proxy或CGLIB)创建代理对象,拦截方法调用并执行通知。对于非接口实现类,Spring会...

    以注解方式模拟Spring IoC AOP

    本篇将深入探讨如何通过注解方式来模拟Spring的这两种机制,帮助你理解其底层原理。 ### 1. 依赖注入(IoC) 依赖注入是Spring框架的核心特性之一,它通过反转对象创建和管理的控制权,使得应用程序组件之间的耦合...

    Spring aop 基于schema的AOP支持及JoinPoint的使用、如何使用CGLIB代理

    **Spring AOP 基于Schema的...CGLIB作为Spring AOP的底层代理技术,为我们提供了对未实现接口类的代理能力,使得AOP的应用场景更加广泛。理解并熟练掌握这些概念和技术,对于构建可维护、高性能的Spring应用至关重要。

    java 动态代理实现,模拟spring aop

    Java动态代理是Java提供的一种在运行时创建代理对象的技术,它是实现类似Spring AOP(面向切面编程)功能的关键机制之一。...但是,理解Java动态代理的底层原理对于深入理解Spring AOP的工作方式是非常有益的。

    AOP_使用spring框架进行面向切面编程

    面向切面编程(AOP)是一种编程范式,它旨在减少代码中的重复部分,特别是那些与核心业务逻辑无关但又必须处理...同时,通过分析和操作`springAOP`压缩包中的示例代码,可以更直观地了解AOP在Spring框架中的具体实现。

    模拟spring工厂模式底层实现。

    在Spring框架中,工厂模式是核心的组件创建方式,它...总的来说,深入理解Spring工厂模式的实现有助于我们更好地掌握Spring框架的工作原理,从而能更高效地利用Spring进行开发,并且在遇到问题时能够迅速定位和解决。

    Spring技术内幕-深入解析_Spring架构与设计原理

    Spring框架的设计理念强调“轻量级”和“非侵入性”,使得开发人员能够专注于业务逻辑而无需过多关注底层框架的实现细节。 ### IoC容器的深入解析 IoC容器是Spring框架的核心组件,负责管理和控制应用程序对象的...

    spring技术内幕第2版深入解析spring架构与设计原理

    Spring的核心特性主要体现在其依赖注入(DI)和面向切面编程(AOP)的概念上,这两个概念是Spring框架的两大支柱。依赖注入有助于解耦代码,使得组件之间的依赖关系不再由组件自己来维护,而是由外部容器来管理,...

    spring第五天 .pdf

    本课程主要关注Spring AOP的底层原理和源码分析,特别是动态代理机制。 动态代理是Spring AOP实现的核心,它允许在运行时创建一个代理对象,该对象能代理目标对象并执行额外的逻辑。在Java中,有两种主要的动态代理...

Global site tag (gtag.js) - Google Analytics