深入理解SpringAOP的实现原理之代理对象的生成

一、Spring AOP概念

AOP(Aspect-Oriented Programming)面向切面或者面向方面编程的简称,将一些分散在对象或者类中的与业务逻辑无关的代码分离出来进行独立的管理编码,例如日志,事务处理,异常等。几个相关的重要概念:
1、方面/切面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的 Advisor或拦截器实现。
2、连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
3、Advice(通知):定义连接点做什么,为切面增强提供织入接口。如BeforeAdivice、AfterAdvice、ThrowsAdvice,其中前两者分别实现了before()和AfterRunning()回调方法,而后者则通过反射机制完成。
4、Pointcut(切点):决定Advice通知应该作用于哪个连接点,也就是说通过Pointcut来定义需要增强的方法的集合,其通常意味着标识方法。对于Pointcut的判断功能,具体是由一个返回得MethodMatcher来完成,由它判断是否要对当前方法进行增强,或者是否需要对当前调用方法应用配置好的Advice通知。
5、Advisor(通知器):用于结合目标对象的切面增强设计(Advice)和关注点设计(Pointcut),通过Advisor,可以定义应该使用哪个通知并在哪个关注点使用它。

二、两种动态代理

Spring AOP的设计理念,便是将一些与业务逻辑无关的关注点分离出来,例如,当我之时某些方法之时,我需要知道方法执行前后的日志信息,同时希望能够尽可能的减少代码量,该如何去处理?自然而然会想到代理模式,对于某个对象的调用,转而去访问它的代理对象,而无需知道它的存在,使对象对于调用者而言是完全透明的。相信大家都对代理模式有过一定的了解,其中主要有静态代理以及动态代理,静态代理所代理的对象在运行之前就必须确定,因此针对某些特定的业务场景,动态代理将是最完美的选择。
JDK动态代理:
一个Hello接口,里面定义了一个sayHello()方法
这里写图片描述
实现类
这里写图片描述
代理类
这里写图片描述
测试类
这里写图片描述
结果
这里写图片描述
从上面的例子可以很显然的看到,JDK的动态代理主要是针对于接口的,同时它的实现主要是由InvocationHandler对象的invoke()方法里面,同时需要注意,它仅仅能够代理当前接口里面的方法,并不能代理其父类的方法!

Cglib代理:
代理的对象使用上文的HelloImpl类,代理类如下:
这里写图片描述
测试类:
这里写图片描述
结果:
这里写图片描述
从上面的例子可以看出,Cglib代理的实现主要是封装在MethodInteceptor对象的intercept()方法里面。下面,我们来看看Spring中是如何巧妙的运用这两种代理技术去实现AOP的。

三、Spring AOP中的代理对象生成

在Spring中代理对象的生成主要由ProxyFactoryBean承担,由名字可以看出这是一个工厂Bean,它的统计目录还有两个代理工厂AspectJProxyFactory和ProxyFactory
如下图所示:
这里写图片描述
AspectJProxyFactory主要是与AspectJ相关的AOP实现方式,而ProxyFactory用于通过纯POJO编程实现的,既然Spring IoC用于管理Bean,我们就着重分析ProxyFactoryBean的实现原理。
ProxyConfig和AdvisedSupport是三种模式的共同基类,其中前者主要为子类提供配置属性,后者主要用于封装AOP对通知和通知器的相关操作。
其中配置ProxyFactoryBean主要分为以下几步:
1.定义使用的Advisor通知器,这个通知器应当作为一个Bean来定义。这个通知器的实现定义了需要对目标对象进行增强的切面行为,也就是Advice通知。
2.定义ProxyFactoryBean,把它作为一个Bean来定义,它是封装AOP功能的主要类。
3.定义target属性,作为target属性注入的Bean,是需要用AOP通知器中的切面应用来增强的对象,也就是前面所提到的base对象。代码如下:

<bean id="testAdvisor" class="com.abc.TestAdvisor"/>
<bean id="testAOP" class="org.springframework.aop.ProxyFactoryBean">
<property name="proxyInterfaces">
    <value>com.test.AbcInterface</value>
</property>
<property name="target">
    <bean class="com.abc.TestTarget"/>
</property>
<property name="interceptorNames">
    <list><value> testAdvisor</value></list>
</property>
</bean>

配置完成以后,便可开始使用AOP的基本功能,从getObject()方法开始,

初始化通知链,并对被代理对象的类型进行分析,如果是Singleton类型的,则通过getSingletonInstance()方法生成,同时会将生成的单例bean存储于一个ConcurrentHashMap类型的单例注册表中,用于避免对象的重复创建。
如果是Prototype类型,则调用newPrototypeInstance()方法。
这里写图片描述
这里写图片描述
这里写图片描述
从getSingletonInstance()方法可以看到对象的生成是由getProxy方法完成的,这里创建了一个AopProxy对象,它便是封装着代理对象的接口,其主要由以下两个实现类:
这里写图片描述
其中JdkDynamicAopProxy便是通过JDK的动态代理去生成代理对象,CglibAopProxy则是通过Cglib代理去生成代理对象。

五、JdkDynamicAopProxy的实现原理

首先,从其advised对象中获取代理对象的接口配置,然后调用Proxy类的newProxyInstance()方法,最终生成代理对象。
这里写图片描述
由于JdkDynamicAopProxy实现了invoke方法,因此Proxy代理对象的回调方法便是它自身所实现的invoke()方法,其中包括了对拦截器的设定,以及逐个运行拦截器链里的拦截增强。接下来可以看到如下两行代码:
这里写图片描述
这里是代理方法结果所生成的对象,可见JdkDynamicAopProxy将代理对象的所有配置信息,拦截器链都封装在这个ReflectiveMethodInvocation对象中,自此一个代理对象便生成完成,对于被代理对象的调用都会被拦截器链进行拦截,转而去执行拦截方法,以后再具体分析Aop如何对拦截器链进行调用的。

六、CglibAopProxy生成代理对象

CglibAopProxy则主要是通过Enhancer对象生成代理对象,同时将Spring AOP的实现封装在callback的回调设置中,并将DynamicAdvisedInterceptor对象的intercept()方法当作回调如果,类似于动态代理的invoke方法,并以CglibMethodInvocation对象返回,如下:
这里写图片描述

七、总结

本文从源码角度分析了Spring AOP代理对象的生成过程,主要是由JDK动态代理和Cglib代理实现,以后再继续分析具体的拦截过程。

参考:《Spring技术内幕》 计文柯

猜你喜欢

转载自blog.csdn.net/jackFXX/article/details/81636507