Spring 5企业级开发实战
上QQ阅读APP看书,第一时间看更新

3.6 Spring AOP的实现原理

Spring AOP的实现是通过创建目标对象的代理类,并对目标对象进行拦截来实现的。分析Spring AOP的底层实现,需要重点分析几个常用类,相关类图如3-15所示。

ProxyConfig类是一个基类——数据类,主要为各种AOP代理工厂提供属性配置。

AdvisedSupport类是ProxyConfig类的子类,其封装了AOP中对通知(Advice)和通知器(Advisor)的相关操作,这些操作对于不同的创建代理对象的类都是相同的,但是对于具体的AOP代理对象的生成需要AdvisedSupport各个子类去实现。

图3-15 Spring AOP核心类图

ProxyCreatorSupport类是AdvisedSupport的子类——辅助类,不同子类的一些通用的操作都封装在ProxyCreatorSupport中。

ProxyFactoryBean,ProxyFactory和AspectJProxyFactory是用于创建AOP代理对象的,这三个类的作用分别如下:

• ProxyFactoryBean类:功能是创建声明式的代理对象。

• ProxyFactory类:功能是创建编程式的代理对象。

• AspectJProxyFactory类:功能是创建基于AspectJ的代理对象。

3.6.1 设计原理

下面以ProxyFactoryBean为例,分析Spring AOP的实现原理。

首先定义一个接口Log,其中包含一个printLog()方法,Log接口的代码如下:

再创建一个Target类,实现Log接口,重写printLog方法,Target类的代码如下:

然后创建一个通知类LogAroundAdvice并实现MethodInterceptor接口,重写invoke()方法,在方法执行前后分别打印实现,LogAroundAdvice的实现如下:

创建一个测试类,用于观察测试结果,测试代码如下:

文件spring-chapter3-sourcecodelearning.xml的配置如下:

运行测试代码,测试结果如下:

     方法执行开始时间:2018-10-03 08:18:51 167
     执行一些操作
     方法执行结束时间:2018-10-03 08:18:52 172

从测试结果可以看出,在正常的调用printLog()方法前后分别打印了日志,说明AOP已经实现了。下面将通过这个案例分析ProxyFactoryBean的实现逻辑。

打开ProxyFactoryBean的代码,其生成代理对象的核心方法是getObject()方法,部分代码如下:

下面分析getObject()方法中的initializeAdvisorChain()方法,initializeAdvisorChain()方法是初始化通知器链(或者叫拦截器链)的,其代码如下:

执行initializeAdvisorChain()方法后,如果是单例模式,将会调用getSingletonInstance()方法获取一个单例模式的代理对象,getSingletonInstance()方法代码如下:

执行initializeAdvisorChain()方法后,如果是非单例模式即原型模式,将会调用newPrototypeInstance()方法获取一个新的原型模式的代理对象,newPrototypeInstance()方法代码如下:

可以发现,无论是单例模式还是原型模式,最终都是通过调用getProxy()方法获取代理对象的,getProxy()的实现如下:

通过以上对getSingletonInstance()方法和newPrototypeInstance()方法的代码注释可以发现,这两个方法都会调用ProxyCreatorSupport.createAopProxy()方法,ProxyCreatorSupport类的核心代码如下:

从createAopProxy()方法的代码可以看出,AopProxy对象是在DefaultAopProxyFactory类的createAopProxy()方法中生成的,DefaultAopProxyFactory.createAopProxy()方法的代码如下:

从DefaultAopProxyFactory.createAopProxy()使用的类的名称可以发现,如果是继承了接口的类,会使用JDK动态代理,即用JdkDynamicAopProxy类创建代理对象,否则将会使用CGLIB动态代理即用ObjenesisCglibAopProxy类创建代理对象,关于这两种动态代理的具体使用,请参考本章3.1节。

3.6.2 JdkDynamicAopProxy

JDK动态代理只能针对接口起作用,Spring中通过JdkDynamicAopProxy类使用JDK动态代理创建AOPProxy对象,JdkDynamicAopProxy类的定义如下:

JdkDynamicAopProxy类实现了InvocationHandler接口,因而可以使用JDK动态代理产生代理对象。

此处的getProxy()方法是获取代理对象的入口,其是通过调用以下方法实现的:

findDefinedEqualsAndHashCodeMethods()方法的功能是查找代理的接口是否有定义equals()或hashCode()方法。

通过在3.1节中的介绍可以得知,InvocationHandler接口的invoke()方法是代理对象执行方法调用和增强的地方,下面分析JdkDynamicAopProxy实现InvocationHandler接口重写invoke()方法的代码:

通过以上代码分析可知,最核心的功能都是在invocation.proceed()方法中实现的,下面分析ReflectiveMethodInvocation,代码如下:

invokeJoinpoint()方法是调用目标对象方法的地方,其实现如下:

invokeJoinpoint()方法会调用AopUtils.invokeJoinpointUsingReflection()方法,代码如下:

可以看到invokeJoinpointUsingReflection()方法最终是通过反射调用目标对象的方法。

通过对JdkDynamicAopProxy类的代码进行分析可以知道,JdkDynamicAopProxy类实现了InvocationHandler接口,重写了invoke()方法,当进行调用时,其实并不是调用目标对象,而是为目标对象创建一个代理对象,触发代理对象的invoke()方法,在invoke()方法中会通过反射调用目标对象的方法,Spring AOP相关通知的调用也是在invoke()方法中完成的。

3.6.3 CglibAopProxy

由于JDK动态代理只能针对接口生成代理对象,对于没有实现接口的目标对象,需要使用CGLIB产生代理对象,下面分析CglibAopProxy的代码。

回到DefaultAopProxyFactory.createAopProxy()方法,如果目标对象没有实现接口,将会返回一个ObjenesisCglibAopProxy对象。ObjenesisCglibAopProxy类的代码如下:

从代码可以看出,ObjenesisCglibAopProxy继承了CglibAopProxy,Objenesis是一个轻量级的Java库,作用是绕过构造器创建一个实例。因此分析的重点还是CglibAopProxy类。

由本章3.1节可知,CGLIB的运行需要配合回调方法,实现MethodInterceptor接口,在CglibAopProxy中也是一样,下面分析获取回调方法getCallbacks()的代码:

通过上面对CGLIB创建代理和获取回调通知的代码分析,可以了解到CGLIB在获取代理通知时,会创建DynamicAdvisedInterceptor类;当调用目标对象的方法时,不是直接调用目标对象,而是通过CGLIB创建的代理对象来调用目标对象;并且在调用目标对象的方法时,会触发DynamicAdvisedInterceptor的intercept回调方法对目标对象进行处理,CGLIB回调拦截器链的代码如下:

这里的CglibMethodInvocation类继承了ReflectiveMethodInvocation类,CglibMethodInvocation.procceed()调用了父类的ReflectiveMethodInvocation.proceed()方法,和3.6.2节中调用的方法是相同的,此处不再赘述。