詳解Spring AOP的實(shí)現(xiàn)方式
AOP基本概念
Spring框架的兩大核心:IoC和AOP
AOP:Aspect Oriented Programming(面向切面編程)
AOP是一種思想,是對(duì)某一類事情的集中處理
面向切面編程:切面就是指某一類特定的問題,所以AOP可以理解為面向特定方法編程
舉例:攔截器是AOP的一種應(yīng)用
“特定問題”:登錄校驗(yàn)
針對(duì)特定問題統(tǒng)一處理:登錄校驗(yàn)攔截器
Spring對(duì)AOP進(jìn)行了實(shí)現(xiàn),并且提供了一些API,就是Spring AOP
AOP的作用:
攔截器作用的維度是URL(?次請求和響應(yīng)), @ControllerAdvice 應(yīng)用 場景主要是全局異常處理 (配合自定義異常效果更佳), 數(shù)據(jù)綁定, 數(shù)據(jù)預(yù)處理。 AOP作用的維度更加細(xì)致(可以根據(jù)包、類、方法名、參數(shù)等進(jìn)行攔截), 能夠?qū)崿F(xiàn)更加復(fù)雜的業(yè)務(wù)邏輯。
AOP開發(fā)步驟
舉例:往之前的圖書管理系統(tǒng)中創(chuàng)建一個(gè)切面aspect,打印每個(gè)接口的耗時(shí)。
引入AOP依賴
在pom.xml文件中添加配置
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
編寫AOP程序
打印每個(gè)接口的耗時(shí)
@Component//交給Spring管理 @Slf4j//打印日志 @Aspect//表明改類為切面 public class TimeAspect { // @Around定義哪些是目標(biāo)方法 @Around("execution(* com.example.SpringBookaliyun.controller.*.*(..))") public Object timeCost(ProceedingJoinPoint joinPoint) throws Throwable { //ProceedingJoinPoint表示作用的目標(biāo)方法 long start=System.currentTimeMillis(); //執(zhí)行目標(biāo)方法 Object result=joinPoint.proceed(); long end=System.currentTimeMillis(); log.info(joinPoint+"消耗時(shí)間:"+(end-start)+"ms"); return result; } }
通過上面的程序, 我們也可以感受到AOP面向切面編程的?些優(yōu)勢:
• 代碼無侵入: 不修改原始的業(yè)務(wù)方法, 就可以對(duì)原始的業(yè)務(wù)方法進(jìn)行功能的增強(qiáng)或者是功能的改變
• 減少了重復(fù)代碼
• 提高開發(fā)效率
• 維護(hù)方便
AOP詳解
1.切點(diǎn):切入點(diǎn) ,一組規(guī)則,通過表達(dá)式來描述
@Around("execution(* com.example.SpringBookaliyun.controller.*.*(..))")
2.連接點(diǎn):目標(biāo)方法就是連接點(diǎn);切點(diǎn)描述的方法
圖書管理系統(tǒng)中controller下的所有方法(add、delete.....)
3.通知:具體的邏輯,要做的處理
4.切面:切點(diǎn)+通知
通知(advice)
Spring中AOP的通知類型有以下幾種:
• @Around: 環(huán)繞通知, 此注解標(biāo)注的通知方法在目標(biāo)方法前, 后都被執(zhí)行
• @Before: 前置通知, 此注解標(biāo)注的通知方法在目標(biāo)方法前被執(zhí)行
• @After: 后置通知, 此注解標(biāo)注的通知方法在目標(biāo)方法后被執(zhí)行, 無論是否有異常都會(huì)執(zhí)行
• @AfterReturning: 返回后通知, 此注解標(biāo)注的通知方法在目標(biāo)方法后被執(zhí)行, 有異常不會(huì)執(zhí)行
• @AfterThrowing: 異常后通知, 此注解標(biāo)注的通知方法發(fā)生異常后執(zhí)行
簡單做一個(gè)測試:
測試結(jié)果:
先執(zhí)行around,再執(zhí)行before;先執(zhí)行after,再執(zhí)行around
當(dāng)添加一個(gè)異常的接口,執(zhí)行異常接口的時(shí)候,觀察控制臺(tái)的順序:
切點(diǎn)
@PointCut
當(dāng)有多個(gè)切面的時(shí)候,切面的執(zhí)行順序按照名稱進(jìn)行排序。但觀察比較麻煩,下面介紹切面優(yōu)先級(jí)。
切面優(yōu)先級(jí)(@Order)
當(dāng)我們在?個(gè)項(xiàng)目中, 定義了多個(gè)切面類時(shí), 并且這些切面類的多個(gè)切入點(diǎn)都匹配到了同?個(gè)目標(biāo)方法. 當(dāng)目標(biāo)方法運(yùn)行的時(shí)候,運(yùn)行順序不方便管理。
Spring 給我們提供了一個(gè)新的注解, 來控制這些切面通知的執(zhí)行順序:@Order
使用@Order時(shí),數(shù)字越小,優(yōu)先級(jí)越高
切點(diǎn)表達(dá)式
切點(diǎn)表達(dá)式常見有兩種表達(dá)?式
1. execution(RR):根據(jù)方法的簽名來匹配
2. @annotation(RR) :根據(jù)注解匹配
execution表達(dá)式
execution(<訪問修飾符> <返回類型> <包名.類名.?法(?法參數(shù))> <異常>)
訪問修飾符和異??梢允÷?/p>
//切點(diǎn)表達(dá)式?例 //TestController 下的 public修飾, 返回類型為String ?法名為t1, ?參?法 execution(public String com.example.demo.controller.TestController.t1()) //省略訪問修飾符 execution(String com.example.demo.controller.TestController.t1()) //匹配所有返回類型 execution(* com.example.demo.controller.TestController.t1()) //匹配TestController 下的所有?參?法 execution(* com.example.demo.controller.TestController.*()) //匹配TestController 下的所有?法 execution(* com.example.demo.controller.TestController.*(..)) //匹配controller包下所有的類的所有?法 execution(* com.example.demo.controller.*.*(..)) //匹配所有包下?的TestController execution(* com..TestController.*(..)) //匹配com.example.demo包下, ?孫包下的所有類的所有?法 execution(* com.example.demo..*(..))
@annotation注解匹配
execution表達(dá)式更適用有規(guī)則的, 如果我們要匹配多個(gè)無規(guī)則的方法時(shí), 例如:TestController中的t1() 和UserController中的u1()這兩個(gè)方法.
這個(gè)時(shí)候使用execution這種切點(diǎn)表達(dá)式來描述比較麻煩。
此時(shí)使用@annotation 來描述這一類的切點(diǎn)
實(shí)現(xiàn)步驟:
1. 編寫自定義注解
2. 使用@annotation 表達(dá)式來描述切點(diǎn)
3. 在連接點(diǎn)的方法上添加自定義注解
1. 編寫自定義注解
2. 使用@annotation 表達(dá)式來描述切點(diǎn)
3. 在連接點(diǎn)的方法上添加自定義注解
此時(shí)只有執(zhí)行h1和t2時(shí),控制臺(tái)才會(huì)出現(xiàn)對(duì)切點(diǎn)的描述
到此這篇關(guān)于Spring AOP的實(shí)現(xiàn)方式的文章就介紹到這了,更多相關(guān)Spring AOP內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談Java中對(duì)類的主動(dòng)引用和被動(dòng)引用
這篇文章主要介紹了淺談Java中對(duì)類的主動(dòng)引用和被動(dòng)引用,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02基于Java實(shí)現(xiàn)一個(gè)復(fù)雜關(guān)系表達(dá)式過濾器
這篇文章主要為大家詳細(xì)介紹了如何基于Java實(shí)現(xiàn)一個(gè)復(fù)雜關(guān)系表達(dá)式過濾器。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-07-07IDEA插件之mybatisx插件使用教程(超詳細(xì)!)
MybatisX 是一款基于IDEA的快速開發(fā)插件,為效率而生,下面這篇文章主要給大家介紹了關(guān)于IDEA插件之mybatisx插件使用的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06使用Jackson進(jìn)行JSON生成與解析的新手指南
這篇文章主要為大家詳細(xì)介紹了如何使用Jackson進(jìn)行JSON生成與解析處理,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-04-04mybatis if test 不為空字符串且不為null的問題
這篇文章主要介紹了mybatis if test 不為空字符串且不為null的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03基于JSON和java對(duì)象的互轉(zhuǎn)方法
下面小編就為大家?guī)硪黄贘SON和java對(duì)象的互轉(zhuǎn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09使用springboot不自動(dòng)初始化數(shù)據(jù)庫連接池
這篇文章主要介紹了使用springboot不自動(dòng)初始化數(shù)據(jù)庫連接池,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09myeclipse中使用maven前常見錯(cuò)誤及解決辦法
這篇文章主要介紹了myeclipse中使用maven前常見錯(cuò)誤及解決辦法 的相關(guān)資料,需要的朋友可以參考下2016-05-05