文章目录
- 一. 概述
- 二. 讲述
- 1. 单切面中各通知方法的执行顺序
- 2. 多切面中各通知方法的执行顺序
- 3. 多切面的通知方法中抛出异常
- 参考资料
一. 概述
- 本文主要讲述以下几点
- 单AOP切面时,各通知方法的执行顺序。
- 多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 {@Aop1public void testAop(){System.out.println("testAop");}
}@RunWith(SpringRunner.class)
@SpringBootTest(classes = { TestApplication.class })
@EnableAutoConfiguration
class SsmspringboottestApplicationTests {@Testpublic void test(){tEst.testAop();}
}
- 执行结果
Aop1Aspect:doAround1
Aop1Aspect:doBefore
testAop
Aop1Aspect:doAround2
Aop1Aspect:doAfter
Aop1Aspect:doAfterReturning
2. 多切面中各通知方法的执行顺序
多切面各通知方法的执行顺序·总结
- 多切面的执行顺序:按照切面给定的order执行,order越小越先执行,但最先执行的最后结束。
- 多切面中各通知方法的执行顺序:与单切面类似。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@Aop2public void testAop(){System.out.println("testAop");}
}@RunWith(SpringRunner.class)
@SpringBootTest(classes = { TestApplication.class })
@EnableAutoConfiguration
class SsmspringboottestApplicationTests {@Testpublic 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. 多切面的通知方法中抛出异常
- 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 zeroObject obj = pjp.proceed();System.out.println("Aop1Aspect:doAround2");return obj;}
}
- 运行结果
Aop1Aspect:doAround1
Aop1Aspect:doAfter
Aop1Aspect:doAfterThrowingjava.lang.ArithmeticException: / by zero
- Method方法抛出异常:依次执行多个切面的@After和@AfterThrowing
@Component
public class TEst {@Aop1@Aop2public 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:doAfterThrowingjava.lang.ArithmeticException: / by zero
- 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:doAfterThrowingjava.lang.ArithmeticException: / by zero
参考资料
- spring多个AOP执行先后顺序(面试问题:怎么控制多个aop的执行循序)
- SpringAOP多切面的执行顺序
- spring多个AOP执行先后顺序