> 文档中心 > Spring AOP中的责任链设计模式

Spring AOP中的责任链设计模式

文章目录

  • 前言
  • 一、示例代码
  • 二、DynamicAdvisedInterceptor
  • 三、ReflectiveMethodInvocation

前言

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

一、示例代码

@Aspect@Componentpublic 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@Nullablepublic 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 {//最终断点走了elsereturn ((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里面的打印,打个断点,然后看断点下面的方法调用链就可以找到源码中正在执行的方法了。
在这里插入图片描述