AOP切面执行顺序

  • Post author:
  • Post category:其他





一. 概述

  • 本文主要讲述以下几点

    1. 单AOP切面时,各通知方法的执行顺序。
    2. 多AOP切面时,多切面的执行顺序和各通知方法的执行顺序。



二. 讲述



1. 单切面中各通知方法的执行顺序


单切面中各通知方法执行顺序·总结

  • spring aop就是一个同心圆,以要执行的方法为圆心。从最外层按照依次执行切面的@Around方法,@Before方法。然后执行method方法,最后再依次执行@After、@AfterReturning方法。
  • 图示

  • 代码示例
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Aop1 {
}

@Component
@Aspect
@Slf4j
@Order(1)
public class Aop1Aspect {
    @Pointcut("@annotation(com.zijikanwa.ssmspringboottest.manager.aop.Aop1)")
    private void pointCutMethod() {
    }

    //声明前置通知
    @Before("pointCutMethod()")
    public void doBefore(JoinPoint point) {
        System.out.println("Aop1Aspect:doBefore");
        return;
    }

    //声明后置通知
    @AfterReturning(pointcut = "pointCutMethod()", returning = "returnValue")
    public void doAfterReturning(JoinPoint point, Object returnValue) {
        System.out.println("Aop1Aspect:doAfterReturning");
    }

    //声明例外通知
    @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")
    public void doAfterThrowing(Exception e) {
        System.out.println("Aop1Aspect:doAfterThrowing");
    }

    //声明最终通知
    @After("pointCutMethod()")
    public void doAfter() {
        System.out.println("Aop1Aspect:doAfter");
    }

    //声明环绕通知
    @Around("pointCutMethod()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Aop1Aspect:doAround1");
        Object obj = pjp.proceed();
        System.out.println("Aop1Aspect:doAround2");
        return obj;
    }
}

@Component
public class TEst {
    @Aop1
    public void testAop(){
        System.out.println("testAop");
    }
}

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { TestApplication.class })
@EnableAutoConfiguration
class SsmspringboottestApplicationTests {
	 @Test
	 public void test(){
	      tEst.testAop();
	  }
}
  • 执行结果
Aop1Aspect:doAround1
Aop1Aspect:doBefore
testAop
Aop1Aspect:doAround2
Aop1Aspect:doAfter
Aop1Aspect:doAfterReturning



2. 多切面中各通知方法的执行顺序


多切面各通知方法的执行顺序·总结

  1. 多切面的执行顺序:按照切面给定的order执行,order越小越先执行,但最先执行的最后结束。
  2. 多切面中各通知方法的执行顺序:与单切面类似。spring aop就是一个同心圆,以要执行的方法为圆心,最外层的order最小。从最外层按照AOP1、AOP2的顺序依次执行@Around方法,@Before方法。然后执行method方法,最后按照AOP2、AOP1的顺序依次执行@After、@AfterReturning方法。
  • 图示

  • 代码示例:在AOP1的基础上增加AOP2
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Aop2 {
}

@Component
@Aspect
@Slf4j
@Order(2)
public class Aop2Aspect {
    @Pointcut("@annotation(com.zijikanwa.ssmspringboottest.manager.aop.Aop2)")
    private void pointCutMethod() {
    }

    //声明前置通知
    @Before("pointCutMethod()")
    public void doBefore(JoinPoint point) {
        System.out.println("Aop2Aspect:doBefore");
        return;
    }

    //声明后置通知
    @AfterReturning(pointcut = "pointCutMethod()", returning = "returnValue")
    public void doAfterReturning(JoinPoint point, Object returnValue) {
        System.out.println("Aop2Aspect:doAfterReturning");
    }

    //声明例外通知
    @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")
    public void doAfterThrowing(Exception e) {
        System.out.println("Aop2Aspect:doAfterThrowing");
    }

    //声明最终通知
    @After("pointCutMethod()")
    public void doAfter() {
        System.out.println("Aop2Aspect:doAfter");
    }

    //声明环绕通知
    @Around("pointCutMethod()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Aop2Aspect:doAround1");
        Object obj = pjp.proceed();
        System.out.println("Aop2Aspect:doAround2");
        return obj;
    }
}

@Component
public class TEst {
    @Aop1
    @Aop2
    public void testAop(){
        System.out.println("testAop");
    }
}

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { TestApplication.class })
@EnableAutoConfiguration
class SsmspringboottestApplicationTests {
	 @Test
	 public void test(){
	      tEst.testAop();
	  }
}
  • 执行结果
Aop1Aspect:doAround1
Aop1Aspect:doBefore
Aop2Aspect:doAround1
Aop2Aspect:doBefore
testAop
Aop2Aspect:doAround2
Aop2Aspect:doAfter
Aop2Aspect:doAfterReturning
Aop1Aspect:doAround2
Aop1Aspect:doAfter
Aop1Aspect:doAfterReturning



3. 多切面的通知方法中抛出异常

  1. AOP1中

    @Around

    注解的方法抛出异常:执行@After和@AfterThrowing,然后抛出异常。
@Component
@Aspect
@Slf4j
@Order(1)
public class Aop1Aspect {
	@Around("pointCutMethod()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Aop1Aspect:doAround1");
        int i = 1 / 0; // java.lang.ArithmeticException: / by zero
        Object obj = pjp.proceed();
        System.out.println("Aop1Aspect:doAround2");
        return obj;
    }
}
  • 运行结果
Aop1Aspect:doAround1
Aop1Aspect:doAfter
Aop1Aspect:doAfterThrowing

java.lang.ArithmeticException: / by zero
  1. Method方法抛出异常:依次执行多个切面的@After和@AfterThrowing
@Component
public class TEst {
    @Aop1
    @Aop2
    public void testAop(){
        System.out.println("testAop"); // 可以执行到
        int i = 1 / 0; 
        System.out.println("testAop---"); //执行不到
    }
}
  • 执行结果
Aop1Aspect:doAround1
Aop1Aspect:doBefore
Aop2Aspect:doAround1
Aop2Aspect:doBefore
testAop
Aop2Aspect:doAfter
Aop2Aspect:doAfterThrowing
Aop1Aspect:doAfter
Aop1Aspect:doAfterThrowing

java.lang.ArithmeticException: / by zero
  1. AOP1中

    @After

    注解的方法抛出异常:执行@After抛出异常前的部分和@AfterThrowing,然后抛出异常。
@Component
@Aspect
@Slf4j
@Order(1)
public class Aop1Aspect {
	@After("pointCutMethod()")
    public void doAfter() {
        System.out.println("Aop1Aspect:doAfter"); // 可以执行到
        int i = 1 / 0; 
        System.out.println("Aop1Aspect:doAfter----");  //执行不到
    }
}
  • 执行结果
Aop1Aspect:doAround1
Aop1Aspect:doBefore
Aop2Aspect:doAround1
Aop2Aspect:doBefore
testAop
Aop2Aspect:doAround2
Aop2Aspect:doAfter
Aop2Aspect:doAfterReturning
Aop1Aspect:doAround2
Aop1Aspect:doAfter
Aop1Aspect:doAfterThrowing

java.lang.ArithmeticException: / by zero



参考资料



版权声明:本文为zijikanwa原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。