本文基于ProxyFactoryBean。
1、AOP的概念
与OOP中纵向的父子继承关系不同,AOP是通过横向的抽取机制实现的。它将应用中的一些非业务的通过功能抽取出来单独维护,并通过声明的方式(例如配置文件、注解等)定义这些功能要以何种方式作用在那个应用中,而不是在业务模块的代码中直接调用。
2、AOP的实现
目前最流行的AOP实现(框架)主要有两个,分别为Spring AOP和AspectJ。

3、AOP的类型
1)动态AOP:动态AOP的织入过程是在运行时动态执行的。其中最具代表性的动态AOP实现就是Spring AOP,它会为所有被通知的对象创建代理对象,并通过代理对象被原对象进行增强。优点是它可以轻松地对应用程序的所有切面进行修改,而无须对主程序代码进行重新编译。缺点是相较于静态AOP,它的性能通常较差,但随着技术的不断发展,它的性能也在不断的提升。
2)静态AOP:是通过修改应用程序的实际Java字节码,根据需要修改和扩展程序代码来实现织入过程的。最具代表性的静态AOP实现是AspectJ。优点是性能较好,缺点是对切面的任何修改都需要重新编译整个应用程序。
4、AOP的术语

5、AOP的通知类型

6、AOP的常用实现方式
1)一般切面的AOP开发(基于ProxyFactoryBean)。
2)切点切面的AOP开发(基于PointCutAdvisor和ProxyFactoryBean)。
3)自动代理的AOP开发(基于AutoProxyCreator)。
4)基于XML的AspectJ AOP开发。
5)基于注解的AspectJ AOP开发。
注:前三个归属Spring AOP,后两个归属AspectJ。
7、配置ProxyFactoryBean
配置代码如下图所示:

1)定义使用的通知器Advice,这个通知器作为一个Bean来定义。这个通知器的实现定义了需要对目标对象进行增强的切面行为。
2)定义ProxyFactoryBean,把它作为另一个Bean来定义,它是封装AOP功能的主要类。在配置ProxyFactoryBean时,需要设定与AOP实现相关的重要属性,比如proxyInterfaces、interceptorNames和target等。
3)定义target属性,作为target属性注入的Bean,是需要用AOP通知器中的切面应用来增强的对象。
8、生成AopProxy代理对象
从FactoryBean中获取对象,是以getObject方法作为入口完成的。ProxyFactoryBean实现中的getObject方法,是FactoryBean需要实现的接口,具体代码如下图所示:

8.1、initializeAdvisorChain方法
该方法的作用是通过interceptorNames属性获取通知器并且添加到通知器链里用于切面增强调用,具体代码如下图所示:

8.2、getSingletonInstance方法
该方法的作用是获取AOP代理对象,具体代码如下图所示:

8.3、createAopProxy方法
Spring分别通过JDK和CGLIB来生成需要的Proxy代理对象,如果目标对象是接口类,那么使用JDK来生成,否则Spring会使用CGLIB来生成。具体代码如下图所示:

注:JDK动态代理和CGLIB代理具体查看《Java的三种代理模式》
9、AOP拦截器的调用
在Spring AOP通过JDK的Proxy方式或CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。
如果使用JDK的Proxy来生成代理对象,那么需要通过InvocationHandler来设置拦截器回调;而如果使用CGLIB来生成代理对象,就需要根据CGLIB的使用要求,通过DynamicAdvisedInterceptor来完成回调。
9.1、JdkDynamicAopProxy的invoke拦截
在JdkDynamicAopProxy中实现了invocatinHandler接口,也就是说当Proxy对象的代理方法被调用时,JdkDynamicAopProxy的invoke方法作为Proxy对象的回调函数被触发,从而通过invoke的具体实现,来完成对目标对象方法调用的拦截或者说功能增强的工作。invoke方法的代码如下图所示:

9.2、Cglib2AopProxy的intercept拦截
Cglib2AopProxy的回调在intercept方法中实现,和JdkDynamicAopProxy的回调实现是非常类似的。intercept方法的代码如下图所示:

10、目标对象方法的调用
如果没有设置通知器,那么会对目标对象的方法直接进行调用。对于JdkDynamicAopProxy代理对象,这个对目标对象的方法调用是通过AopUtils使用反射机制在AopUtils.invokeJoinpointUsingReflection的方法中实现的。具体代码如下图所示:

对于使用Cglib2AopProxy的代理对象,它对目标对象的调用是通过CGLIB的MethodProxy对象来直接完成的。具体代码如下图所示:

11、AOP通知器链的配置
通知器链的配置是通过AdvisedSupport的getInterceptorsAndDynamicInterceptionAdvice方法实现的,具体代码如下:

接下来查看getInterceptorsAndDynamicInterceptionAdvice方法,具体代码如下图所示:

12、AOP通知器链的调用
通知器链的调用是在ReflectiveMethodInvocation中通过proceed方法实现的。在proceed方法中,会逐个运行通知器的方法,在逐个运行前会判断是否匹配。具体代码如下图所示:

13、Advice通知的实现
Advice通知的实现由DefaultAdvisorAdapterRegistry的getInterceptors方法执行,具体代码如下图所示:

网友评论