电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

聊聊Spring AOP @Before @Around @After等advice的執行順序

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

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

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

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

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

前提

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

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

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

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

添加 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@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'); }}添加測試用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 advisetest 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 advisethrow an exception[Aspect1] after advise[Aspect1] afterThrowing advise結論

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

正常情況:

聊聊Spring AOP @Before @Around @After等advice的執行順序

異常情況:

聊聊Spring AOP @Before @Around @After等advice的執行順序

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

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

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

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@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'); }}

測試用Controller也不變

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

下面繼續進行測試!

測試 正常情況

在瀏覽器直接輸入以下的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 advisetest OK[Aspect1] around advise2[Aspect1] after advise[Aspect1] afterReturning advise[Aspect2] around advise2[Aspect2] after advise[Aspect2] afterReturning advise

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

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

[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

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

測試 異常情況

在瀏覽器中直接輸入以下的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 advisethrow 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 advisethrow an exception[Aspect2] after advise[Aspect2] afterThrowing advise[Aspect1] after advise[Aspect1] afterThrowing advise

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

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

方法有兩種:

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

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

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

比如,我們為 apsect1 和 aspect2 分別添加 @Order 注解,如下:

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

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

如下圖所示:

聊聊Spring AOP @Before @Around @After等advice的執行順序

注意點

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

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

比如,我們假設正常情況下,執行順序為”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

從結果可以發現, Controller 中的 接口 未被執行,aspect1 中的 @Before advice 也未被執行。

參考資料

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

其中,AOP的執行順序章節為: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.

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

標簽: Spring
相關文章:
主站蜘蛛池模板: 二手Sciex液质联用仪-岛津气质联用仪-二手安捷伦气质联用仪-上海隐智科学仪器有限公司 | 直读光谱仪,光谱分析仪,手持式光谱仪,碳硫分析仪,创想仪器官网 | 创绿家招商加盟网-除甲醛加盟-甲醛治理加盟-室内除甲醛加盟-创绿家招商官网 | 锂电混合机-新能源混合机-正极材料混料机-高镍,三元材料混料机-负极,包覆混合机-贝尔专业混合混料搅拌机械系统设备厂家 | PC构件-PC预制构件-构件设计-建筑预制构件-PC构件厂-锦萧新材料科技(浙江)股份有限公司 | 开云(中国)Kaiyun·官方网站 - 登录入口| 德国BOSCH电磁阀-德国HERION电磁阀-JOUCOMATIC电磁阀|乾拓百科 | 纯水电导率测定仪-万用气体检测仪-低钠测定仪-米沃奇科技(北京)有限公司www.milwaukeeinst.cn 锂辉石检测仪器,水泥成分快速分析仪-湘潭宇科分析仪器有限公司 手术室净化装修-手术室净化工程公司-华锐手术室净化厂家 | 识禅_对禅的了解,从这里开始| 集装箱箱号识别_自重载重图像识别_铁路车号自动识别_OCR图像识别 | 维泰克Veertek-锂电池微短路检测_锂电池腐蚀检测_锂电池漏液检测 | 3d可视化建模_三维展示_产品3d互动数字营销_三维动画制作_3D虚拟商城 【商迪3D】三维展示服务商 广东健伦体育发展有限公司-体育工程配套及销售运动器材的体育用品服务商 | 南京展台搭建-南京展会设计-南京展览设计公司-南京展厅展示设计-南京汇雅展览工程有限公司 | 环保袋,无纺布袋,无纺布打孔袋,保温袋,环保袋定制,环保袋厂家,环雅包装-十七年环保袋定制厂家 | 作文导航网_作文之家_满分作文_优秀作文_作文大全_作文素材_最新作文分享发布平台 | 超细粉碎机|超微气流磨|气流分级机|粉体改性设备|超微粉碎设备-山东埃尔派粉碎机厂家 | 首页 - 张店继勇软件开发工作室| 送料机_高速冲床送料机_NC伺服滚轮送料机厂家-东莞市久谐自动化设备有限公司 | 美能达分光测色仪_爱色丽分光测色仪-苏州方特电子科技有限公司 | 济南品牌包装设计公司_济南VI标志设计公司_山东锐尚文化传播 | 耐高温风管_耐高温软管_食品级软管_吸尘管_钢丝软管_卫生级软管_塑料波纹管-东莞市鑫翔宇软管有限公司 | 河南卓美创业科技有限公司-河南卓美防雷公司-防雷接地-防雷工程-重庆避雷针-避雷器-防雷检测-避雷带-避雷针-避雷塔、机房防雷、古建筑防雷等-山西防雷公司 | 超声波气象站_防爆气象站_空气质量监测站_负氧离子检测仪-风途物联网 | IIS7站长之家-站长工具-爱网站请使用IIS7站长综合查询工具,中国站长【WWW.IIS7.COM】 | 【直乐】河北石家庄脊柱侧弯医院_治疗椎间盘突出哪家医院好_骨科脊柱外科专业医院_治疗抽动症/关节病骨伤权威医院|排行-直乐矫形中医医院 | 档案密集柜_手动密集柜_智能密集柜_内蒙古档案密集柜-盛隆柜业内蒙古密集柜直销中心 | 游动电流仪-流通式浊度分析仪-杰普仪器(上海)有限公司 | 阿里巴巴诚信通温州、台州、宁波、嘉兴授权渠道商-浙江联欣科技提供阿里会员办理 | 广州市哲铭油墨涂料有限公司,水性漆生产研发基地 | EDLC超级法拉电容器_LIC锂离子超级电容_超级电容模组_软包单体电容电池_轴向薄膜电力电容器_深圳佳名兴电容有限公司_JMX专注中高端品牌电容生产厂家 | 半容积式换热器_北京浮动盘管换热器厂家|北京亿丰上达 | 「钾冰晶石」氟铝酸钾_冰晶石_氟铝酸钠「价格用途」-亚铝氟化物厂家 | 消泡剂-水处理消泡剂-涂料消泡剂-切削液消泡剂价格-东莞德丰消泡剂厂家 | 磁棒电感生产厂家-电感器厂家-电感定制-贴片功率电感供应商-棒形电感生产厂家-苏州谷景电子有限公司 | 武汉森源蓝天环境科技工程有限公司-为环境污染治理提供协同解决方案 | 无锡不干胶标签,卷筒标签,无锡瑞彩包装材料有限公司 | 塑胶跑道施工-硅pu篮球场施工-塑胶网球场建造-丙烯酸球场材料厂家-奥茵 | LCD3D打印机|教育|桌面|光固化|FDM3D打印机|3D打印设备-广州造维科技有限公司 | NBA直播_NBA直播免费观看直播在线_NBA直播免费高清无插件在线观看-24直播网 | 手持气象站_便携式气象站_农业气象站_负氧离子监测站-山东万象环境 | 安驭邦官网-双向万能直角铣头,加工中心侧铣头,角度头[厂家直销] 闸阀_截止阀_止回阀「生产厂家」-上海卡比阀门有限公司 |