Spring-AOP-基於注解的AOP通知執行順序
通知的選取規則
五大通知類型中,環繞通知功能最為強大,因為環繞通知,可以控制目標方法是否執行。
如果需要記錄異常信息,使用異常通知。
其他通知,只能做記錄工作,不能做處理,所以執行順序其實對整個程序影響不大,沒有必要太深究。
Spring版本不一樣,通知執行順序可能也會存在差異
下面以Spring4.0版本、Spring5.28版本進行測試
一、單個切面類
(1)@Before、@After、@AfterReturning、@AfterThrowing執行順序
①Spring4.0
正常情況:@Before=====目標方法=====@After=====@AfterReturning
異常情況:@Before=====目標方法=====@After=====@AfterThrowing
②Spring5.28
正常情況:@Before=====目標方法=====@AfterReturning=====@After
異常情況:@Before=====目標方法=====@AfterThrowing=====@After

@Service public class BookService { public int add(int i,int j) { int result=i+j; System.out.println("目標方法執行"); //System.out.println(1/0); return result; } } @Aspect @Component public class BookServiceProxy { @Pointcut(value = "execution(* com.orz.spring.aop.BookService.add(..))") public void myPointCut(){} @Before(value = "myPointCut()") public void before() { System.out.println("@Before"); } @After(value = "myPointCut()") public void after() { System.out.println("@After"); } @AfterReturning(value = "myPointCut()") public void afterReturning() { System.out.println("@AfterReturning"); } @AfterThrowing(value = "myPointCut()") public void afterThrowing() { System.out.println("@AfterThrowing"); } } @Test public void test2() { ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean2.xml"); BookService bookService = applicationContext.getBean("bookService", BookService.class); bookService.add(1,2); } Spring4.0 正常情況 @Before 目標方法執行 @After @AfterReturning 異常情況 @Before 目標方法執行 @After @AfterThrowing Spring5.28 正常情況 @Before 目標方法執行 @AfterReturning @After 異常情況 @Before 目標方法執行 @AfterThrowing @After
(2)@Around的執行順序
@Around(value = "myPointCut()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint) { Object[] args = proceedingJoinPoint.getArgs(); Object result=null; try { //前置通知@Before System.out.println("環繞前置通知"); //目標方法執行 result = proceedingJoinPoint.proceed(args); //環繞返回通知@AfterReturning System.out.println("環繞返回通知"); } catch (Throwable throwable) { //環繞異常通知@AfterThrowing System.out.println("環繞異常通知"); throw new RuntimeException(throwable); } finally { //最終通知@After System.out.println("環繞最終通知"); } return result; }
①Spring4.0
正常情況:環繞前置=====目標方法執行=====環繞返回=====環繞最終
異常情況:環繞前置=====目標方法執行=====環繞異常=====環繞最終
②Spring5.28
正常情況:環繞前置=====目標方法執行=====環繞返回=====環繞最終
異常情況:環繞前置=====目標方法執行=====環繞異常=====環繞最終

@Service public class BookService { public int add(int i,int j) { int result=i+j; System.out.println("目標方法執行"); return result; } } @Aspect @Component public class BookServiceProxy { @Pointcut(value = "execution(* com.orz.spring.aop.BookService.add(..))") public void myPointCut(){} @Around(value = "myPointCut()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint) { Object[] args = proceedingJoinPoint.getArgs(); Object result=null; try { //前置通知@Before System.out.println("環繞前置通知"); //目標方法執行 result = proceedingJoinPoint.proceed(args); //環繞返回通知@AfterReturning System.out.println("環繞返回通知"); } catch (Throwable throwable) { //環繞異常通知@AfterThrowing System.out.println("環繞異常通知"); throw new RuntimeException(throwable); } finally { //最終通知@After System.out.println("環繞最終通知"); } return result; } } @Test public void test2() { ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean2.xml"); BookService bookService = applicationContext.getBean("bookService", BookService.class); bookService.add(1,2); } Spring4.0 環繞前置通知 目標方法執行 環繞返回通知 環繞最終通知 異常情況 環繞前置通知 目標方法執行 環繞異常通知 環繞最終通知 Spring5.28 正常情況 環繞前置通知 目標方法執行 環繞返回通知 環繞最終通知 異常情況 環繞前置通知 目標方法執行 環繞異常通知 環繞最終通知
(3)五大通知執行順序
①Spring4.0
正常情況:環繞前置=====@Before======目標方法執行=====環繞返回=====環繞最終=====@After=====@AfterReturning
異常情況:環繞前置=====@Before======目標方法執行=====環繞異常=====環繞最終=====@After=====@AfterThrowing
②Spring5.28
正常情況:環繞前置=====@Before=====目標方法執行=====@AfterReturning=====@After=====環繞返回=====環繞最終
異常情況:環繞前置=====@Before=====目標方法執行=====@AfterThrowing=====@After=====環繞異常=====環繞最終

@Service public class BookService { public int add(int i,int j) { int result=i+j; System.out.println("目標方法執行"); //System.out.println(1/0); return result; } } @Aspect @Component public class BookServiceProxy { @Pointcut(value = "execution(* com.orz.spring.aop.BookService.add(..))") public void myPointCut(){} @Before(value = "myPointCut()") public void before() { System.out.println("@Before"); } @After(value = "myPointCut()") public void after() { System.out.println("@After"); } @AfterReturning(value = "myPointCut()") public void afterReturning() { System.out.println("@AfterReturning"); } @AfterThrowing(value = "myPointCut()") public void afterThrowing() { System.out.println("@AfterThrowing"); } @Around(value = "myPointCut()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint) { Object[] args = proceedingJoinPoint.getArgs(); Object result=null; try { //前置通知@Before System.out.println("環繞前置通知"); //目標方法執行 result = proceedingJoinPoint.proceed(args); //環繞返回通知@AfterReturning System.out.println("環繞返回通知"); } catch (Throwable throwable) { //環繞異常通知@AfterThrowing System.out.println("環繞異常通知"); throw new RuntimeException(throwable); } finally { //最終通知@After System.out.println("環繞最終通知"); } return result; } } @Test public void test2() { ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean2.xml"); BookService bookService = applicationContext.getBean("bookService", BookService.class); bookService.add(1,2); } Spring4.0 正常情況 環繞前置通知 @Before 目標方法執行 環繞返回通知 環繞最終通知 @After @AfterReturning 異常情況 環繞前置通知 @Before 目標方法執行 環繞異常通知 環繞最終通知 @After @AfterThrowing Spring5.28 正常情況 環繞前置通知 @Before 目標方法執行 @AfterReturning @After 環繞返回通知 環繞最終通知 異常情況 環繞前置通知 @Before 目標方法執行 @AfterThrowing @After 環繞異常通知 環繞最終通知
二、多個切面
①Spring4.0
正常情況:切面1環繞前置===切面1@Before===切面2環繞前置===切面2@Before===目標方法執行===切面2環繞返回===切面2環繞最終===切面2@After===切面2@AfterReturning===切面1環繞返回===切面1環繞最終===切面1@After===切面1@AfterThrowing
異常情況:切面1環繞前置===切面1@Before===切面2環繞前置===切面2@Before===目標方法執行===切面2環繞異常===切面2環繞最終===切面2@After===切面2@AfteThrowing===切面1環繞異常===切面1環繞最終===切面1@After===切面1@AfterThrowing
②Spring5.28
正常情況:切面1環繞前置===切面1@Before===切面2環繞前置===切面2@Before===目標方法執行===切面2@AfterReturning===切面2@After===切面2環繞返回===切面2環繞最終===切面1@AfterReturning===切面1@After===切面1環繞返回===切面1環繞最終
異常情況:切面1環繞前置===切面1@Before===切面2環繞前置===切面2@Before===目標方法執行===切面2@AfterThrowing===切面2@After===切面2環繞異常===切面2環繞最終===切面1@AfterThrowing===切面1@After===切面1環繞異常===切面1環繞最終

@Service public class BookService { public int add(int i,int j) { int result=i+j; System.out.println("目標方法執行"); //System.out.println(1/0); return result; } } @Aspect @Component public class BookServiceProxy { @Pointcut(value = "execution(* com.orz.spring.aop.BookService.add(..))") public void myPointCut(){} @Before(value = "myPointCut()") public void before() { System.out.println("切面一:@Before"); } @After(value = "myPointCut()") public void after() { System.out.println("切面一:@After"); } @AfterReturning(value = "myPointCut()") public void afterReturning() { System.out.println("切面一:@AfterReturning"); } @AfterThrowing(value = "myPointCut()") public void afterThrowing() { System.out.println("切面一:@AfterThrowing"); } @Around(value = "myPointCut()") public Object myAround(ProceedingJoinPoint proceedingJoinPoint) { Object[] args = proceedingJoinPoint.getArgs(); Object result=null; try { //前置通知@Before System.out.println("切面一:環繞前置通知"); //目標方法執行 result = proceedingJoinPoint.proceed(args); //環繞返回通知@AfterReturning System.out.println("切面一:環繞返回通知"); } catch (Throwable throwable) { //環繞異常通知@AfterThrowing System.out.println("切面一:環繞異常通知"); throw new RuntimeException(throwable); } finally { //最終通知@After System.out.println("切面一:環繞最終通知"); } return result; } } @Test public void test2() { ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean2.xml"); BookService bookService = applicationContext.getBean("bookService", BookService.class); bookService.add(1,2); } Spring4.0 正常情況 切面一:環繞前置通知 切面一:@Before 切面二:環繞前置通知 切面二:@Before 目標方法執行 切面二:環繞返回通知 切面二:環繞最終通知 切面二:@After 切面二:@AfterReturning 切面一:環繞返回通知 切面一:環繞最終通知 切面一:@After 切面一:@AfterReturning 異常情況 切面一:環繞前置通知 切面一:@Before 切面二:環繞前置通知 切面二:@Before 目標方法執行 切面二:環繞異常通知 切面二:環繞最終通知 切面二:@After 切面二:@AfterThrowing 切面一:環繞異常通知 切面一:環繞最終通知 切面一:@After 切面一:@AfterThrowing Spring5.28 正常情況 切面一:環繞前置通知 切面一:@Before 切面二:環繞前置通知 切面二:@Before 目標方法執行 切面二:@AfterReturning 切面二:@After 切面二:環繞返回通知 切面二:環繞最終通知 切面一:@AfterReturning 切面一:@After 切面一:環繞返回通知 切面一:環繞最終通知 異常情況 切面一:環繞前置通知 切面一:@Before 切面二:環繞前置通知 切面二:@Before 目標方法執行 切面二:@AfterThrowing 切面二:@After 切面二:環繞異常通知 切面二:環繞最終通知 切面一:@AfterThrowing 切面一:@After 切面一:環繞異常通知 切面一:環繞最終通知
三、可以使用@Order注解指定先后順序,數字越小,優先級越高,先進后出
可以使用@Order注解指定先后順序,數字越小,優先級越高,先進后出 @Order(value = 1) @Aspect @Component public class BookServiceProxy {} @Order(value = 0) @Aspect @Component public class BookServiceProxy2 {} 切面二:環繞前置通知 切面二:@Before 切面一:環繞前置通知 切面一:@Before 目標方法執行 切面一:@AfterReturning 切面一:@After 切面一:環繞返回通知 切面一:環繞最終通知 切面二:@AfterReturning 切面二:@After 切面二:環繞返回通知 切面二:環繞最終通知