成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

你真的確定Spring AOP的執(zhí)行順序嗎

開(kāi)發(fā) 前端
公司新項(xiàng)目需要搭建一個(gè)新的前后分離HTTP服務(wù),我選擇了目前比較熟悉的SpringBoot Web來(lái)快速搭建一個(gè)可用的系統(tǒng)。

 [[346655]]

前言

公司這兩個(gè)月啟動(dòng)了全新的項(xiàng)目,項(xiàng)目排期滿滿當(dāng)當(dāng),不過(guò)該學(xué)習(xí)還是要學(xué)習(xí)。這不,給公司搭項(xiàng)目的時(shí)候,。

本文內(nèi)容重點(diǎn):

  • 問(wèn)題描述
  • Spring AOP執(zhí)行順序
  • 探究順序錯(cuò)誤的真相
  • 代碼驗(yàn)證
  • 結(jié)論

問(wèn)題描述

公司新項(xiàng)目需要搭建一個(gè)新的前后分離HTTP服務(wù),我選擇了目前比較熟悉的SpringBoot Web來(lái)快速搭建一個(gè)可用的系統(tǒng)。

魯迅說(shuō)過(guò),不要隨便升級(jí)已經(jīng)穩(wěn)定使用的版本。我偏不信這個(gè)邪,仗著自己用了這么久Spring,怎么能不沖呢。不說(shuō)了,直接引入了最新的SprinBoot 2.3.4.RELEASE版本,開(kāi)始給項(xiàng)目搭架子。

起初,大多數(shù)的組件引入都一切順利,本以為就要大功告成了,沒(méi)想到在搭建日志切面時(shí)栽了跟頭。

作為一個(gè)接口服務(wù),為了方便查詢接口調(diào)用情況和定位問(wèn)題,一般都會(huì)將請(qǐng)求日志打印出來(lái),而Spring的AOP作為切面支持,完美的切合了日志記錄的需求。

之前的項(xiàng)目中,運(yùn)行正確的切面日志記錄效果如下圖:

 

可以看到圖內(nèi)的一次方法調(diào)用,會(huì)輸出請(qǐng)求url,出入?yún)ⅲ约罢?qǐng)求IP等等,之前為了好看,還加入了分割線。

我把這個(gè)實(shí)現(xiàn)類放入新項(xiàng)目中,執(zhí)行出來(lái)卻是這樣的:

 

我揉了揉眼睛,仔細(xì)看了看復(fù)制過(guò)來(lái)的老代碼,精簡(jiǎn)版如下:

  1. /** 
  2.  * 在切點(diǎn)之前織入 
  3.  * @param joinPoint 
  4.  * @throws Throwable 
  5.  */ 
  6. @Before("webLog()"
  7. public void doBefore(JoinPoint joinPoint) throws Throwable { 
  8.     // 開(kāi)始打印請(qǐng)求日志 
  9.     ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 
  10.     HttpServletRequest request = attributes.getRequest(); 
  11.  
  12.     // 初始化traceId 
  13.     initTraceId(request); 
  14.  
  15.     // 打印請(qǐng)求相關(guān)參數(shù) 
  16.     LOGGER.info("========================================== Start =========================================="); 
  17.     // 打印請(qǐng)求 url 
  18.     LOGGER.info("URL            : {}", request.getRequestURL().toString()); 
  19.     // 打印 Http method 
  20.     LOGGER.info("HTTP Method    : {}", request.getMethod()); 
  21.     // 打印調(diào)用 controller 的全路徑以及執(zhí)行方法 
  22.     LOGGER.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); 
  23.     // 打印請(qǐng)求的 IP 
  24.     LOGGER.info("IP             : {}", IPAddressUtil.getIpAdrress(request)); 
  25.     // 打印請(qǐng)求入?yún)?nbsp;
  26.     LOGGER.info("Request Args   : {}", joinPoint.getArgs()); 
  27.  
  28. /** 
  29.  * 在切點(diǎn)之后織入 
  30.  * @throws Throwable 
  31.  */ 
  32. @After("webLog()"
  33. public void doAfter() throws Throwable { 
  34.     LOGGER.info("=========================================== End ==========================================="); 
  35.  
  36. /** 
  37.  * 環(huán)繞 
  38.  * @param proceedingJoinPoint 
  39.  * @return 
  40.  * @throws Throwable 
  41.  */ 
  42. @Around("webLog()"
  43. public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { 
  44.     long startTime = System.currentTimeMillis(); 
  45.     Object result = proceedingJoinPoint.proceed(); 
  46.     // 打印出參 
  47.     LOGGER.info("Response Args  : {}", result); 
  48.     // 執(zhí)行耗時(shí) 
  49.     LOGGER.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime); 
  50.     return result; 

代碼感覺(jué)完全沒(méi)有問(wèn)題,難道新版本的SpringBoot出Bug了。

顯然,成熟的框架不會(huì)在這種大方向上犯錯(cuò)誤,那會(huì)不會(huì)是新版本的SpringBoot把@After和@Around的順序反過(guò)來(lái)了?

其實(shí)事情也沒(méi)有那么簡(jiǎn)單。

Spring AOP執(zhí)行順序

我們先來(lái)回顧下Spring AOP執(zhí)行順序。

我們?cè)诰W(wǎng)上查找關(guān)于SpringAop執(zhí)行順序的的資料,大多數(shù)時(shí)候,你會(huì)查到如下的答案:

正常情況

 

異常情況

 

多個(gè)切面的情況

 

所以@Around理應(yīng)在@After之前,但是在SprinBoot 2.3.4.RELEASE版本中,@Around切切實(shí)實(shí)執(zhí)行在了@After之后。

當(dāng)我嘗試切換回2.2.5.RELEASE版本后,執(zhí)行順序又回到了@Around-->@After

探究順序錯(cuò)誤的真相

既然知道了是SpringBoot版本升級(jí)導(dǎo)致的問(wèn)題(或者說(shuō)順序變化),那么就要來(lái)看看究竟是哪個(gè)庫(kù)對(duì)AOP執(zhí)行的順序進(jìn)行了變動(dòng),畢竟,SpringBoot只是“形”,真正的內(nèi)核在Spring。

我們打開(kāi)pom.xml文件,使用插件查看spring-aop的版本,發(fā)現(xiàn)SpringBoot 2.3.4.RELEASE 版本使用的AOP是spring-aop-5.2.9.RELEASE。

而2.2.5.RELEASE對(duì)應(yīng)的是spring-aop-5.2.4.RELEASE

于是我去官網(wǎng)搜索文檔,不得不說(shuō)Spring由于過(guò)于龐大,官網(wǎng)的文檔已經(jīng)到了冗雜的地步,不過(guò)最終還是找到了:

https://docs.spring.io/spring-framework/docs/5.2.9.RELEASE/spring-framework-reference/core.html#aop-ataspectj-advice-ordering

 

As of Spring Framework 5.2.7, advice methods defined in the same @Aspect class that need to run at the same join point are assigned precedence based on their advice type in the following order, from highest to lowest precedence: @Around, @Before, @After, @AfterReturning, @AfterThrowing.

我粗淺的翻譯一下重點(diǎn):

從Spring5.2.7開(kāi)始,在相同@Aspect類中,通知方法將根據(jù)其類型按照從高到低的優(yōu)先級(jí)進(jìn)行執(zhí)行:@Around,@Before ,@After,@AfterReturning,@AfterThrowing。

這樣看其實(shí)對(duì)比不明顯,我們?cè)倩氐嚼习姹荆簿褪?.2.5.RELEASE對(duì)應(yīng)的spring-aop-5.2.4.RELEASE,當(dāng)時(shí)的文檔是這么寫(xiě)的:

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).

簡(jiǎn)單翻譯:在相同@Aspect類中Spring AOP遵循與AspectJ相同的優(yōu)先級(jí)規(guī)則來(lái)確定advice執(zhí)行的順序。

再挖深一點(diǎn),那么AspectJ的優(yōu)先級(jí)規(guī)則是什么樣的?

我找了AspectJ的文檔:

https://www.eclipse.org/aspectj/doc/next/progguide/semantics-advice.html

 

At a particular join point, advice is ordered by precedence.

A piece of around advice controls whether advice of lower precedence will run by calling proceed. The call to proceed will run the advice with next precedence, or the computation under the join point if there is no further advice.

A piece of before advice can prevent advice of lower precedence from running by throwing an exception. If it returns normally, however, then the advice of the next precedence, or the computation under the join pint if there is no further advice, will run.

Running after returning advice will run the advice of next precedence, or the computation under the join point if there is no further advice. Then, if that computation returned normally, the body of the advice will run.

Running after throwing advice will run the advice of next precedence, or the computation under the join point if there is no further advice. Then, if that computation threw an exception of an appropriate type, the body of the advice will run.

Running after advice will run the advice of next precedence, or the computation under the join point if there is no further advice. Then the body of the advice will run.

大伙又要說(shuō)了,哎呀太長(zhǎng)不看!簡(jiǎn)短地說(shuō),Aspectj的規(guī)則就是上面我們能夠在網(wǎng)上查閱到的順序圖展示的那樣,依舊是老的順序。

代碼驗(yàn)證

我把業(yè)務(wù)邏輯從代碼中刪除,只驗(yàn)證下這幾個(gè)advice的執(zhí)行順序:

  1. /** 
  2.  * 日志切面 
  3.  */ 
  4. @Aspect 
  5. @Component 
  6. public class WebLogAspect { 
  7.  
  8.     private final static Logger LOGGER = LoggerFactory.getLogger(WebLogAspect.class); 
  9.  
  10.     /** 以 controller 包下定義的所有請(qǐng)求為切入點(diǎn) */ 
  11.     @Pointcut("execution(public * com.xx.xxx.xxx.controller..*.*(..))"
  12.     public void webLog() {} 
  13.  
  14.     /** 
  15.      * 在切點(diǎn)之前織入 
  16.      * @param joinPoint 
  17.      * @throws Throwable 
  18.      */ 
  19.     @Before("webLog()"
  20.     public void doBefore(JoinPoint joinPoint) throws Throwable { 
  21.         LOGGER.info("-------------doBefore-------------"); 
  22.     } 
  23.  
  24.     @AfterReturning("webLog()"
  25.     public void afterReturning() { 
  26.         LOGGER.info("-------------afterReturning-------------"); 
  27.     } 
  28.     @AfterThrowing("webLog()"
  29.     public void afterThrowing() { 
  30.         LOGGER.info("-------------afterThrowing-------------"); 
  31.     } 
  32.  
  33.     /** 
  34.      * 在切點(diǎn)之后織入 
  35.      * @throws Throwable 
  36.      */ 
  37.     @After("webLog()"
  38.     public void doAfter() throws Throwable { 
  39.         LOGGER.info("-------------doAfter-------------"); 
  40.     } 
  41.  
  42.     /** 
  43.      * 環(huán)繞 
  44.      * @param proceedingJoinPoint 
  45.      * @return 
  46.      * @throws Throwable 
  47.      */ 
  48.     @Around("webLog()"
  49.     public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { 
  50.         long startTime = System.currentTimeMillis(); 
  51.         LOGGER.info("-------------doAround before proceed-------------"); 
  52.         Object result = proceedingJoinPoint.proceed(); 
  53.         LOGGER.info("-------------doAround after proceed-------------"); 
  54.         return result; 
  55.     } 

我們將版本改為2.2.5.RELEASE,結(jié)果如圖:

 

我們將版本改為2.3.4.RELEASE,結(jié)果如圖:

 

結(jié)論

經(jīng)過(guò)上面的資料文檔查閱,我能給出的結(jié)論是:

從Spring5.2.7開(kāi)始,Spring AOP不再嚴(yán)格按照AspectJ定義的規(guī)則來(lái)執(zhí)行advice,而是根據(jù)其類型按照從高到低的優(yōu)先級(jí)進(jìn)行執(zhí)行:@Around,@Before ,@After,@AfterReturning,@AfterThrowing。

這次的研究思考十分倉(cāng)促,如果結(jié)論有誤請(qǐng)大家踴躍指正,也歡迎大家自己嘗試,畢竟口說(shuō)無(wú)憑,實(shí)驗(yàn)室檢驗(yàn)真理的唯一標(biāo)準(zhǔn)!

參考

https://www.cnblogs.com/dennyLee2025/p/13724981.html

 

https://segmentfault.com/a/1190000011283029

本文轉(zhuǎn)載自微信公眾號(hào)「后端技術(shù)漫談」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系后端技術(shù)漫談公眾號(hào)。

 

責(zé)任編輯:武曉燕 來(lái)源: 后端技術(shù)漫談
相關(guān)推薦

2012-03-01 11:20:45

2016-04-20 09:49:25

網(wǎng)絡(luò)測(cè)試網(wǎng)絡(luò)優(yōu)化

2022-02-16 13:46:40

Spring Aop代碼注解

2016-01-07 11:18:50

用戶畫(huà)像

2024-04-19 13:17:40

PostgreSQLSQL數(shù)據(jù)庫(kù)

2016-06-01 15:42:58

Hadoop數(shù)據(jù)管理分布式

2020-04-17 14:25:22

Kubernetes應(yīng)用程序軟件開(kāi)發(fā)

2022-07-26 00:00:22

HTAP系統(tǒng)數(shù)據(jù)庫(kù)

2014-04-17 16:42:03

DevOps

2025-01-07 09:16:16

2021-02-01 13:59:47

比特幣區(qū)塊鏈安全

2023-12-27 14:04:00

Spring框架參數(shù)

2025-01-03 08:09:15

2022-09-22 14:55:31

前端JavaScripthis

2022-09-26 13:10:17

JavaScriptthis

2024-01-08 08:45:07

Spring容器Bean

2021-01-15 07:44:21

SQL注入攻擊黑客

2021-11-09 09:48:13

Logging python模塊

2022-08-15 10:42:50

千兆網(wǎng)絡(luò)千兆光纖

2021-04-23 07:27:31

內(nèi)存分配CPU
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: re久久| 中文字幕视频在线观看 | 中文字幕乱码一区二区三区 | 日本三级做a全过程在线观看 | 一区二区三区四区av | 一区二区三区国产 | 国产成在线观看免费视频 | 国产激情 | 国产精品成人一区二区三区夜夜夜 | 亚洲一区二区久久 | 国产精品伦理一区二区三区 | 亚洲国产片 | 亚洲最新网址 | 不卡一区二区三区四区 | 中文字幕一级毛片视频 | 欧美综合一区二区 | 亚洲精品久久久久中文字幕欢迎你 | 91色网站| 亚洲国产中文在线 | 色综合久 | 成人精品福利 | 国产精品特级毛片一区二区三区 | 一区二区三区成人 | 国产精品极品美女在线观看免费 | 日韩淫片免费看 | 亚洲精品在线播放 | 国产成人免费视频网站高清观看视频 | 国产成人久久精品一区二区三区 | av毛片| 成人超碰| 农村黄性色生活片 | 中文字幕成人网 | 夜夜骑天天干 | 91欧美精品成人综合在线观看 | 色久伊人| 天天综合干 | 午夜影院黄 | 精品久久香蕉国产线看观看亚洲 | 久草视频观看 | 国产在线中文字幕 | 国产有码 |