Spring AOP源码解析-拦截器链的执行过程

一.简介

在前面的两篇文章中,分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程。现在得到了 bean 的代理对象,且通知也以合适的方式插在了目标方法的前后。接下来要做的事情,就是执行通知逻辑了。通知可能在目标方法前执行,也可能在目标方法后执行。具体的执行时机,取决于用户的配置。当目标方法被多个通知匹配到时,Spring 通过引入拦截器链来保证每个通知的正常执行。在本文中,我们将会通过源码了解到 Spring 是如何支持 expose-proxy 属性的,以及通知与拦截器之间的关系,拦截器链的执行过程等。

二.背景知识

有时候目标对象内部的自我调用将无法实施切面中的增强:

public interface UserService{
	public void a();
	public void a();
}

public class UserServiceImpl implements UserService{
	@Transactional(propagation = Propagation.REQUIRED)
	public void a(){
		this.b();
	}
	@Transactional(propagation = Propagation.REQUIRED_NEW)
	public void b(){
		System.out.println("b has been called");
	}
}

a的事务会生效,b中不会有事务,因为a中调用b属于内部调用,没有通过代理,所以不会有事务产生(原因:SpringAOP对于最外层的函数只拦截public方法,不拦截protected和private方法,另外不会对最外层的public方法内部调用的其他方法也进行拦截,即只停留于代理对象所调用的方法。)。

为了解决这个问题,我们可以这样做:<aop:aspectj-autoproxy expose-proxy=“true”> ,设置expose-proxy属性为true,将代理暴露出来,使用AopContext.currentProxy()获取当前代理,将this.b()改为((UserService)AopContext.currentProxy()).b()。

三.源码解析

本章所分析的源码来自 JdkDynamicAopProxy。

3.1 JDK 动态代理逻辑分析

对于 JDK 动态代理,代理逻辑封装在 InvocationHandler 接口实现类的 invoke 方法中。JdkDynamicAopProxy 实现了 InvocationHandler 接口,下面我们就来分析一下 JdkDynamicAopProxy 的 invoke 方法。如下:

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		MethodInvocation invocation;
		Object oldProxy = null;
		boolean setProxyContext = false;
 
		//获取原对象信息
		TargetSource targetSource = this.advised.targetSource;
		Class<?> targetClass = null;
		Object target = null;
 
		try {
			//如果接口中定义了equals或hashCode方法,则进行专门处理
			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);
			}
			//opaque属性,表示是否禁止将代理对象转换为Advised对象,默认是false
			//如果调用的方法来自Advised接口
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				//通过反射Method.invoke,调用advised(传入的ProxyFactory实例,该类实现了Advised接口)对应的方法
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}
 
			Object retVal;
			//为了解决目标对象内部的自我调用无法实施切面中的增强,需要暴露代理对象
			if (this.advised.exposeProxy) {
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}
 
			// 获取目标对象信息
			target = targetSource.getTarget();
			if (target != null) {
				targetClass = target.getClass();
			}
 
			// 获取当前方法的拦截器链
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 
			// 如果没有任何拦截器,则调用直接对原目标对象调用方法
			if (chain.isEmpty()) {
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// 将拦截器链封装到ReflectiveMethodInvocation,方便使用其proceed进行链式调用拦截器
				invocation = new ReflectiveMethodInvocation(proxy, target, meth
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值