Spring 源码阅读 61:基于 JDK 动态代理的 AOP 代理回调方法 invoke 分析
概述
上一篇中,分析了 Spring AOP 通过 JDK 动态代理和 CGLIB 创建代理对象的逻辑。在 JDK 动态代理的方式中,会创建一个 JdkDynamicAopProxy 作为代理对象的 InvocationHandler 来处理对目标方法的增强。本文开始,我们将进入 JdkDynamicAopProxy 的invoke
方法,看看增强逻辑是如何执行的。
invoke 方法
找到 JdkDynamicAopProxy 类型的invoke
方法源码。
方法比较长,我们可以先分析整体结构,其中主要的逻辑都在try
语句块中,我们分成几个部分来分析具体的逻辑。
advised 成员变量的来源
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
方法的开始,定义了一些后面会用到的局部变量,这里需要留意一下targetSource
这个局部变量,其他几个只是给了一个简单的初始值,后面流程中遇到了再分析。
targetSource
的值是this.advised.targetSource
,我们先找到advised
环境变量。
/** Config used to configure this proxy. */
private final AdvisedSupport advised;
它的类型是 AdvisedSupport,注释中说明了它是对代理对象的配置。前面我们分析过 JdkDynamicAopProxy 对象的创建,创建的方式是调用它的构造方法。
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
advised
正是在构造方法中创建的,而方法参数传入的config
参数,就是创建代理对象之前初始化好的 ProxyFactory 对象。
advised
的targetSource
属性,则是初始化 ProxyFactory 时为其配置的属性,其中封装了目标 Bean 的信息。
特殊情况的处理
回到invoke
方法中接着往下看,进入try
语句块中的逻辑。
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
这里通过对参数中传入的method
变量的判断,对被调用的目标方法的四种特定情况进行了处理,如果执行的方法调用,不在这四种特殊情况当中,则执行后面的一般情况处理逻辑。
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
接下来,如果exposeProxy
的值为true
的话,将代理对象放到当前的 AopContext 上下文中。不过,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);
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
获取被代理的目标对象和目标对象的类型。并且,从advised
中获取到增强目标方法的拦截器链。这里调用的getInterceptorsAndDynamicInterceptionAdvice
方法是invoke
方法的流程中的关键点之一。获取到拦截器链之后,就是拦截器中的增强逻辑的执行。
执行增强逻辑
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// 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 = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
这里分成了两种情况,就是拦截器链是不是为空的情况。
这里需要说明一下拦截器链为空的情况。在创建 AOP 代理之前,已经根据目标类型,进行过了拦截器的匹配(也就是 Advisor 的筛选),那为什么还会出现这里找到的拦截器链为空的情况呢?在创建代理的时候,因为被代理的是一个类,只要这个类中,有一个方法需要被增强,这个类就需要被代理。但是,具体到这个类中的每一方法,并不是需要被代理的类中的每一个方法都会被增强,因此,这里需要分情况处理。
返回执行结果
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
方法的最后一部分,就是将最终执行的结果返回。
总结
本文分析了 JdkDynamicAopProxy 的invoke
方法,invoke
方法是基于 JDK 动态代理创建的 AOP 代理对象的方法处理回调逻辑,也是 Spring AOP 增强目标方法的关键逻辑。通过本文,可以了解invoke方法的整体流程,下一篇开始将会深入分析其中的原理细节。
转载自:https://juejin.cn/post/7158771615184977927