3.4.1 设计原理
在Spring AOP通过JDK的Proxy方式或者CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。
如果使用JDK的Proxy来生成代理对象,那么需要通过InvocationHandler来设置拦截器回调;如果使用CGLIB来生成代理对象,就通过DynamicAdvisedInterceptor来完成回调。
3.4.2 JdkDynamicAopProxy的invoke拦截
在JdkDynamicAopProxy生成代理对象是通过以下方式完成的:
Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
这里的this参数对应的是InvocationHandler对象,InvocationHandler是JDK定义的反射类的一个接口,这个接口定义了invoke方法,而这个invoke方法是作为JDK Proxy代理对象进行拦截的回调入口出现的。当Proxy对象的代理方法被调用时,JdkDynamicAopProxy的invoke方法作为Proxy对象的回调函数被触发,从而通过invoke的具体实现来完成对目标对象方法调用的拦截或者说功能增强。在这个invoke方法中,实现了对Proxy对象的代理设置,这些设置包括获取目标对象、拦截器链,同时把这些对象作为输入,创建ReflectionMethodInvocation对象,通过ReflectionMethodInvocation对象完成AOP功能实现的封装。在这个invoke方法中,包含了一个完整的拦截器链对目标对象的拦截过程,比如获得拦截器链并对其中的拦截器配置,然后逐个运行拦截器链里的拦截增强,直到最后运行目标对象方法。
3.4.3 Cglib2AopProxy的intercept拦截
Cglib2AopProxy生成代理对象时,进行拦截的回调入口是在DynamicAdvisedInterceptor对象的intercept方法中实现的,它的回调方法实现和
JdkDynamicAopProxy的回调实现非常类似,区别在于:
在Cglib2AopProxy中,构造CglibMethodInvocation对象来完成;
在JdkDynamicAopProxy中,构造ReflectionMethodInvocation对象来完成。
3.4.4 目标对象方法的调用
如果没有设置拦截器,那么会对目标对象的方法直接调用。
如果是对于JdkDynamicAopProxy的代理对象,对目标方法的调用是通过AopUtils使用反射机制在AopUtils.invokeJoinpointUsingReflection的方法中实现的,在这个调用中,首先得到调用方法的反射对象,再使用invoke启动对方法反射对象的调用。
如果是对于Cglib2AopProxy的代理对象,它对目标对象的调用是通过CGLIB的MethodProxy对象来直接完成的,具体调用在DynamicAdvisedInterceptor对象的intercept方法中可以看到,具体代码是:retVal = methodProxy.invoke(target, args);
3.4.5 AOP拦截器链的调用
虽然JDK和CGLIB使用了不同的AopProxy代理对象,但最终对AOP拦截的处理几乎是一样的:它们对拦截器链的调用都是在ReflectionMethodInvocation中通过proceed方法实现。
在proceed方法中,先进行判断,如果现在已经运行到拦截器链的末尾,那么就会直接调用目标对象的实现方法;否则,沿着拦截器链继续进行,得到下一个拦截器,通过这个拦截器进行matches判断,判断是否适用于横切增强的场合,如果是,从拦截器中得到通知器,并开启通知器的invoke方法进行切面增强。在这个过程结束以后,会迭代调用proceed方法,直到拦截器链中的拦截器都完成以上的拦截过程为止。
3.4.6 配置通知器
在整个AopProxy代理对象的拦截回调过程中,先回到ReflectionMethodInvocation类的proceed方法,在这个方法中可以看到得到了一个拦截器interceptorOrInterceptionAdvice,这个拦截器是interceptorsAndDynamicMethodMatchers持有的list中的一个元素。关于如何配置拦截器(通知器)的问题就转化成了这个list中的拦截器元素来自哪里,在哪里配置的问题。在JdkDynamicAopProxy中的invoke方法或者Cglib2AopProxy中DynamicAdvisedInterceptor对象的intercept回调方法中,可以看到获取拦截器的操作是由advised对象完成的:
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice
(method, targetClass);
这个advised是一个AdvisedSupport对象,在AdvisedSupport的代码中可以看到上述getInterceptorsAndDynamicInterceptionAdvice方法的具体实现是在这个方法中取得了拦截器链,为提高取得拦截器链的效率,还未这个拦截器链设置了缓存。
在这个方法中,取得拦截器链的工作是由advisorChainFactory来完成的,它是一个生产通知器链的工厂,在这里它被配置成一个DefaultAdvisorChainFactory对象,在DefaultAdvisorChainFactory中,获取拦截器链的过程如下:首先设置一个List,长度由配置的通知器的个数决定,这个配置就是XML中对ProxyFactoryBean做的interceptNames属性的配置;然后通过一个AdvisorAdapterRegistry来实现拦截器的注册,利用这个注册器来对ProxyFactoryBean配置中得到的通知进行适配,从而获得相应的拦截器,再把这个拦截器加入到前面设置好的List中,完成适配和注册过程以后,List中的拦截器会被JDK生成的AopProxy代理对象的invoke方法或者CGLIB代理对象的intercept拦截方法取得,并启动拦截器的invoke调用,触发通知的切面增强。
在初始化拦截器链的时候是如何获取advisor通知器的?它是委托给IoC容器完成的,在ProxyFactoryBean中先获得IoC容器,然后通过回调IoC容器的getBean方法来得到通知器advisor。这里涉及到了IoC容器的实现原理,如果一个Bean的类型实现了BeanFactoryAware接口,那么就可以把IoC容器设置到Bean自身定义的一个属性中去,那么在这个Bean的自身实现中就能得到它所在的IoC容器,从而调用IoC容器的getBean方法,完成对IoC容器的回调。
3.4.7 Advice通知的实现
前面说到有一个取得拦截器的配置过程,由DefaultAdvisorChainFactory实现,这个工厂类负责生成拦截器链,它的getInterceptorsAndDynamicInterceptionAdvice方法中有一个适配和注册过程。在DefaultAdvisorChainFactory的实现中,首先构造了一个GlobalAdvisorAdapterRegistry单件,然后对配置的Advisor通知器进行逐个遍历(配置在interceptorNames中),取得通知器之后就由GlobalAdvisorAdapterRegistry来完成拦截器的适配和注册过程。
GlobalAdvisorAdapterRegistry本质上是一个适配器的作用,也是一个单件模式的应用,它为Spring AOP模块提供了一个DefaultAdvisorAdapterRegistry单件,由这个单件来完成各种通知的适配和注册工作。
再来看DefaultAdvisorAdapterRegistry,这里提供了一系列与Spring AOP的advice通知相对应的adapter适配器。对它们的使用主要是两方面:
1. 调用adapter的support方法,通过这个方法判断取得的advice属于什么类型的advice通知,从而根据不同的advice类型来注册不同的AdviceInterceptor(拦截器);
2. 这些AdviceInterceptor都是Spring AOP框架设计好了的,是为实现不同的advice功能提供服务。有了这些AdviceInterceptor,可以方便地使用由Spring提供的各种不同的advice来设计AOP应用。
在了解这些adapter实现之前,先看下adapter模式(适配器模式):
继续看adapter,从MethodBeforeAdviceAdapter、AfterRunningAdviceAdapter、ThrowsAdviceAdapter等几个通知适配器的名字上就能看到它们和advice一一对应。它们都是实现了AdvisorAdapter接口的同一层次的类,只是各自承担不同的适配任务,一对一地服务于不同的advice实现:
再看这些适配器的具体实现,以MethodBeforeAdviceAdapter为例,它实现了AdvisorAdapter的两个接口方法:
- 一个是supportAdvice,这个方法对advice的类型进行判断,如果advice是MethodBeforeAdviceAdapter的实例,那么返回true;
- 另一个是getInterceptor,这个方法把advice通知从通知器中取出,然后创建一个MethodBeforeAdviceInterceptor对象,通过这个对象把取得的advice通知包装起来,然后返回。
再来看MethodBeforeAdviceInterceptor是如何对通知进行封装的,在MethodBeforeAdviceInterceptor的invoke回调方法中,首先触发了advice的before回调,然后才是MethodInvocation的proceed方法调用。这与前面说到的ReflectionMethodInvocation类的proceed方法联系起来:当AopProxy代理对象触发的ReflectionMethodInvocation的proceed方法中,在取得拦截器以后,启动了对拦截器invoke方法的调用,这个invoke方法会根据不同的advice类型,触发Spring对不同的advice的拦截器封装,比如MethodBeforeAdvice,最终会触发MethodBeforeAdviceInterceptor的invoke方法,在这个方法中会先调用advice的before方法,再调用proceed方法(在方法调用之前完成通知增强)。
举一反三,AfterRunningAdviceInterceptor的实现也类似,不同之处在于AfterRunningAdviceInterceptor invoke方法中先完成了MethodInvocation的proceed方法调用(也就是目标方法的调用),然后再启动advice通知的afterRunning回调。
3.4.8 ProxyFactory实现AOP
在3.3.1章节中了解到,除了使用ProxyFactoryBean实现AOP应用之外,还可以使用ProxyFactory来实现。两者的实现原理是一样的,区别在于:使用ProxyFactoryBean时可以在IoC容器中完成声明式配置;而在使用ProxyFactory时则需要编程式完成配置。