Spring之AOP流程解析(ProxyFactory)

Posted letsfly

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring之AOP流程解析(ProxyFactory)相关的知识,希望对你有一定的参考价值。

  本节我们从ProxyFactory开始分析。该类有几个比较重要的方法——addAdvice、addAdvisor、getProxy,其中最后一个方法是我们本节的重点。前两个方法都是向ProxyFactory中成员变量advisors中加入成员,以便后面调用方法时实现拦截。
  这里,我们首先来了解前两个方法。在addAdvice中会调用到addAdvisor,而内部封装的advisor实际类型是DefaultPointcutAdvisor。如下图所示,这里将advice封装到DefaultPointcutAdvisor。这里我们默认只传入advice参数,在DefaultPointcutAdvisor中的成员变量pointcut默认为Pointcut.TRUE,也就是TruePointcut.INSTANCE,他比较特殊的是通过方法getClassFilter返回的是ClassFilter.TRUE,也就是TrueClassFilter.INSTANCE,通过方法getMethodMatcher返回的是MethodMatcher.TRUE,也就是TrueMethodMatcher.INSTANCE。通过他们的matches方法返回值都是true。接着,在addAdvisor方法中调用了addAdvisorInternal,该方法将入参advisor加入成员变量advisors中,然后将其中的值转换为数组赋给成员变量advisorArray(该变量用于后来在方法DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice中构建interceptorList列表),然后调用adviceChanged方法将成员变量methodCache中的值清空。技术图片
  下面,我们来到本节的重点ProxyFactory.getProxy,该方法并不复杂,只是返回一个代理对象,该代理对象除了实现了ProxyFactory.targetSource.getTargetClass所实现接口,另外实现了SpringProxy、Advised、DecoratingProxy这三个接口。
  在ProxyFactory.getProxy方法中调用了ProxyCreatorSupport.createAopProxy,该方法首先调用了方法activate,然后通过方法getAopProxyFactory获得成员变量aopProxyFactory,该成员变量在通过ProxyFactory调用时是DefaultAopProxyFactory的实例。关于ProxyCreatorSupport的另一个构造方法,入参为aopProxyFactory,调用是在ProxyFactoryBean.newPrototypeInstance中,我将放在以后来讲解。接下来调用了DefaultAopProxyFactory.createAopProxy,这里的入参就是我们的ProxyFactory,这点需要紧记,因为在后来的代理对象调用方法时会用到,这里的入参接着会传入到接下来构建的AopProxy实现类型中。在DefaultAopProxyFactory.createAopProxy方法中根据情况构造了ObjenesisCglibAopProxy或者JdkDynamicAopProxy。其中JdkDynamicAopProxy是AopProxy基于JDK的实现,而ObjenesisCglibAopProxy是基于Cglib的实现,他直接继承自CglibAopProxy。这里我只分析JdkDynamicAopProxy,大家有兴趣可以看一下ObjenesisCglibAopProxy,二者只是实现方式不同,大体流程是一致的。我们这里然后就调用了JdkDynamicAopProxy.getProxy,这里有一个参数是ClassUtils.getDefaultClassLoader(),该方法获取的是当前线程的ClassLoader,也就是默认的AppLauncher。然后通过方法AopProxyUtils.completeProxiedInterfaces填充了SpringProxy、Advised、DecoratingProxy这三个接口。而后通过Proxy.newProxyInstance方法构建了代理对象,注意,这里的最后一个入参就是我们这里的JdkDynamicAopProxy。
  下面,假设我们调用了返回的代理对象的某个方法,也就是说,我们将来到JdkDynamicAopProxy.invoke。不知道大家是否还记得,在JdkDynamicAopProxy.advised就是在DefaultAopProxyFactory.createAopProxy方法中的入参,也就是我们的ProxyFactory。让我们再回到JdkDynamicAopProxy.invoke方法。这里首先获得了advised.targetSource,也就是ProxyFactory.targetSource。这里的targetSource是在ProxyFactory的构造函数中将入参Object封装后的TargetSource,默认实现是SingletonTargetSource。接着调用了targetSource.getTarget,也就是获取到了我们这里的目标对象,也就是构造ProxyFactory时的入参Object。然后,获取到target的实际类型,调用了advised.getInterceptorsAndDynamicInterceptionAdvice,也就是方法AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice。该方法根据之前传入的advisor构建调用链。由于我们之前并没有调用该方法,因此,在AdvisedSupport.methodCache中并没有该方法的缓存值,然后调用了DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice来构造cached并将其将入到成员变量methodCache中。
  接下来,让我们来到DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice,该方法实现了将入参config中的Advisors转换为通过匹配后的MethodInterceptor列表,也就是真实方法调用前的拦截链。如下图所示,这里是getInterceptorsAndDynamicInterceptionAdvice的完整方法。
  1.首先调用GlobalAdvisorAdapterRegistry.getInstance获得DefaultAdvisorAdapterRegistry。这里我们需要注意的是在DefaultAdvisorAdapterRegistry的构造方法中已经调用registerAdvisorAdapter方法为其成员变量adapters加入了MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter这三个AdvisorAdapter。
  2.调用入参config.getAdvisors获取在ProxyFactory中配置的advisors。
  3.遍历ProxyFactory.advisors,一般来说,在ProxyFactory中加入的advisor是DefaultPointcutAdvisor,实现了接口PointcutAdvisor。因此,这里将advisor强转为PointcutAdvisor,获取其pointcut,紧接着调用Pointcut.getClassFilter,并调用ClassFilter.matches,判断目标类型是否与当前pointcut的ClassFilter相匹配,如果返回值为true,则继续调用PointcutAdvisor.getPointcut.getMethodMatcher获得MethodMatcher,接着判断其是否与目标类型的调用方法相匹配。如果当前调用方法确实是拦截点,就会调用DefaultAdvisorAdapterRegistry.getInterceptors将当前advisor转换为MethodInterceptor列表。
  这里我简单说一下PointcutAdvisor与Advisor。PointcutAdvisor实现接口Advisor,并且增加了方法getPointcut,返回的Pointcut就是用来判断当前执行的方法是否与当前PointcutAdvisor相匹配。而advisor的作用就是用来封装advice,其有一个方法是getAdvice。这里的DefaultAdvisorAdapterRegistry.getInterceptors方法我放到后面来讲解。
  4.将返回的MethodInterceptor数组加入到interceptorList中然后返回。技术图片
  这里我们首先来到DefaultAdvisorAdapterRegistry.getInterceptors。
  1.如果通过advisor.getAdvice获取的advice实现了接口MethodInterceptor,则直接将其加入到interceptors列表中。
  2.这里的成员变量adapters就是在DefaultAdvisorAdapterRegistry构造时就填充了MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter。接着遍历adapters并将满足条件的advice封装后加入到interceptors列表中。
  这里我们以MethodBeforeAdviceAdapter为例。在MethodBeforeAdviceAdapter.supportsAdvice方法中仅仅是判断入参advice是否实现了MethodBeforeAdvice接口,如果满足条件,则调用MethodBeforeAdviceAdapter.getInterceptor将advice强转为MethodBeforeAdvice并将其封装到MethodBeforeAdviceInterceptor中。技术图片
  到此为止,我们就构造好了AdviceChain,接下来,来到本节的最后一个重点——构造ReflectiveMethodInvocation,并调用其proceed方法。在构造ReflectiveMethodInvocation时,其最后一个入参就是我们刚刚构造好的chain。接下来,我们来到ReflectiveMethodInvocation.proceed。这里的链式调用很类似web应用中的过滤器,可能spirng团队也是经常写web架构的。
  1.这里首先判断当前调用是否已经将所有的调用链完成,如果已经完成,则调用invokeJoinpoint,触发真实要执行的方法。大家可能比较疑惑,这里为什么是interceptorsAndDynamicMethodMatchers.size() - 1,因为这里的currentInterceptorIndex是从-1开始的,如果从0开始的话,那么,显然就没有后面的 - 1。
  2.从interceptorsAndDynamicMethodMatchers列表中获取值,然后调用其invoke方法。这里我把MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor都讲解一下。
  如果这里的MethodInterceptor实际类型是MethodInterceptor,那么调用了MethodBeforeAdviceInterceptor.invoke,注意,这里的入参是ReflectiveMethodInvocation,也就是说,这里在调用了advice.before后,接着调用了ReflectiveMethodInvocation.proceed,接着来到ReflectiveMethodInvocation.proceed。
  然后假设这里的MethodInterceptor实际类型是AfterReturningAdviceInterceptor,这里直接就调用了ReflectiveMethodInvocation.proceed,在其调用完成后,调用了advice.afterReturning。
  接着,我们假设这里的MethodInterceptor实际类型是ThrowsAdviceInterceptor,这里直接调用了ReflectiveMethodInvocation.proceed,不过,这里添加了异常捕获如果获取到对应的Method,则通过invokeHandlerMethod调用捕获异常的方法。然后继续将异常抛出。
  可以说,这里很好的使用的递归的思路,实现了拦截器的链式调用。技术图片
  到这里,本节的内容就结束了。尽管内容洋洋洒洒,但是当你调试代码的时候,会发现其实并没有多少东西。希望大家在看本文的时候尽量结合源码调试,以加深理解。如果有疑问或有相关问题探讨,欢迎大家留言。

以上是关于Spring之AOP流程解析(ProxyFactory)的主要内容,如果未能解决你的问题,请参考以下文章

解析Spring AOP执行流程

Spring源码剖析-事务源码之@Transactionl解析

spring AOP解析之xml方式详解

Spring AOP源码分析

spring AOP解析之注解方式详解

做一个合格的程序猿之浅析Spring AOP源码(十八) Spring AOP开发大作战源码解析