Spring AOP Advice的顺序问题

Advice优先级与执行顺序的关系

当多个Advice作用于同一个JoinPoint的时候,他们的顺序是怎样的?在这个问题上,SpringAOP的优先级规则与AspectJ是相同的。优先级最高的在进入时先执行,但是在出去时最后执行。示例如下:

在调用被代理的方法时(进入时),优先级最高的Advice1会先被执行,紧接着是Advice2和Advice3。在从被代理的方法返回时,优先级最低的Advice3会被先执行,紧接着是Advice2和Advice1。
举几个例子:
如果Advice1、Advice2和Advice3都是BeforeAdvice,那么增强逻辑都是在proxied method执行前执行,那么Advice1、Advice2和Advice3按照优先级顺序执行。优先级最高的Advice1会先被执行,紧接着是Advice2和Advice3。
如果Advice1、Advice2和Advice3都是AfterAdice,那么增强逻辑都是在proxied method执行后执行,优先级最低的Advice3会先被执行,紧接着是Advice2和Advice1。
如果Advice1、Advice2和Advice3都是AroudAdvice,那么在proxied method执行前后都会有增强逻辑,其执行顺序是:Advice1的前部增强逻辑->Advice2的前部增强逻辑->Advice3的前部增强逻辑->proxied method ->Advice3的前部增强逻辑->Advice2的前部增强逻辑->Advice1的前部增强逻辑。

如何指定Advice优先级

Advice的优先级通过Aspect指定。切面类可以实现org.springframework.core.Ordered接口或者使用@Order注解来指定优先级。Order越低,优先级越高。位于不同的Aspect当中的Advice可以通过这种方式指定优先级。那么位于同一个Aspect内的Adivce的顺序呢?
位于同一个Aspect内的Adivce的顺序按照如下规则:
@Around->@Before->@After->@AfterReturning->@AfterThrowing
即AroudAdivce优先级最高,AfterThrowing优先级最低。

如果不同类型的Advice作用于同一个JoinPoint上,且这些Advice在同一个Aspect内,他们的执行顺序会是怎样的?比如这样的一个代码片段:

@Aspect
@Component
public class SimpleAspect {


    @Before(value = "execution(* com.lspring.beans..*.doSomething(..)) ")
    public void before() {

        System.out.println("before....");
    }

    @After(value = "execution(* com.lspring.beans..*.doSomething(..)) ")
    public void after() {

        System.out.println("after....");
    }


    @AfterReturning(value = "execution(* com.lspring.beans..*.doSomething(..)) ")
    public void afterRet() {

        System.out.println("after return....");
    }

    @AfterThrowing(value = "execution(* com.lspring.beans..*.doSomething(..)) ")
    public void afterThrow() {

        System.out.println("after throwing....");
    }



    @Around(value = "execution(* com.lspring.beans..*.doSomething(..))")
    public void doMonitor(ProceedingJoinPoint jp) {

        System.out.println("Around before...");
        try {
            Object proceed = jp.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("Around after...");

    }
}

执行结果:

Around before...
before....
do something,name=10,age=18
after return....
after....
Around after...

JdkDynamicAopProxy产生的拦截器链如下:

  1. ExposeInvocationInterceptor
  2. AspectJAroundAdvice
  3. MethodBeforeAdviceInterceptor
  4. AspectJAfterAdvice
  5. AfterReturningAdviceInterceptor
  6. AspectJAfterThrowingAdvice

运行截图:
image.png
与执行结果相符。可以看出其执行顺序遵循如下顺序:

    //around before
    //@Before()
       try {           
           try {
               Object retVal = method.proceed();
              // @AfterReturning
               return retVal;
           }catch (Exception e){
               //@AfterThrowing
           }
           
       }finally {
          // @After
       }
   // around after

将代码稍作修改:

@Aspect
@Component
public class AnotherAspect {


    @After(value = "execution(* com.lspring.beans..*.doSomething(..)) ")
    public void after() {

        System.out.println("after....");
    }


    @AfterReturning(value = "execution(* com.lspring.beans..*.doSomething(..)) ")
    public void afterRet() {

        System.out.println("after return....");
    }

    @AfterThrowing(value = "execution(* com.lspring.beans..*.doSomething(..)) ")
    public void afterThrow() {

        System.out.println("after throwing....");
    }
}

@Aspect
@Component
public class SimpleAspect {


    @Before(value = "execution(* com.lspring.beans..*.doSomething(..)) ")
    public void before() {

        System.out.println("before....");
    }

    @Around(value = "execution(* com.lspring.beans..*.doSomething(java.lang.String,java.lang.Integer))")
    public void doMonitor(ProceedingJoinPoint jp) {

        System.out.println("Around before...");

        //System.out.println("age=" + a);
        try {
            Object proceed = jp.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("Around after...");

    }
}

获得的执行结果如下:

Around before...
before....
do something,name=10,age=18
Around after...
after return....
after....

JdkDynamicAopProxy产生的拦截器链如下:

  1. ExposeInvocationInterceptor
  2. AspectJAfterAdvice
  3. AfterReturningAdviceInterceptor
  4. AspectJAfterThrowingAdvice
  5. AspectJAroundAdvice
  6. MethodBeforeAdviceInterceptor

与执行结果相符。

posted @ 2023-01-31 15:16  小张同学哈  阅读(307)  评论(0)    收藏  举报