3.3 建立AopProxy代理对象

3.3.1 设计原理

在Spring的AOP模块中,一个主要部分是代理对象的生成,通过配置和调用Spring的ProxyFactoryBean来完成这个任务。在ProxyFactoryBean中,封装了主要代理对象的生成过程。在这个生成过程中,可以使用JDK的ProxyCGLIB两种生成方式。以ProxyFactory的设计为中心的相关类继承关系如下图:

在上图中,同级别的完成AOP应用的类如AspectJProxyFactory、ProxyFactory和ProxyFactoryBean,都在同一个继承体系下,它们都是ProxyConfig、AdvisedSupport和ProxyCreatorSupport的子类。这三个共同基类的作用分别是:

  1. ProxyConfig:是一个数据基类,为ProxyFactoryBean这样的子类提供配置属性;
  2. AdvisedSupport:封装了AOP对通知和通知器的相关操作,这些操作对于不同的AOP代理对象的生成都是一样的;
  3. ProxyCreatorSupport:可将它看成是它子类创建AOP代理对象的一个辅助类。

具体的AOP代理对象的生成,根据不同需要,分别由AspectJProxyFactory、ProxyFactory和ProxyFactoryBean来完成。对于需要使用AspectJ的AOP应用,AspectJProxyFactory起到集成Spring和AspectJ的作用;对于使用Spring AOP的应用,ProxyFactory和ProxyFactoryBean都提供了AOP功能的封装,区别在于:使用ProxyFactoryBean,可以在IoC容器中完成声明式配置;而使用ProxyFactory,则需要编程式地使用Spring AOP的功能。

3.3.2 配置ProxyFactoryBean

配置ProxyFactoryBean的过程大概可以概括成以下2点:

1. 定义使用的通知器Advisor,这个通知器应该作为一个Bean来定义,它的实现定义了需要对目标对象进行增强的切面行为,也就是Advice通知。

2. 定义ProxyFactoryBean,把它作为另一个Bean来定义,它是封装AOP功能的主要类。在配置ProxyFactoryBean这个bean的时候,有几个重要的属性,比如proxyInterface、interceptorNames和target等。interceptorNames属性往往设置为需要定义的通知器,target属性就是设置为需要用AOP通知器中的切面应用来增强的对象。

下面是一个关于配置的例子:

3.3.3 ProxyFactoryBean生成AopProxy代理对象

ProxyFactoryBean是一个FactoryBean,对于FactoryBean的工作原理,之前的博客中已经说明了,从FactoryBean中获取对象,是通过getObject方法作为入口完成的。这里看下ProxyFactoryBean的getObject方法,这里面主要有三个方法,分别是:

  • initializeAdvisorChain方法:对通知器链进行初始化,通知器链封装了一系列的通知器,这些通知器都要从配置中读取,然后为代理对象的生成做好准备。
  • getSingletonInstance方法:如果目标对象是单态模式,就调用获取单态模式对象的方法产生AOPProxy代理。
  • newPrototypeInstance方法:如果目标对象是原型模式,就调用原型模式对象方法每次创建一个新的AOPProxy代理对象。

先来看initializeAdvisorChain方法,这个方法中首先会有一个标志位来表示通知器链是否已经初始化,如果已经初始化,这里就不再初始化,直接返回。接着读取配置中出现的所有通知器,把通知器的名字交给容器的getBean方法,通过对IoC容器实现的一个回调来获得。然后把从IoC容器中取得的通知器加入到通知器链中,这个动作由addAdvisorOnChainCreation方法完成。

再看获取单例代理对象的getSingletonInstance方法以及获取多例代理对象的newPrototypeInstance方法,我们重点看这两个方法中都调用了getProxy(createAopProxy())这个方法,这里的createAopProxy方法已经生成了代理对象,来看下这个代理对象是怎么生成的。在createAopProxy方法中,首先要从AdvisedSupport对象中取得配置的目标对象,这个目标对象是实现AOP功能所必需的,因为AOP完成的是切面应用对目标对象别的增强,如果没有目标对象,那么又该对谁进行增强呢?所谓“皮之不存,毛将焉附”,这个目标对象就是“皮”,AOP切面增强就是依附于这块皮的“毛”。如果这里没有配置目标对象,会抛出异常,提醒AOP应用提供正确的目标对象的配置。在完成目标对象配置的检查之后,再根据配置的情况来决定使用什么方式创建AopProxy对象。如果配置的目标对象是接口类,则使用JDK动态代理机制来生成AopProxy代理对象(默认方式);如果配置的目标对象不是接口类,则使用CGLIB来生成AopProxy代理对象。

3.3.4 JDK生成AopProxy代理对象

AopProxy代理对象可以由JDK或CGLIB来生成,而JdkDynamicAopProxy和Cglib2AopProxy都是实现了AopProxy接口,AopProxy接口的设计也简单,就是获得Proxy代理对象,方式有两种:

  • 一种是指定ClassLoader:getProxy(ClassLoader);
  • 另一种不需要指定:getProxy()

在JdkDynamicAopProxy中,使用了JDK的Proxy类来生成代理对象。首先从advised对象中取得代理对象的代理接口配置,然后调用Proxy的newProxyInstance方法。这里创建代理对象的时候,需要指明3个参数,一个是类加载器、一个是代理接口、另一个是Proxy回调方法所在的对象,这个对象需要实现InvocationHandler接口。这里JdkDynamicAopProxy本身就实现了该接口,所以可以使用this对象本身作为参数。

3.3.5 CGLIB生成AopProxy代理对象

通过CGLIB生成AopProxy代理对象同样是在实现AopProxy接口方法getProxy完成的,主要过程是先从advised中取得在IoC容器中配置的target对象,然后创建并配置CGLIB的Enhancer对象(这个Enhancer对象时CGLIB的主要操作类),通过Enhancer对象来生成代理对象。在生成过程中,要注意Enhancer对象callback回调的设置,正是这些回调封装了Spring AOP的实现。

那么到这里,通过使用AopProxy对象封装target目标对象之后,ProxyFactoryBean的getObject方法得到的对象就不是一个普通的Java对象了,而是一个AopProxy的代理对象。这个时候已经不会让应用直接调用target的方法实现了,而是先被AopProxy代理对象拦截,对于不同的Aopproxy代理对象的不同生成方法,拦截入口不同。比如:JDK使用的是InvocationHandler使用的是invoke入口,二Cglib使用的是设置好的callback回调。

猜你喜欢

转载自my.oschina.net/u/3342874/blog/1821896
3.3