Spring?AOP中的環(huán)繞通知詳解
一、什么是AOP?
Aspect Oriented Programming(面向切面編程)
AOP是Spring框架的第??核?(第??核?是IoC)
AOP是一種思想,是對(duì)某一類(lèi)事情的集中處理。
其中在下面的學(xué)習(xí)中我們會(huì)學(xué)習(xí)到攔截器、統(tǒng)一異常處理,統(tǒng)一結(jié)果處理等,這些都是運(yùn)用了AOP的統(tǒng)一思想來(lái)實(shí)現(xiàn)的。
攔截器實(shí)現(xiàn)AOP思想作用的維度是前端對(duì)后端進(jìn)行的一次請(qǐng)求和一次響應(yīng),主要是檢索前端傳來(lái)的URL,如果檢索后返回True,則可以進(jìn)入Controller開(kāi)始執(zhí)行代碼,如果返回的為False,則表示失敗,直接被攔截在外面,無(wú)法執(zhí)行代碼。
統(tǒng)一結(jié)果處理則是使用注解@ControllerAdvice(通知類(lèi)注解),實(shí)現(xiàn)ResponseBodyAdvice接口,對(duì)響應(yīng)的結(jié)果進(jìn)行統(tǒng)一處理,對(duì)齊進(jìn)行統(tǒng)一的包裝后響應(yīng),其中如果數(shù)據(jù)類(lèi)型為String類(lèi)型的話要進(jìn)行特殊處理,使用ObjectMapper的方法將String格式轉(zhuǎn)為Json格式再次響應(yīng)。
統(tǒng)一異常處理也是使用注解@ControllerAdvice(通知類(lèi)注解),以及在方法上使用@ExceptionHandler注解,在全部的程序中如果遇到運(yùn)行時(shí)異常則會(huì)自動(dòng)捕捉,進(jìn)行拋出,注:編譯時(shí)異常是寫(xiě)代碼過(guò)程中出現(xiàn)的,不手動(dòng)解決就無(wú)法運(yùn)行程序。
接下來(lái)我們要學(xué)習(xí)的是運(yùn)用了AOP思想,進(jìn)行AOP的環(huán)繞處理
二、AOP 的環(huán)繞通知
2.1 切點(diǎn)以及切點(diǎn)表達(dá)式
切點(diǎn)=通知類(lèi)型+切點(diǎn)表達(dá)式
切點(diǎn)表示了為該方法提供一組規(guī)則,來(lái)對(duì)程序進(jìn)行功能增強(qiáng)
通知類(lèi)型有以下5種:
@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í)行
如下圖所示:
在該方法上的@Around,表示的是環(huán)繞處理,是一種通知類(lèi)型
其后面的execution(* com.example.demo.controller..(…)) 表示的是該通知類(lèi)型作用的范圍,是切點(diǎn)表達(dá)式
2.2 連接點(diǎn)
滿足切點(diǎn)表達(dá)式規(guī)則的方法就是連接點(diǎn)
在該圖中,public recordTime方法就是連接點(diǎn)
2.3 通知(Advice)
通知就是具體要做的內(nèi)容,簡(jiǎn)單來(lái)說(shuō)就是方法內(nèi)執(zhí)行的代碼內(nèi)容
如圖所示:
該圖中標(biāo)紅的位置就是通知內(nèi)容,在AOP面向切面編程當(dāng)中,我們把這部分重復(fù)的代碼邏輯抽取出來(lái)單獨(dú)定義,這部分代碼就是通知的內(nèi)容
2.4 切面(Aspect)
首先使用注解@Aspect來(lái)表示該類(lèi)是一個(gè)切面類(lèi)
然后使用不同的通知類(lèi)型進(jìn)行處理,如圖表示的是環(huán)繞通知類(lèi)型
在處理過(guò)程中ProceedingJoinPoint.proceed()讓原始方法執(zhí)行
切面(Aspect)=切點(diǎn)(Pointcut)+通知(Advice)
以下代碼表示一個(gè)完整的切面類(lèi):
import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Slf4j @Aspect @Component public class TimeAspect { /** * 記錄方法耗時(shí) */ @Around("execution(* com.example.demo.controller.*.*(..))") public Object recordTime(ProceedingJoinPoint pjp) throws Throwable { //記錄方法執(zhí)行開(kāi)始時(shí)間 long begin = System.currentTimeMillis(); //執(zhí)行原始方法 Object result = pjp.proceed(); //記錄方法執(zhí)行結(jié)束時(shí)間 long end = System.currentTimeMillis(); //記錄方法執(zhí)行耗時(shí) log.info(pjp.getSignature() + "執(zhí)行耗時(shí): {}ms", end - begin); return result; } }
2.5 不同通知類(lèi)型的區(qū)別
2.5.1 正常情況下
環(huán)繞通知 @Around 標(biāo)識(shí)的通知方法包含兩部分,?個(gè)"前置邏輯",?個(gè)"后置邏輯".其
中"前置邏輯"會(huì)先于 @Before 標(biāo)識(shí)的通知方法執(zhí)行,"后置邏輯"會(huì)晚于 @After 標(biāo)識(shí)的通知方法執(zhí)行
2.5.2異常情況下
程序發(fā)?異常的情況下:
• @AfterReturning 標(biāo)識(shí)的通知方法不會(huì)執(zhí)行, @AfterThrowing 標(biāo)識(shí)的通知方法執(zhí)行了
• @Around 環(huán)繞通知中原始方法調(diào)?時(shí)有異常,通知中的環(huán)繞后的代碼邏輯也不會(huì)在執(zhí)行了(因?yàn)?br />原始方法調(diào)?出異常了)
注意事項(xiàng):
• @Around 環(huán)繞通知需要調(diào)? ProceedingJoinPoint.proceed() 來(lái)讓原始方法執(zhí)行,其他
通知不需要考慮目標(biāo)方法執(zhí)行.
• @Around 環(huán)繞通知方法的返回值,必須指定為Object,來(lái)接收原始方法的返回值,否則原始方法執(zhí)
行完畢,是獲取不到返回值的.
• ?個(gè)切面類(lèi)可以有多個(gè)切點(diǎn)
2.6 統(tǒng)一管理切點(diǎn)@PointCut
• @Around 環(huán)繞通知需要調(diào)? ProceedingJoinPoint.proceed() 來(lái)讓原始方法執(zhí)行,其他
通知不需要考慮目標(biāo)方法執(zhí)行.
• @Around 環(huán)繞通知方法的返回值,必須指定為Object,來(lái)接收原始方法的返回值,否則原始方法執(zhí)
行完畢,是獲取不到返回值的.
• ?個(gè)切面類(lèi)可以有多個(gè)切點(diǎn)
本類(lèi)使用注解后的切點(diǎn)表達(dá)式代碼如下:
@Slf4j @Aspect @Component public class AspectDemo { //定義切點(diǎn)(公共的切點(diǎn)表達(dá)式) @Pointcut("execution(* com.example.demo.controller.*.*(..))") private void pt(){} //前置通知 @Before("pt()") public void doBefore() { //...代碼省略 } //后置通知 @After("pt()") public void doAfter() { //...代碼省略 } //返回后通知 @AfterReturning("pt()") public void doAfterReturning() { //...代碼省略 } //拋出異常后通知 @AfterThrowing("pt()") public void doAfterThrowing() { //...代碼省略 } //添加環(huán)繞通知 @Around("pt()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { //...代碼省略 } }
在其他類(lèi)中調(diào)用該切點(diǎn)表達(dá)式代碼如下:
@Slf4j @Aspect @Component public class AspectDemo2 { //前置通知 @Before("com.example.demo.aspect.AspectDemo.pt()") public void doBefore() { log.info("執(zhí)行 AspectDemo2 -> Before 方法"); } }``` 當(dāng)切點(diǎn)定義使?private修飾時(shí),僅能在當(dāng)前切面類(lèi)中使?,當(dāng)其他切面類(lèi)也要使?當(dāng)前切點(diǎn)定義時(shí),就需要把private改為public.引?方式為:全限定類(lèi)名.方法名() ### 2.7 切面優(yōu)先級(jí)@Order 在切面類(lèi)中會(huì)有多個(gè)切點(diǎn)同時(shí)匹配成功,那么該如何進(jìn)行執(zhí)行順序呢? 應(yīng)該使用注解@Order(數(shù)字)來(lái)表示優(yōu)先級(jí)順序 @Order注解標(biāo)識(shí)的切面類(lèi),執(zhí)行順序如下: ? @Before 通知:數(shù)字越?先執(zhí)行 ? @After 通知:數(shù)字越?先執(zhí)行 @Order 控制切面的優(yōu)先級(jí),先執(zhí)行優(yōu)先級(jí)較?的切面,再執(zhí)行優(yōu)先級(jí)較低的切面,最終執(zhí)行目標(biāo)方法.
到此這篇關(guān)于Spring AOP中的環(huán)繞通知的文章就介紹到這了,更多相關(guān)Spring AOP環(huán)繞通知內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springbootAOP定義切點(diǎn)獲取/修改請(qǐng)求參數(shù)方式
- 使用Spring AOP監(jiān)控指定方法執(zhí)行時(shí)間的代碼詳解
- Spring Boot使用AOP在指定方法執(zhí)行完后執(zhí)行異步處理操作
- spring?boot如何通過(guò)自定義注解和AOP攔截指定的請(qǐng)求
- Spring AOP注解實(shí)戰(zhàn)指南
- SpringBoot使用AOP實(shí)現(xiàn)統(tǒng)計(jì)全局接口訪問(wèn)次數(shù)詳解
- 詳解Java SpringAOP切面類(lèi)
- Spring AOP快速入門(mén)及開(kāi)發(fā)步驟
相關(guān)文章
SpringBoot3 RestTemplate配置與使用詳解
本文詳細(xì)介紹了在 SpringBoot 3.x 中如何配置和使用 RestTemplate,包括基本配置、高級(jí)配置以及各種使用場(chǎng)景,感興趣的朋友跟隨小編一起看看吧2024-12-12Java網(wǎng)絡(luò)編程之基于TCP協(xié)議
本文主要將Java基于TCP的網(wǎng)絡(luò)編程主要分解成5個(gè)功能:功能分解1:單向通信功能分解,2:雙向通信功能分解,3:對(duì)象流傳送功能分解,4:加入完整的處理異常方式功能分解,5:多線程接收用戶請(qǐng)求,需要的朋友可以參考下2021-05-05Java實(shí)現(xiàn)ArrayList排序的方法詳解
Java中常見(jiàn)的ArrayList排序方法主要為三種:JDK8的stream、Comparator#compare()和Comparable#compareTo(),本文將詳解這三者的使用,需要的可以參考一下2022-05-05解析SpringBoot @EnableAutoConfiguration的使用
這篇文章主要介紹了解析SpringBoot @EnableAutoConfiguration的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09基于Spring AMQP實(shí)現(xiàn)消息隊(duì)列的示例代碼
Spring AMQP作為Spring框架的一部分,是一套用于支持高級(jí)消息隊(duì)列協(xié)議(AMQP)的工具,AMQP是一種強(qiáng)大的消息協(xié)議,旨在支持可靠的消息傳遞,本文給大家介紹了如何基于Spring AMQP實(shí)現(xiàn)消息隊(duì)列,需要的朋友可以參考下2024-03-03java 裝飾模式(Decorator Pattern)詳解及實(shí)例代碼
裝飾器模式(Decorator Pattern)允許向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。這種類(lèi)型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類(lèi)的一個(gè)包裝2016-10-10Linux下Java開(kāi)發(fā)環(huán)境搭建以及第一個(gè)HelloWorld
這篇文章主要介紹了Linux下Java開(kāi)發(fā)環(huán)境搭建以及第一個(gè)HelloWorld的實(shí)現(xiàn)過(guò)程,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-09-09mybatis-plus3.4.0邏輯刪除報(bào)錯(cuò)的解決
這篇文章主要介紹了mybatis-plus3.4.0邏輯刪除報(bào)錯(cuò)的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11