上一篇中,我们通过JDK动态代理已经生成了代理对象,AOP通过JDK创建的动态代理对象,最终都会执行JdkDynamicAopProxy类的invoke()方法,而在这个invoke()方法中,就会来执行目标方法和切面中的增强逻辑了,那执行过程到底是怎么样的呢?我们今天就来分析下这个invoke()方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
// 获取代理的目标对象,也就是真正的对象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 对equals 方法的处理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// 对hashCode方法的处理
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
// 对DecorationgProxy接口中定义方法的处理
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// 如果是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);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 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.
// 获取当前调用方法的拦截器链, advised就是一个ProxyFactory
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 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
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 处理拦截器链,也就是依次执行每一个拦截器
retVal = invocation.proceed();
}
// 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;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
首先我们来看这块代码,如下图:
我们刚进入invoke()方法时需要执行的代码,我们看到有很多的if 判断,那这些if判断是做什么呢?我们看到前两个if分支的条件,分别调用了isEqualsMethod()和isHashCodeMethod()方法完成了判断,我们直接点进去看下这两个方法的代码,如下图:
通过上边的代码,我们可以看到,这两个方法上分别有一段注释,大概意思就是说,判断给定的这个方法是不是equals方法和hashCode方法。也就是说如果当前调用的是equals方法的话,那么就执行equals(args[0])这行代码完成处理,而如果是hashCode方法的话,则执行hashCode()这行代码进行处理,而调用的equals(args[0])和hashCode()其实就是JdkDynamicAopProxy类中定义的两个方法而已,代码如下:
可以看到,我们现在不知道这块代码为什么要这样处理?首先我们都知道在调用代理对象的方法时,在invoke()方法中会为我们调用的目标方法添加增强,如果调用的这个方法是我们接口中定义的方法,比如ProductService接口中定义的addProduct()方法和getProductById()方法,如下代码:
// 接口
public interface ProductService {
void addProduct(Product product);
Product getProductById(Integer productId);
}
// 实现类
public class ProductServiceImpl implements ProductService {
public void addProduct(Product product){
}
public Product getProductById(Integer productId){
}
}
也就是说当调用代理对象中的addProduct()方法和getProductById()方法时,invoke()方法就会执行我们的增强逻辑。如果调用的是代理对象的equals方法和hashCode方法,还有没有必要为这两个方法添加逻辑呢?我们知道这两个方法是Object类中定义的方法!如果代理接口ProductService中声明了equals方法和hashCode方法,且目标类productServiceImpl中重写了这两个方法,此时就会为equals方法和hashCode方法执行增强逻辑,否则将直接调用JdkDynamicAopProxy类中定义的equals方法和hashCode方法来完成处理。那么怎么判断代理接口中有没有声明equals方法和hashCode方法呢?其实通过这两个变量就可以,如下图:
我们看下边这块代码:
其实就是当代理接口中没有定义equals方法和hashCode方法时,就直接使用JdkDynamicAopProxy类中的equals方法和hashCode方法完成判断,否则就正常为equals方法和hashCode方法添加增强逻辑。
我们在看下这个代码是做什么的:
这块代码首先通过getDeclaringClass()方法获取到当前方法的声明类,然后再使用获取到的声明类判断这个类是不是指定类,说白了一个是对DecoratingProxy接口中定义方法的处理,一个是对Advised类型的接口中定义的方法的处理,其实我们刚才分析的这一大块代码,都只是在刚进入invoke()方法时,对特定方法和特定类的单独处理,接下来才是真正的处理,也就是执行切面中定义的增强逻辑。
我们接着下边这块代码看下:
我们可以看到其中使用了一个叫做targetSource的属性,那这个targetSource是什么呢?其实这个targetSource在前边已经定义了,targetSource定义的代码如下:
我们可以看到,这里直接将this.advised.targetSource赋值给了targetSource,那么这个advised又是什么呢?我们来看下advised的定义就知道了,我们看这里:
通过上边的代码,我们可以看到,advised是JdkDynamicAopProxy类中的一个变量,并且是在构造方法中完成的初始化。那是因为之前我们分析过这个构造方法,我们看下边的代码:
通过上边的代码,我们可以看到,其实就是在创建jdk代理时,将入参config赋值给了advised变量,那么这个入参config到底是谁呢?这个config就是之前我们分析过的ProxyFactory,我们看下边的代码:
上边代码中的ProxyFactory,之前我们分析过的,这个ProxyFactory就是创建代理最重要的配置,可以看到,这里为ProxyFactory设置了很多关键的属性,比如将增强advisors和目标类targetSource设置到ProxyFactory中。
说白了JdkDynamicAopProxy中的advised属性其实就是之前我们分析过的ProxyFactory,这个ProxyFactory中包含了增强advisors和目标类targetSource等核心属性。我们继续往下分析invoke()方法,我们看下边这块代码:
通过上边的代码,大家可以看到,这里会先从advised中获取到targetSource,说白了就是从ProxyFactory中获取到当时设置的目标对象targetSource,然后再进一步获取到目标对象的class对象并赋值给targetClass。接着就会调用advised(也就是ProxyFactory)中的getInterceptorsAndDynamicInterceptionAdvice()方法,并将目标类(ProductServiceImpl)和当前要执行的方法method作为入参传递进去,最后就可以获取到当前方法method要执行的拦截器链chain了,可以看到,这个chain就是一个List集合。那么这个getInterceptorsAndDynamicInterceptionAdvice()方法具体是怎么处理的呢?我们大概想一下就知道了,在advised(也就是ProxyFactory)中是有所有增强advisors的,是通过addAdvisors()方法将增强advisors设置给了ProxyFactory,所以getInterceptorsAndDynamicInterceptionAdvice()方法肯定是根据advisors经过处理获取到了最终的拦截器链。我们继续往下看,接着我们会看到这样一块代码:
其实这里就是会看一下拦截器链chain是不是为空?如果拦截器链chain为空的话,那么就直接执行目标方法,其中invokeJoinpointUsingReflection()方法的定义如下:
可以看到,这个核心代码就是method.invoke(target, args)这一代码,说白了就是通过反射执行目标方法。而如果拦截器链chain不为空的话,就会执行下边这块代码:
这里会先将拦截器链统一封装为MethodInvocation,然后再执行retVal = invocation.proceed()这行代码,其实就是真正去执行拦截器链。我们继续往下看,我们知道有的方法是有出参的,比如我们的接口getProductById()方法会返回一个商品Product,那么当拦截器链执行完毕后,该怎么返回出参呢?此时我们会看到这块代码:
大家可以看到,其实就是根据returnType对返回值retVal做了简单的处理。这个返回类型returnType很简单,如果你这个方法不需要返回出参,此时returnType的值就是void类型,而如果你这个方法需要返回一个商品Product,此时returnType的值就是com.younger.aop.model.Product类型,最后将返回值retVal直接return回去。
一张图来梳理下AOP代理的执行流程: