spring aop(二) JdkDynamicAopProxy 代理执行过程

本文来分析 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()
    1. 用角标控制拦截器数组的推进
    2. 每个拦截器执行完增强,都要调回 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;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值