成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

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

瀏覽:94日期:2023-07-22 17:04:48

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

最近,為了實(shí)現(xiàn)項(xiàng)目中的輸出日志和權(quán)限控制這兩個(gè)需求,我也使用到了AOP功能。

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

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

前提

對(duì)于AOP相關(guān)類(lèi)(aspect、pointcut等)的概念,本文不作說(shuō)明。

對(duì)于如何讓spring框架掃描到AOP,本文也不作說(shuō)明。

情況一: 一個(gè)方法只被一個(gè)Aspect類(lèi)攔截

當(dāng)一個(gè)方法只被一個(gè)Aspect攔截時(shí),這個(gè)Aspect中的不同advice是按照怎樣的順序進(jìn)行執(zhí)行的呢?請(qǐng)看:

添加 PointCut類(lèi)

該pointcut用來(lái)攔截test包下的所有類(lèi)中的所有方法。

package test;import org.aspectj.lang.annotation.Pointcut;public class PointCuts { @Pointcut(value = 'within(test.*)') public void aopDemo() { }}添加Aspect類(lèi)

該類(lèi)中的advice將會(huì)用到上面的pointcut,使用方法請(qǐng)看各個(gè)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@Aspectpublic 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'); }}添加測(cè)試用Controller

添加一個(gè)用于測(cè)試的controller,這個(gè)controller中只有一個(gè)方法,但是它會(huì)根據(jù)參數(shù)值的不同,會(huì)作出不同的處理:一種是正常返回一個(gè)對(duì)象,一種是拋出異常(因?yàn)槲覀円獪y(cè)試@AfterThrowing這個(gè)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; } }}

測(cè)試 正常情況

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

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

我們會(huì)看到輸出的結(jié)果是:

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

測(cè)試 異常情況

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

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

我們會(huì)看到輸出的結(jié)果是:

[Aspect1] around advise 1[Aspect1] before advisethrow an exception[Aspect1] after advise[Aspect1] afterThrowing advise結(jié)論

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

正常情況:

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

異常情況:

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

情況二: 同一個(gè)方法被多個(gè)Aspect類(lèi)攔截

此處舉例為被兩個(gè)aspect類(lèi)攔截。

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

pointcut類(lèi)保持不變

添加一個(gè)新的aspect類(lèi)

package test;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;@Component@Aspectpublic 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'); }}

測(cè)試用Controller也不變

還是使用上面的那個(gè)Controller。但是現(xiàn)在 aspect1 和 aspect2 都會(huì)攔截該controller中的方法。

下面繼續(xù)進(jìn)行測(cè)試!

測(cè)試 正常情況

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

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

我們會(huì)看到輸出的結(jié)果是:

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

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

不信?你把服務(wù)務(wù)器重新啟動(dòng)一下,再試試,說(shuō)不定你就會(huì)看到如下的執(zhí)行結(jié)果:

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

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

測(cè)試 異常情況

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

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

我們會(huì)看到輸出的結(jié)果是:

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

同樣地,如果把服務(wù)器重啟,然后再測(cè)試的話(huà),就可能會(huì)看到如下的結(jié)果:

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

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

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

方法有兩種:

實(shí)現(xiàn)org.springframework.core.Ordered接口,實(shí)現(xiàn)它的getOrder()方法

給aspect添加@Order注解,該注解全稱(chēng)為:org.springframework.core.annotation.Order

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

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

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

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

如下圖所示:

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

注意點(diǎn)

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

對(duì)于@Around這個(gè)advice,不管它有沒(méi)有返回值,但是必須要方法內(nèi)部,調(diào)用一下 pjp.proceed();否則,Controller 中的接口將沒(méi)有機(jī)會(huì)被執(zhí)行,從而也導(dǎo)致了 @Before這個(gè)advice不會(huì)被觸發(fā)。

比如,我們假設(shè)正常情況下,執(zhí)行順序?yàn)椤盿spect2 -> apsect1 -> controller”,如果,我們把 aspect1中的@Around中的 pjp.proceed();給刪掉,那么,我們看到的輸出結(jié)果將是:

[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

從結(jié)果可以發(fā)現(xiàn), 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.

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持好吧啦網(wǎng)。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

標(biāo)簽: Spring
相關(guān)文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
欧美三日本三级三级在线播放| 色婷婷综合激情| 国产成人综合精品三级| 日产欧产美韩系列久久99| 亚洲第一综合色| 天涯成人国产亚洲精品一区av| 亚洲一区在线免费观看| 亚洲午夜在线视频| 天堂久久久久va久久久久| 亚洲线精品一区二区三区| 亚洲国产成人av网| 久久国产日韩欧美精品| 精品亚洲成a人在线观看| 国产精品自拍网站| 99精品1区2区| 一区免费在线| 免费不卡亚洲欧美| 欧美主播一区二区三区美女| 69精品人人人人| 日韩免费高清av| 亚洲国产成人一区二区三区| 成人免费一区二区三区在线观看 | 最好看的中文字幕久久| 亚洲欧美日韩系列| 肉色丝袜一区二区| 国产成人av影院| 91免费观看视频在线| 亚洲美洲欧洲综合国产一区| 久久青青草综合| 日韩一区二区三区四区五区六区| 精品国产免费视频| 亚洲男人天堂av网| 久久精品国产99| 91影院在线观看| 亚洲精品在线二区| 欧美日韩国产片| 国产色产综合色产在线视频| 亚洲永久免费av| 国产一区二区调教| 国色天香一区二区| 色哟哟一区二区三区| 精品国产亚洲在线| 亚洲午夜激情网站| heyzo一本久久综合| 国产农村妇女精品一二区 | 自拍偷拍欧美精品| 国产伦精一区二区三区| 亚洲精品在线视频观看| 欧美日韩中文字幕一区| 中文字幕在线不卡一区| 黄色日韩网站视频| 亚洲青涩在线| 欧美xxxx老人做受| 午夜精品久久久久久久| 99精品在线观看视频| 蜜桃av久久久亚洲精品| 久久久久久亚洲综合| 日韩av网站在线观看| 狠狠色噜噜狠狠色综合久| 欧美日韩中文字幕一区| 亚洲另类春色校园小说| 成人免费视频caoporn| 久久综合影音| 亚洲欧美日韩中文播放| av在线不卡观看免费观看| 六月丁香综合| 成人欧美一区二区三区| 99久久久免费精品国产一区二区| 色哟哟欧美精品| 亚洲乱码国产乱码精品精98午夜 | 欧美日韩在线一二三| 这里是久久伊人| 日日骚欧美日韩| 激情一区二区三区| 久久人人97超碰com| 狠狠色丁香久久婷婷综| 色婷婷激情一区二区三区| 亚洲欧美日韩国产手机在线| 91视视频在线直接观看在线看网页在线看| 老司机免费视频久久| 亚洲精品中文字幕在线观看| 欧美在线亚洲| 久久久夜色精品亚洲| 国产乱淫av一区二区三区| 久久午夜av| 午夜亚洲福利老司机| 一本色道久久| 亚洲精选视频在线| 最新成人av网站| 国产精品美女久久久久久久久 | 国产精品手机在线| 亚洲激情男女视频| 亚洲精选91| 亚洲啪啪综合av一区二区三区| 欧美高清一区二区| 久久精品人人做人人综合| 成人一道本在线| 日韩欧美一卡二卡| 国产成人精品aa毛片| 91麻豆精品国产91久久久久久久久 | 欧美日韩亚洲三区| 国产精品色眯眯| 亚洲网友自拍| 亚洲欧洲精品天堂一级| 在线观看视频日韩| 亚洲欧美国产高清| 亚洲一区二区伦理| 日韩精品成人一区二区三区| 一本大道av伊人久久综合| 日韩av一二三| 欧美精品乱人伦久久久久久| 国产精品456露脸| 精品美女一区二区| 午夜精品美女久久久久av福利| 中文字幕免费观看一区| 欧美特黄a级高清免费大片a级| 成人欧美一区二区三区| 国产精品日韩欧美一区二区| 天天综合色天天综合| 欧美日韩精品欧美日韩精品| 国产在线看一区| 精品精品国产高清一毛片一天堂| 91麻豆福利精品推荐| 亚洲欧美综合色| 久久九九免费| 国产精品夜夜爽| 国产午夜一区二区三区| 99国产精品99久久久久久粉嫩| 亚洲大片在线观看| 欧美日韩情趣电影| 91色综合久久久久婷婷| 亚洲品质自拍视频| 欧美三级在线视频| 91浏览器打开| 午夜欧美电影在线观看| 日韩一区二区三| 伊人色综合久久天天五月婷| 日韩一区欧美二区| 欧美一区二区三区系列电影| 欧美一区亚洲二区| 亚洲成人自拍偷拍| 日韩丝袜情趣美女图片| 最新亚洲激情| 国产一区二区按摩在线观看| 中文字幕av一区二区三区| 一本久久精品一区二区| 99riav久久精品riav| 亚洲国产日韩精品| 日韩欧美亚洲一区二区| 亚洲一区二区三区精品在线观看| 国产成人av电影| 一区二区三区高清| 欧美电影免费观看高清完整版在线 | 亚洲色图制服诱惑 | 国产精品免费人成网站| 色偷偷成人一区二区三区91| 91蝌蚪porny| 久久99精品久久久| 一区在线观看视频| 欧美一级黄色大片| 奶水喷射视频一区| 欧美在线不卡| 韩国一区二区视频| 一区二区三区不卡视频| 精品国产一区二区在线观看| 久久av在线| 亚洲无线观看| 成人网在线免费视频| 日韩经典一区二区| 自拍偷在线精品自拍偷无码专区| 欧美一区二区三区成人| 久久精品二区三区| 雨宫琴音一区二区在线| 国产夫妻精品视频| 日韩电影免费在线| 亚洲一区二区三区中文字幕在线| 久久品道一品道久久精品| 欧美日韩一区精品| 99在线观看免费视频精品观看| 972aa.com艺术欧美| 国模娜娜一区二区三区| 图片区小说区国产精品视频| 中文字幕一区日韩精品欧美| 久久综合九色综合久久久精品综合| 日本高清不卡在线观看| 亚洲一区二区高清视频| 亚洲经典三级| 好吊视频一区二区三区四区 | 69精品人人人人| 欧美日韩大陆一区二区| 色呦呦一区二区三区| 乱人伦精品视频在线观看| 亚洲精选在线| 亚洲精品一区二区三区av| 国产综合欧美| 国产一区再线| 亚洲国产精品一区二区第一页 | 国产精品免费区二区三区观看| 亚洲一级二级| 亚洲黄色成人|