最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

聊聊Spring AOP @Before @Around @After等advice的執(zhí)行順序

 更新時間:2021年02月19日 12:01:31   作者:rainbow702  
這篇文章主要介紹了聊聊Spring AOP @Before @Around @After等advice的執(zhí)行順序,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

用過spring框架進行開發(fā)的人,多多少少會使用過它的AOP功能,都知道有@Before、@Around和@After等advice。

最近,為了實現項目中的輸出日志和權限控制這兩個需求,我也使用到了AOP功能。

我使用到了@Before、@Around這兩個advice。但在,使用過程中,卻對它們的執(zhí)行順序并不清楚。

為了弄清楚在不同情況下,這些advice到底是以怎么樣的一個順序進行執(zhí)行的,我作了個測試,在此將其記錄下來,以供以后查看。

前提

對于AOP相關類(aspect、pointcut等)的概念,本文不作說明。

對于如何讓spring框架掃描到AOP,本文也不作說明。

情況一: 一個方法只被一個Aspect類攔截

當一個方法只被一個Aspect攔截時,這個Aspect中的不同advice是按照怎樣的順序進行執(zhí)行的呢?請看:

添加 PointCut類

該pointcut用來攔截test包下的所有類中的所有方法。

package test;
import org.aspectj.lang.annotation.Pointcut;
public class PointCuts {
 @Pointcut(value = "within(test.*)")
 public void aopDemo() {
 }
}

添加Aspect類

該類中的advice將會用到上面的pointcut,使用方法請看各個advice的value屬性。

package test;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class Aspect1 {
 @Before(value = "test.PointCuts.aopDemo()")
 public void before(JoinPoint joinPoint) {
  System.out.println("[Aspect1] before advise");
 }
 @Around(value = "test.PointCuts.aopDemo()")
 public void around(ProceedingJoinPoint pjp) throws Throwable{
  System.out.println("[Aspect1] around advise 1");
  pjp.proceed();
  System.out.println("[Aspect1] around advise2");
 }
 @AfterReturning(value = "test.PointCuts.aopDemo()")
 public void afterReturning(JoinPoint joinPoint) {
  System.out.println("[Aspect1] afterReturning advise");
 }
 @AfterThrowing(value = "test.PointCuts.aopDemo()")
 public void afterThrowing(JoinPoint joinPoint) {
  System.out.println("[Aspect1] afterThrowing advise");
 }
 @After(value = "test.PointCuts.aopDemo()")
 public void after(JoinPoint joinPoint) {
  System.out.println("[Aspect1] after advise");
 }
}

添加測試用Controller

添加一個用于測試的controller,這個controller中只有一個方法,但是它會根據參數值的不同,會作出不同的處理:一種是正常返回一個對象,一種是拋出異常(因為我們要測試@AfterThrowing這個advice)

package test;
import test.exception.TestException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/aop")
public class AopTestController {
 @ResponseStatus(HttpStatus.OK)
 @RequestMapping(value = "/test", method = RequestMethod.GET)
 public Result test(@RequestParam boolean throwException) {
  // case 1
  if (throwException) {
   System.out.println("throw an exception");
   throw new TestException("mock a server exception");
  }
  // case 2
  System.out.println("test OK");
  return new Result() {{
   this.setId(111);
   this.setName("mock a Result");
  }};
 }
 public static class Result {
  private int id;
  private String name;
  public int getId() {
   return id;
  }
  public void setId(int id) {
   this.id = id;
  }
  public String getName() {
   return name;
  }
  public void setName(String name) {
   this.name = name;
  }
 }
}

測試 正常情況

在瀏覽器直接輸入以下的URL,回車:

http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false

我們會看到輸出的結果是:

[Aspect1] around advise 1
[Aspect1] before advise
test OK
[Aspect1] around advise2
[Aspect1] after advise
[Aspect1] afterReturning advise

測試 異常情況

在瀏覽器中直接輸入以下的URL,回車:

http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true

我們會看到輸出的結果是:

[Aspect1] around advise 1
[Aspect1] before advise
throw an exception
[Aspect1] after advise
[Aspect1] afterThrowing advise

結論

在一個方法只被一個aspect類攔截時,aspect類內部的 advice 將按照以下的順序進行執(zhí)行:

正常情況:

異常情況:

情況二: 同一個方法被多個Aspect類攔截

此處舉例為被兩個aspect類攔截。

有些情況下,對于兩個不同的aspect類,不管它們的advice使用的是同一個pointcut,還是不同的pointcut,都有可能導致同一個方法被多個aspect類攔截。那么,在這種情況下,這多個Aspect類中的advice又是按照怎樣的順序進行執(zhí)行的呢?請看:

pointcut類保持不變

添加一個新的aspect類

package test;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class Aspect2 {
 @Before(value = "test.PointCuts.aopDemo()")
 public void before(JoinPoint joinPoint) {
  System.out.println("[Aspect2] before advise");
 }
 @Around(value = "test.PointCuts.aopDemo()")
 public void around(ProceedingJoinPoint pjp) throws Throwable{
  System.out.println("[Aspect2] around advise 1");
  pjp.proceed();
  System.out.println("[Aspect2] around advise2");
 }
 @AfterReturning(value = "test.PointCuts.aopDemo()")
 public void afterReturning(JoinPoint joinPoint) {
  System.out.println("[Aspect2] afterReturning advise");
 }
 @AfterThrowing(value = "test.PointCuts.aopDemo()")
 public void afterThrowing(JoinPoint joinPoint) {
  System.out.println("[Aspect2] afterThrowing advise");
 }
 @After(value = "test.PointCuts.aopDemo()")
 public void after(JoinPoint joinPoint) {
  System.out.println("[Aspect2] after advise");
 }
}

測試用Controller也不變

還是使用上面的那個Controller。但是現在 aspect1 和 aspect2 都會攔截該controller中的方法。

下面繼續(xù)進行測試!

測試 正常情況

在瀏覽器直接輸入以下的URL,回車:

http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false

我們會看到輸出的結果是:

[Aspect2] around advise 1
[Aspect2] before advise
[Aspect1] around advise 1
[Aspect1] before advise
test OK
[Aspect1] around advise2
[Aspect1] after advise
[Aspect1] afterReturning advise
[Aspect2] around advise2
[Aspect2] after advise
[Aspect2] afterReturning advise

但是這個時候,我不能下定論說 aspect2 肯定就比 aspect1 先執(zhí)行。

不信?你把服務務器重新啟動一下,再試試,說不定你就會看到如下的執(zhí)行結果:

[Aspect1] around advise 1
[Aspect1] before advise
[Aspect2] around advise 1
[Aspect2] before advise
test OK
[Aspect2] around advise2
[Aspect2] after advise
[Aspect2] afterReturning advise
[Aspect1] around advise2
[Aspect1] after advise
[Aspect1] afterReturning advise

也就是說,這種情況下, aspect1 和 aspect2 的執(zhí)行順序是未知的。那怎么解決呢?不急,下面會給出解決方案。

測試 異常情況

在瀏覽器中直接輸入以下的URL,回車:

http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true

我們會看到輸出的結果是:

[Aspect2] around advise 1
[Aspect2] before advise
[Aspect1] around advise 1
[Aspect1] before advise
throw an exception
[Aspect1] after advise
[Aspect1] afterThrowing advise
[Aspect2] after advise
[Aspect2] afterThrowing advise

同樣地,如果把服務器重啟,然后再測試的話,就可能會看到如下的結果:

[Aspect1] around advise 1
[Aspect1] before advise
[Aspect2] around advise 1
[Aspect2] before advise
throw an exception
[Aspect2] after advise
[Aspect2] afterThrowing advise
[Aspect1] after advise
[Aspect1] afterThrowing advise

也就是說,同樣地,異常情況下, aspect1 和 aspect2 的執(zhí)行順序也是未定的。

那么在 情況二 下,如何指定每個 aspect 的執(zhí)行順序呢?

方法有兩種:

實現org.springframework.core.Ordered接口,實現它的getOrder()方法

給aspect添加@Order注解,該注解全稱為:org.springframework.core.annotation.Order

不管采用上面的哪種方法,都是值越小的 aspect 越先執(zhí)行。

比如,我們?yōu)?apsect1 和 aspect2 分別添加 @Order 注解,如下:

@Order(5)
@Component
@Aspect
public class Aspect1 {
 // ...
}
@Order(6)
@Component
@Aspect
public class Aspect2 {
 // ...
}

這樣修改之后,可保證不管在任何情況下, aspect1 中的 advice 總是比 aspect2 中的 advice 先執(zhí)行。

如下圖所示:

注意點

如果在同一個 aspect 類中,針對同一個 pointcut,定義了兩個相同的 advice(比如,定義了兩個 @Before),那么這兩個 advice 的執(zhí)行順序是無法確定的,哪怕你給這兩個 advice 添加了 @Order 這個注解,也不行。這點切記。

對于@Around這個advice,不管它有沒有返回值,但是必須要方法內部,調用一下 pjp.proceed();否則,Controller 中的接口將沒有機會被執(zhí)行,從而也導致了 @Before這個advice不會被觸發(fā)。

比如,我們假設正常情況下,執(zhí)行順序為”aspect2 -> apsect1 -> controller”,如果,我們把 aspect1中的@Around中的 pjp.proceed();給刪掉,那么,我們看到的輸出結果將是:

[Aspect2] around advise 1
[Aspect2] before advise
[Aspect1] around advise 1
[Aspect1] around advise2
[Aspect1] after advise
[Aspect1] afterReturning advise
[Aspect2] around advise2
[Aspect2] after advise
[Aspect2] afterReturning advise

從結果可以發(fā)現, Controller 中的 接口 未被執(zhí)行,aspect1 中的 @Before advice 也未被執(zhí)行。

參考資料

Spring 4.3.2.RELEASE 官方資料:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/

其中,AOP的執(zhí)行順序章節(jié)為:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#aop-ataspectj-advice-ordering

Advice ordering

What happens when multiple pieces of advice all want to run at the same join point?

Spring AOP follows the same precedence rules as AspectJ to determine the order of advice execution.

The highest precedence advice runs first "on the way in" (so given two pieces of before advice, the one with highest precedence runs first).

"On the way out" from a join point, the highest precedence advice runs last (so given two pieces of after advice, the one with the highest precedence will run second).

When two pieces of advice defined in different aspects both need to run at the same join point, unless you specify otherwise the order of execution is undefined.

You can control the order of execution by specifying precedence.

This is done in the normal Spring way by either implementing the org.springframework.core.Ordered interface in the aspect class or annotating it with the Order annotation.

Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.

When two pieces of advice defined in the same aspect both need to run at the same join point, the ordering is undefined (since there is no way to retrieve the declaration order via reflection for javac-compiled classes).

Consider collapsing such advice methods into one advice method per join point in each aspect class, or refactor the pieces of advice into separate aspect classes - which can be ordered at the aspect level.

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。

相關文章

  • SpringBoot自定義Starter的教程指南

    SpringBoot自定義Starter的教程指南

    SpringBoot的Starter自動配置機制極大地簡化了依賴管理和應用配置,使得開發(fā)者可以以最少的配置快速啟動和運行Spring應用,有時,標準的Starter可能無法滿足特定需求,需要創(chuàng)建自定義Starter,所以本文給大家介紹了SpringBoot自定義Starter的教程指南
    2024-11-11
  • SpringAop中的Advice通知實例

    SpringAop中的Advice通知實例

    這篇文章主要介紹了SpringAop中的Advice通知詳解,Spring的AOP功能中一個關鍵概念是通知Advice與切點Pointcut表達式相關聯在特定節(jié)點織入一些邏輯,Spring提供了五種類型的通知,需要的朋友可以參考下
    2023-09-09
  • Java實現XML與JSON的互相轉換詳解

    Java實現XML與JSON的互相轉換詳解

    這篇文章主要為大家詳細介紹了如何使用Java實現XML與JSON的互相轉換,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-03-03
  • IDEA創(chuàng)建Java?Web項目的超詳細圖文教學

    IDEA創(chuàng)建Java?Web項目的超詳細圖文教學

    IDEA是程序員們常用的java集成開發(fā)環(huán)境,也是被公認為最好用的java開發(fā)工具,下面這篇文章主要給大家介紹了關于IDEA創(chuàng)建Java?Web項目的相關資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2022-12-12
  • SpringBoot下載文件的正確解法方式

    SpringBoot下載文件的正確解法方式

    這篇文章主要給大家介紹了關于SpringBoot下載文件的正確解法方式,SpringBoot是一款流行的框架,用于開發(fā)Web應用程序,在使用SpringBoot構建Web應用程序時,可能需要實現文件下載的功能,需要的朋友可以參考下
    2023-08-08
  • Java 網絡編程總結

    Java 網絡編程總結

    這篇文章主要給大家分享Java 網絡編程的一個總結,說到網絡編程肯定都會想到IP地址、端口、通信協(xié)議等一些必不可少的元素,下面來看看文章的詳細介紹吧
    2021-11-11
  • springboot參數傳中文亂碼的解決方案

    springboot參數傳中文亂碼的解決方案

    這篇文章主要介紹了springboot參數傳中文亂碼的解決方案,幫助大家更好的理解和學習使用springboot,感興趣的朋友可以了解下
    2021-03-03
  • Flowable中定時器的玩法詳解

    Flowable中定時器的玩法詳解

    這篇文章主要為大家詳細介紹了Flowable中定時器的各種玩法,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-11-11
  • spring事務的propagation傳播屬性示例詳解

    spring事務的propagation傳播屬性示例詳解

    這篇文章主要為大家介紹了spring事務的propagation傳播屬性示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • Spring中Bean掃描原理詳情

    Spring中Bean掃描原理詳情

    這篇文章主要介紹了Spring中Bean掃描原理詳情,文章為榮啊主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-07-07

最新評論

乌拉特前旗| 喜德县| 灵石县| 沛县| 宾川县| 荔浦县| 洛浦县| 栾城县| 开封县| 宜丰县| 治县。| 铜山县| 新余市| 固镇县| 肇州县| 江孜县| 邵东县| 栖霞市| 安国市| 岳阳市| 龙口市| 兴和县| 陆丰市| 丰宁| 扎鲁特旗| 吴堡县| 东辽县| 商都县| 郑州市| 磴口县| 九龙县| 丰台区| 三明市| 灵宝市| 铁岭市| 莱西市| 江口县| 吴旗县| 调兵山市| 当阳市| 澎湖县|