基于 Spring Framework v5.2.6.RELEASE
相关阅读:Spring 源码阅读 60:通过 JDK 动态代理或者 CGLIB 创建 AOP 代理对象
接上一篇:Spring 源码阅读 71:基于 CGLIB 的 AOP 代理的原理(1)- DynamicAdvisedInterceptor 分析
概述
上一篇分析了基于 CGLIB 的 AOP 代理对象执行 AOP 增强逻辑的入口,也就是 DynamicAdvisedInterceptor 的intercept
方法,本文来进入这个方法,分析其执行增强逻辑的原理。
DynamicAdvisedInterceptor 的 intercept 方法
首先看这个方法的源码。
方法虽然很长,但是真正执行逻辑的代码并不多。
ObjectoldProxy=null; booleansetProxyContext=false; Objecttarget=null; TargetSourcetargetSource=this.advised.getTargetSource();
方法的一开始会声明一些变量,这些变量会在后面的流程中看到,其中包括从advised
属性中获取到的被代理的目标对象。advised
成员变量是在创建 DynamicAdvisedInterceptor 是通过构造方法的参数传入的。
后续的流程会进入一个try
语句块。
if (this.advised.exposeProxy) { // Make invocation available if necessary.oldProxy=AopContext.setCurrentProxy(proxy); setProxyContext=true; }
这个if语句块中,会将代理对象放到 AopContext 上下文中,不过默认情况下,this.advised.exposeProxy
的值是false
,因此这里的逻辑不会被执行。
拦截器的查找
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...target=targetSource.getTarget(); Class<?>targetClass= (target!=null?target.getClass() : null); List<Object>chain=this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
接下来会进入一个重要的步骤,就是根据目标类型和当前调用的方法,查找拦截器链。如果你读过之前关于基于 JDK 动态代理的 AOP 代理的原理,就会发现这个用来查找拦截器链的方法很熟悉。其实,这个方法跟 JdkDynamicAopProxy 的invoke
方法中调用的getInterceptorsAndDynamicInterceptionAdvice
方法是同一个方法。
关于这个方法的原理,我之前写过 4 篇文章来详细介绍,可以阅读之前的文章来了解其中的原理。
拦截器的执行
// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() &&Modifier.isPublic(method.getModifiers())) { // We can skip creating a MethodInvocation: just invoke the target directly.// Note that the final invoker must be an InvokerInterceptor, so we know// it does nothing but a reflective operation on the target, and no hot// swapping or fancy proxying.Object[] argsToUse=AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal=methodProxy.invoke(target, argsToUse); } else { // We need to create a method invocation...retVal=newCglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); }
接下来就是对获取到的拦截器链进行判断,如果拦截器链是空的,且方法是public
修饰的,则不需要执行拦截器的逻辑。在if
语句块中,首先通过 AopProxyUtils 类的adaptArgumentsIfNecessary
方法,对调用方法的参数进行处理,这里主要是在有必要的情况下,对方法参数列表中的可变参数进行类型适配。然后,通过methodProxy
的invoke
方法直接调用目标方法。
如果拦截器链不为空,那么则会通过构造方法创建一个 CglibMethodInvocation 对象,然后调用它的proceed
方法,执行拦截器链的增强逻辑。
我们先看一下 CglibMethodInvocation 类。
可以看到,它是 ReflectiveMethodInvocation 的子类,而 ReflectiveMethodInvocation 是基于 JDK 动态代理的 AOP 代理回调方法中用来执行拦截器链逻辑的类型,因此可以推测,这两种代理方式的拦截器链执行逻辑应该也大同小异。
接下来看一下 CglibMethodInvocation 的类定义和构造方法。
privatestaticclassCglibMethodInvocationextendsReflectiveMethodInvocation { privatefinalMethodProxymethodProxy; publicCglibMethodInvocation(Objectproxy, Objecttarget, Methodmethod, Object[] arguments, Class<?>targetClass, List<Object>interceptorsAndDynamicMethodMatchers, MethodProxymethodProxy) { super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers); // Only use method proxy for public methods not derived from java.lang.Objectthis.methodProxy= (Modifier.isPublic(method.getModifiers()) &&method.getDeclaringClass() !=Object.class&&!AopUtils.isEqualsMethod(method) &&!AopUtils.isHashCodeMethod(method) &&!AopUtils.isToStringMethod(method) ?methodProxy : null); } // 省略其他代码}
它是 CglibAopProxy 的一个静态内部类,在构造方法中,调用了父类的构造方法,也就是 ReflectiveMethodInvocation 的构造方法,此外,还初始化了methodProxy
变量。methodProxy
初始化的逻辑也比较简单,主要是确保被代理的方法是public
修饰的不是声明在 Object 中的方法,且不是equals
、hashCode
、toString
这三个方法。
对父类构造方法的调用主要是一些属性的初始化,之前介绍 ReflectiveMethodInvocation 的时候,已经介绍过,这里不再赘述。
了解完构造方法之后,再看其执行拦截器链逻辑的proceed
方法。
// org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceedpublicObjectproceed() throwsThrowable { try { returnsuper.proceed(); } catch (RuntimeExceptionex) { throwex; } catch (Exceptionex) { if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) { throwex; } else { thrownewUndeclaredThrowableException(ex); } } }
其核心逻辑只有一行,就是调用父类的proceed
方法,也就是 ReflectiveMethodInvocation 的proceed
方法,到这里,接下来的逻辑就跟基于 JDK 动态代理的 AOP 代理回调执行拦截器链的逻辑相同了,在之前的文章中,也详细分析过这个方法的执行逻辑,你可以通过之前的文章来了解其中的细节。
总结
本文分析了基于 CGLIB 的 AOP 代理如何查找和执行拦截器链,其主要的逻辑在 DynamicAdvisedInterceptor 的intercept
方法执行。对于拦截器链的查找和执行逻辑,与基于 JDK 动态代理的 AOP 代理的执行逻辑共用了大部分的代码。