持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第34天,点击查看活动详情
基于 Spring Framework v5.2.6.RELEASE
概述
上一篇分析了基于 CGLIB 的 AOP 代理对象执行 AOP 增强逻辑的入口,也就是 DynamicAdvisedInterceptor 的intercept
方法,本文来进入这个方法,分析其执行增强逻辑的原理。
DynamicAdvisedInterceptor 的 intercept 方法
首先看这个方法的源码。
方法虽然很长,但是真正执行逻辑的代码并不多。
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = 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 = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
接下来就是对获取到的拦截器链进行判断,如果拦截器链是空的,且方法是public
修饰的,则不需要执行拦截器的逻辑。在if
语句块中,首先通过 AopProxyUtils 类的adaptArgumentsIfNecessary
方法,对调用方法的参数进行处理,这里主要是在有必要的情况下,对方法参数列表中的可变参数进行类型适配。然后,通过methodProxy
的invoke
方法直接调用目标方法。
如果拦截器链不为空,那么则会通过构造方法创建一个 CglibMethodInvocation 对象,然后调用它的proceed
方法,执行拦截器链的增强逻辑。
我们先看一下 CglibMethodInvocation 类。
可以看到,它是 ReflectiveMethodInvocation 的子类,而 ReflectiveMethodInvocation 是基于 JDK 动态代理的 AOP 代理回调方法中用来执行拦截器链逻辑的类型,因此可以推测,这两种代理方式的拦截器链执行逻辑应该也大同小异。
接下来看一下 CglibMethodInvocation 的类定义和构造方法。
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
@Nullable
private final MethodProxy methodProxy;
public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
Object[] arguments, @Nullable Class<?> targetClass,
List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
// Only use method proxy for public methods not derived from java.lang.Object
this.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#proceed
@Override
@Nullable
public Object proceed() throws Throwable {
try {
return super.proceed();
}
catch (RuntimeException ex) {
throw ex;
}
catch (Exception ex) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
throw ex;
}
else {
throw new UndeclaredThrowableException(ex);
}
}
}
其核心逻辑只有一行,就是调用父类的proceed
方法,也就是 ReflectiveMethodInvocation 的proceed
方法,到这里,接下来的逻辑就跟基于 JDK 动态代理的 AOP 代理回调执行拦截器链的逻辑相同了,在之前的文章中,也详细分析过这个方法的执行逻辑,你可以通过之前的文章来了解其中的细节。
总结
本文分析了基于 CGLIB 的 AOP 代理如何查找和执行拦截器链,其主要的逻辑在 DynamicAdvisedInterceptor 的intercept
方法执行。对于拦截器链的查找和执行逻辑,与基于 JDK 动态代理的 AOP 代理的执行逻辑共用了大部分的代码。