本文来分析 Spring 中 JdkDynamicAopProxy 代理对象的生成 getProxy() 方法和拦截增强 invoke 方法的相关处理逻辑。上文我们研究过了 Pointcut 和 Advice(Advisor)接口以及它们在 Spring AOP 代理中的作用,并利用几个 Demo 演示了其相关关系。为了方便阅读,把上文中的 ProxyFactoryDemo 类代码再次贴出来。
public class ProxyFactoryDemo {
public static void main(String[] args) {
// 1. 构造目标对象
Cat catTarget = new Cat();
// 2. 通过 target 对象,构造 ProxyFactory 对象
ProxyFactory factory = new ProxyFactory(catTarget);
// 添加一个方法拦截器
factory.addAdvice(new MyMethodInterceptor());
// 3. 根据目标对象生成代理对象
Object proxy = factory.getProxy();
Animal cat = (Animal) proxy;
cat.eat();
}
}
首先,我们从 ProxyFactory
类的 getProxy()
方法开始分析
public Object getProxy() {
return createAopProxy().getProxy();
}
1. createAopProxy()
方法使用了 DefaultAopProxyFactory
类中的 createAopProxy()
方法
该方法会判断生成 JdkDynamicAopProxy
对象还是用于 cglib 代理的 ObjenesisCglibAopProxy
对象。如果 target 对象实现了接口,或者是 jdk 动态代理生成的类,则使用 JdkDynamicAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//...
// 如果被代理类的类型是接口,或者被代理类是 JDK 动态代理生成的代理类,则使用 JDK 动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 使用 CGLIB 动态代理
return new ObjenesisCglibAopProxy(config);
// ...
}
2. 因此重点是 JdkDynamicAopProxy
类的 getProxy()
方法
首先,JdkDynamicAopProxy
实现了 InvocationHandler
接口,所以它有 invoke 方法, 它的 invoke 方法在后面分析。
看到 getProxy()
方法中, 该方法会调用 jdk 动态代理方法 Proxy.newProxyInstance
实现代理,不同的是,代理对象除了 target 对象的接口,还包括 spring 自己额外的一些接口。所以接下来的重点是看 JdkDynamicAopProxy 类中对了了哪些额外接口,和 invoke 中如何反射调用方法
public Object getProxy(@Nullable ClassLoader classLoader) {
// spring 会在内部增加一些代理对象需要额外实现的接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 我们熟悉的 JDK 动态代理类生成方法
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
(1)获取代理类应该实现的接口: AopProxyUtils.completeProxiedInterfaces(this.advised, true)
如下代码显示,代理对象要实现的接口包括4种
- 被代理对象实现的接口
- SpringProxy 接口
- Advised 接口
- DecoratingProxy 接口
// AopProxyUtils.java
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
// (1) 被代理对象实现的接口
Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
// (2) 如果被代理的接口集合中没有 SpringProxy 接口,则需要添加 SpringProxy 接口
boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
// (3) 如果 opaque 为 false(默认是 false),且被代理的接口集合中没有 Advised 接口,则需要添加 Advised 接口到被代理集合集合中
boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
// (4) decoratingProxy 为 ture,且被代理的接口集合中没有 DecoratingProxy 接口,则需要添加 DecoratingProxy 接口到被代理集合集合中
boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
// 组合接口数组
int nonUserIfcCount = 0;
if (addSpringProxy) {nonUserIfcCount++;}
if (addAdvised) {nonUserIfcCount++;}
if (addDecoratingProxy) {nonUserIfcCount++;}
// 数组
Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
// 数组拷贝
System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
int index = specifiedInterfaces.length;
if (addSpringProxy) {
proxiedInterfaces[index] = SpringProxy.class;
index++;
}
if (addAdvised) {
proxiedInterfaces[index] = Advised.class;
index++;
}
if (addDecoratingProxy) {
proxiedInterfaces[index] = DecoratingProxy.class;
}
return proxiedInterfaces;
}
(2)invoke 方法的逻辑
该方法分为4大类
- (i)不对 equals() 和 hashCode() 方法代理
- (ii)
DecoratingProxy
接口的方法代理 - (iii)
Advised 接口
的方法 - (v)控制拦截器链一个一个的对 target 对象实现接口的增强处理
(v)下面重点分析
// AopProxyUtils.java
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// (1) 不对 equals() 和 hashCode() 方法代理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
// (2) 如果是 DecoratingProxy 接口的方法
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// (3) 如果是 Advised 接口的方法
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// 如果需要在拦截器暴露 proxy 对象,则把 proxy 对象添加到 ThreadLocal 中
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 获取 target 对象
target = targetSource.getTarget();
// target 对象的 Class
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取用于 invoke 方法中的拦截器链,职责链模式对代理类加强
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// (4) ReflectiveMethodInvocation 控制拦截器链一个一个的进行增强处理
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed(); // 驱动拦截器责任链的运行,并获取到返回值。
// ...
}
(v)控制拦截器链向前推行的方法
拿出上面相关步骤的代码,发现重点在两步:拦截器链的获取和推进执行
// 获取用于 invoke 方法中的拦截器链,职责链模式对代理类加强
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// (4) ReflectiveMethodInvocation 控制拦截器链一个一个的进行增强处理
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed(); // 驱动拦截器责任链的运行,并获取到返回值。
- 拦截器链的获取
getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
- 拦截器链推进执行
ReflectiveMethodInvocation#proceed()
- 用角标控制拦截器数组的推进
- 每个拦截器执行完增强,都要调回 ReflectiveMethodInvocation 的 proceed() 方法进行推进
// ReflectiveMethodInvocation.java
// 拦截器Index,记录当前推进到哪个拦截器
private int currentInterceptorIndex = -1;
public Object proceed() throws Throwable {
// (1)拦截器 index 推进完毕,直接执行 target 对象的方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint(); // 内部就是反射执行方法 method.invoke(target, args);
}
// (2)根据 index, 从连接器链中获取 MethodInterceptor 对象
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 计算是否需要匹配方法
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
// 就是自己实现的 MyPoinCut 对象中的 methodMatcher
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
// 匹配的话,执行 MethodInterceptor 的 invoke() 方法
// 传入 this,是为了让 MethodInterceptor 执行增强后调用 this.proceed() 讲方法传递
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// 不需要匹配的话直接调用拦截器
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
[附] 拦截器 MethodInterceptor 的实现
public static class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("MyMethodInterceptor invoke 调用 before invocation.proceed");
Object ret = invocation.proceed();
System.out.println("MyMethodInterceptor invoke 调用 after invocation.proceed");
return ret;
}
}