spring5.0源码解析 从源码角度分析 advice 的执行顺序 aop 05

从源码角度分析 advice 的执行顺序 aop

  • 从源码角度分析 advice 的执行顺序
    • 配置通知
    • 运行结果
    • 从源码角度分析
      • 第一个调用 ExposeInvocationInterceptor
      • 第二个调用 AspectJAroundAdvice
    • 第三个调用 MethodBeforeAdviceInterceptor
    • 第四个调用 MethodBeforeAdviceInterceptor
    • 第五个调用 AspectJAfterAdvice
    • 第六个调用 AfterReturningAdviceInterceptor
    • 第六个调用 AspectJAfterThrowingAdvice
    • 最后调用目标方法
    • 方法一次返回

从源码角度分析 advice 的执行顺序

advice 在执行行 不管是 Jdk 的 代理 还是 CGlib 的代理 ReflectiveMethodInvocation 的 proceed()方法去实现的,具体可以去都之前的本专栏的 前几篇 aop 文章,里面有 Aop 实现的整个流程

配置通知

@Aspect
@Component
public class TestAop {

		@Before("pointCut()")
	public void before(JoinPoint joinPoint)
	{
		Class clz = joinPoint.getTarget().getClass();
		Signature signature = joinPoint.getSignature();
		String name = signature.getName();
		System.out.println("========="+"前置通知:"+name+"===========");
	}
	@After("zclvct.spring.aop.TestAop.pointCut()")
	public void after(JoinPoint joinPoint)
	{
		Class clz = joinPoint.getTarget().getClass();
		String name = clz.getName();
		System.out.println("========="+"最终通知:"+name+"===========");
	}

	@Around("zclvct.spring.aop.TestAop.pointCut()")
	public void around(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("========="+"环绕前"+"===========");
		joinPoint.proceed();
		System.out.println("========="+"环绕后"+"===========");

	}

	@AfterThrowing("zclvct.spring.aop.TestAop.pointCut()")
	public void afterThrowing(JoinPoint joinPoint) throws Throwable {
		System.out.println("========="+"异常通知"+"===========");

	}
	@AfterReturning("zclvct.spring.aop.TestAop.pointCut()")
	public void afterReturning(JoinPoint joinPoint) throws Throwable {
		System.out.println("========="+"后置通知"+"===========");

	}
}

运行结果

=========环绕前===========
=========前置通知:test===========
我是userserviceTest01
=========最终通知===========
=========后置通知===========
=========环绕后===========

从源码角度分析

在刚进入 proceed 方法时,可以看到整个拦截器链
spring5.0源码解析 从源码角度分析 advice 的执行顺序 aop 05_第1张图片

第一个调用 ExposeInvocationInterceptor

他维护了 一个 ThreadLocal 对象 用于保存 MethodInvocation 的上下文,在后续的任何下调用链环节,只要需要用到当前的MethodInvocation就通过ExposeInvocationInterceptor.currentInvocation()静态方法获得。

private static final ThreadLocal<MethodInvocation> invocation =
			new NamedThreadLocal<>("Current AOP method invocation");
@Override
	@Nullable
	public Object invoke(MethodInvocation mi) throws Throwable {
	// 设置 线程 MethodInvocation 副本
		MethodInvocation oldInvocation = invocation.get();
		invocation.set(mi);
		try {
			//递归执行 proceed 方法
			return mi.proceed();
		}
		finally {
			invocation.set(oldInvocation);
		}
	}

第二个调用 AspectJAroundAdvice

第二个调用 AspectJAroundAdvice 的 invoke 方法 invoke 中调用 invokeAdviceMethodWithGivenArgs方法

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
		Object[] actualArgs = args;
		if (this.aspectJAdviceMethod.getParameterCount() == 0) {
			actualArgs = null;
		}
		try {
			ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
			//反射调用通知方法
			//this.aspectInstanceFactory.getAspectInstance()获取的是切面的实例
			return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
		}
		catch (IllegalArgumentException ex) {
			throw new AopInvocationException("Mismatch on arguments to advice method [" +
					this.aspectJAdviceMethod + "]; pointcut expression [" +
					this.pointcut.getPointcutExpression() + "]", ex);
		}
		catch (InvocationTargetException ex) {
			throw ex.getTargetException();
		}
	}

其实这个对象通过反射调用的方法其实是 我们之前调用的 TestAop 的 around 方法
ProceedingJoinPoint

@Around("zclvct.spring.aop.TestAop.pointCut()")
	public void around(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("========="+"环绕前"+"===========");
		joinPoint.proceed();
		System.out.println("========="+"环绕后"+"===========");

	}

此时 参数中的 joinPoint 是一个 MethodInvocationProceedingJoinPoint 实例
在这里插入图片描述
在 MethodInvocationProceedingJoinPoint 的 proceed 方法中可以看到
还是调用的 this.methodInvocation.invocableClone().proceed(); 方法继续递归

public Object proceed() throws Throwable {
		return this.methodInvocation.invocableClone().proceed();
	}

当然 此时 around 方法还没执行完成 只打印
=========环绕前===========

第三个调用 MethodBeforeAdviceInterceptor

这里很简单 调用 在递归前 before 方法 回调 继续递归执行

public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		return mi.proceed();
	}

第四个调用 MethodBeforeAdviceInterceptor

这里很简单 调用 在递归前 before 方法 回调 继续递归执行

public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		return mi.proceed();
	}

第五个调用 AspectJAfterAdvice

先递归调用 之后 finally 执行 最终通知

try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}

第六个调用 AfterReturningAdviceInterceptor

先递归 再调用

public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}

第六个调用 AspectJAfterThrowingAdvice

这里 利用 catch 捕获到 异常 在发生异常时执行 同时 将异常 抛出,防止异常被吃掉

try {
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}

最后调用目标方法

// 我们从指数-1开始,并提前递增。 递归调用 所有拦截器链中的 Matcher 的 advice
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			// 运行目标对象的方法  也就是反射调用的指定目标
			return invokeJoinpoint();
		}

方法一次返回

-* AspectJAfterThrowingAdvice 检查异常

  • AfterReturningAdviceInterceptor 如果发生异常不执行
  • AspectJAfterAdvice 最终通知 finally 中运行 一定会执行
  • MethodBeforeAdviceInterceptor 第一次调用已经执行完
  • AspectJAroundAdvice 环绕通知 发生异常不执行,没有异常继续执行
  • ExposeInvocationInterceptor 重新设置 threadLocal变量

你可能感兴趣的:(spring源码解析,java,spring)