读懂Spring AOP中通知的执行原理

读懂Spring AOP中通知的执行原理

  • 前言
  • 定义一个切面
  • 执行结果
  • 图解通知的执行流程
    • 将图片中的代码归纳在一起

前言

这个代理类是AOP基于JDK动态代理生成的,当使用代理类调用目标方法时,会执行到org.springframework.aop.framework.JdkDynamicAopProxy#invoke方法中去,后面的调用链也在这里面。

定义一个切面

切面包含了环绕通知(前)、前置通知、增强方法、环绕通知(后、后置通知、带返回值后置通知、异常通知

/**
 * 增强计算器的切面
 */
@Component
@Aspect
public class JisuanqiAspect {

    //AOP功能==》引入方式的使用

  /*  @DeclareParents(value = "yuanma.leiqiang.aop.JiSuanQiImpl",
            defaultImpl = YinruImpl.class
    )
    public static Yinru yinru;*/



    //各种通知的使用↓
    @Pointcut("execution(* com.redis.aop..*(..))")
    public void pointCut() {}

    @Before(value = "pointCut()")
    public void before(JoinPoint joinPoint) throws Exception{
        String name = joinPoint.getSignature().getName();
        System.out.println("Before增强了方法"+ name);

    }

    @After(value = "pointCut()")
    public void after(JoinPoint joinPoint) throws Exception{
        String name = joinPoint.getSignature().getName();
        System.out.println("无返回值After增强了方法"+ name);

    }

    @AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) throws Exception{
        String name = joinPoint.getSignature().getName();
        System.out.println("带返回值After增强了方法"+ name + "结果为"+result);

    }

    @AfterThrowing(value = "pointCut()")
    public void afterThrowing(JoinPoint joinPoint) throws Exception{
        String name = joinPoint.getSignature().getName();
        System.out.println("方法出现了异常"+ name);

    }

    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        String name = pjp.getSignature().getName();
        System.out.println("环绕通知=>方法执行前"+ name);

        Object object = pjp.proceed(pjp.getArgs());//执行我们的方法

        System.out.println("环绕通知=>方法执行后"+ name);
        return object;
    }
}

执行结果

读懂Spring AOP中通知的执行原理_第1张图片
上图中有3张图,上面2张为控制台打印的AOP各种类型通知的执行顺序
上两图介绍
图1为执行了异常通知的打印结果:环绕通知(前)→前置通知→增强方法→后置通知→异常通知
图2为正常的结果:环绕通知(前)→前置通知→增强方法→环绕通知(后)→后置通知→带返回值后置通知
可以看出当出现异常后,那种通知是不会被执行的
第三张图
这个图为AOP生成代理类后,使用代理类调用目标方法时执行通知的集合,就是chain集合中的通知会被递归调用,这些方法中看名字就知道是AOP对各个通知方法的调用;

图解通知的执行流程

读懂Spring AOP中通知的执行原理_第2张图片

将图片中的代码归纳在一起


    public static void main(String[] args) {
        MethodInvocation oldInvocation = invocation.get();
        invocation.set(mi);
        try {
            //ExposeInvocationInterceptor.invoke AOP内置的一个通知,可以不用看


            try {
                //AspectJAfterThrowingAdvice.invoke 这是异常通知,可以看就是一个try/catch,也就是将后面的执行逻辑全部包含,所以异常通知能捕获异常呢

                Object retVal;
                //AfterReturningAdviceInterceptor.invoke 带返回值的后置通知,可以看到这里它定义了返回值接收参数

                try {
                    //AspectJAfterAdvice.invoke 无返回值的后置通知,可以看得出,为啥就算目标方法异常了,后置通知还是会执行,因为后置通知的调用在finally中

                    String name = pjp.getSignature().getName();
                    System.out.println("环绕通知=>方法执行前" + name);
                    //执行环绕通知,这里环绕通知会跳转到自己定义的方法中去执行proceed()这个递归方法,在其他的通知类型中proceed()这个方法都是由AOP去执行的,在环绕通知中,是需要我们自己去执行

                    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
                    //执行前置通知MethodBeforeAdviceInterceptor.invoke 继续递归

                    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                        return invokeJoinpoint();
                    }
                    //最终执行连接点,就我们的目标方法ReflectiveMethodInvocation.proceed

                    //最终执行连接点,就我们的目标方
                    //执行前置通知

                    //执行环绕通知,这里环绕通知会跳转到自己定义的方法中去执行
                    System.out.println("环绕通知=>方法执行后" + name);

                    //AspectJAfterAdvice.invoke
                } finally {
                    invokeAdviceMethod(getJoinPointMatch(), null, null);
                }

                //AfterReturningAdviceInterceptor.invoke
                this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
                return retVal;

                //AspectJAfterThrowingAdvice.invoke
            } catch (Throwable ex) {
                if (shouldInvokeOnThrowing(ex)) {
                    invokeAdviceMethod(getJoinPointMatch(), null, ex);
                }
                throw ex;
            }


            //ExposeInvocationInterceptor.invoke AOP内置的一个通知
        } finally {
            invocation.set(oldInvocation);
        }
    }
    

你可能感兴趣的:(Spring,spring,java)