Spring AOP中的责任链设计模式


前言

前面简单的写了下Spring AOP中是怎么实现动态代理的,简单的来说是通过bean对象的后置管理器对实例化的bean对象做判断后使用不同的动态代理方式,下面来看一下生成的动态代理是怎么执行的。

一、示例代码

@Aspect
@Component
public class MyAspect {

	@Pointcut("execution(public void com.jack.service.TestService.doSomething())")
	public void point(){}

	@Before("point()")
	public void beforeMethod(JoinPoint joinPoint) {
		System.out.println("beforeMethod----");
	}

	@After("point()")
	public void afterMethod(JoinPoint joinPoint) {
		System.out.println("afterMethod----");
	}

	@AfterReturning("point()")
	public void AfterReturning() {
		System.out.println("AfterReturning----");
	}

	@AfterThrowing("point()")
	public void AfterThrowing() {
		System.out.println("AfterThrowing----");
	}

	@Around("point()")
	public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
		System.out.println("around start---");
		proceedingJoinPoint.proceed();
		System.out.println("around end---");
	}
}

多配置几个通知类型来观察一下这些通知之间是怎么协调调用的。

二、DynamicAdvisedInterceptor

CGLIB的动态代理主要是依靠MethodInterceptor来实现的,看一下AOP中CglibAopProxy类,在这个类里面有个内部类DynamicAdvisedInterceptor,仔细一看这个类它的父类是MethodInterceptor瞬间就清晰了,这就是最后CGLIB代理的执行类。

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

		private final AdvisedSupport advised;

		public DynamicAdvisedInterceptor(AdvisedSupport advised) {
			this.advised = advised;
		}

		@Override
		@Nullable
		public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object oldProxy = null;
			boolean setProxyContext = false;
			Object target = null;
			//获取代理对象等属性一系列操作
			TargetSource targetSource = this.advised.getTargetSource();
			try {
				if (this.advised.exposeProxy) {
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}
				target = targetSource.getTarget();
				Class<?> targetClass = (target != null ? target.getClass() : null);
				//获取任务调用链
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
				Object retVal;
				//进行了一系列判断,最终断点没走这
				if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
					Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
					try {
						retVal = methodProxy.invoke(target, argsToUse);
					}
					catch (CodeGenerationException ex) {
						CglibMethodInvocation.logFastClassGenerationFailure(method);
						retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
					}
				}
				else {
					//断点走了这里,当走完这一行发现打印完所有语句了,应该是在这里进行的调用
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null && !targetSource.isStatic()) {
					targetSource.releaseTarget(target);
				}
				if (setProxyContext) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}
		...
	}

可以看到获取到的任务调用链就是我们写的那几个通知方法
在这里插入图片描述
在执行过程中我们定位到了执行代理方法的是这一行。

	retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

三、ReflectiveMethodInvocation

CglibMethodInvocation的父类是ReflectiveMethodInvocation,这是最终执行的父类。
看一下其属性

	//代理类
	protected final Object proxy;
	protected final Object target;
	//被代理的方法切面
	protected final Method method; 
	protected Object[] arguments;
	private final Class<?> targetClass;
	//这个打断点后发现里面存放的是切点
	private Map<String, Object> userAttributes;
	//这个是调用链
	protected final List<?> interceptorsAndDynamicMethodMatchers;
	//调用链坐标
	private int currentInterceptorIndex = -1;

可以看到上面的方法CGLIB调用操作最终是对其属性进行赋值。

protected ReflectiveMethodInvocation(
		Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
		@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

	this.proxy = proxy;
	this.target = target;
	this.targetClass = targetClass;
	this.method = BridgeMethodResolver.findBridgedMethod(method);
	this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
	this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}

看一下该类的执行方法,很简单的操作

public Object proceed() throws Throwable {
		// 获取调用链的长度
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
		//获取当前该执行的通知任务
		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());
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				return proceed();
			}
		}
		else {
			//最终断点走了else
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

看断点的结果可以得出结论,代理任务中的多种代理方式都有一个对应的实现类,然后按照代理的顺序去调用不同的代理类。
在这里插入图片描述
随便看一个MethodBeforeAdviceInterceptor中的实现

public Object invoke(MethodInvocation mi) throws Throwable {
	//调用前置处理方法
	this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
	//调用方法
	return mi.proceed();
}

其实在Spring中的动态代理最终的执行使用的是责任链设计模式。大家可以自己看一下JDK动态代理的实现方式,最终是一样的。

在这里教大家一个看源码的小技巧,假设我们对CglibMethodInvocation类不了解,不知道它的执行方法是哪个怎么办呢?我们点到了配置方法没有看到运行。
可以这样做,随便找个要执行的方法,例如before里面的打印,打个断点,然后看断点下面的方法调用链就可以找到源码中正在执行的方法了。
在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值