Spring @Around注解使用及說明
@Around是 Spring AOP(面向切面編程)中的一個(gè)注解,它用于定義一個(gè)環(huán)繞通知(Around Advice)。
環(huán)繞通知是 AOP 中最強(qiáng)大的一種通知類型,因?yàn)樗軌蛟诜椒▓?zhí)行之前和之后都執(zhí)行自定義的邏輯,并且可以控制方法是否繼續(xù)執(zhí)行或改變其返回值。
@Around注解的基本用法
要使用@Around注解,你需要先定義一個(gè)切面(Aspect),然后在該切面中使用@Around注解來標(biāo)注一個(gè)方法,該方法將作為環(huán)繞通知。環(huán)繞通知方法必須接受一個(gè)ProceedingJoinPoint類型的參數(shù),這個(gè)參數(shù)提供了對(duì)正在執(zhí)行的方法的訪問。
以下是一個(gè)簡(jiǎn)單的例子:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAroundAdvice {
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
// 在方法執(zhí)行之前的邏輯
System.out.println("Before method execution");
try {
Object result = pjp.proceed(); // 執(zhí)行目標(biāo)方法
// 在方法執(zhí)行之后的邏輯
System.out.println("After method execution");
return result; // 返回目標(biāo)方法的執(zhí)行結(jié)果
} catch (Throwable throwable) {
// 處理異常
System.out.println("Exception occurred: " + throwable.getMessage());
throw throwable; // 重新拋出異常
}
}
}
@Around注解的工作機(jī)制
匹配切入點(diǎn):
@Around注解的值是一個(gè)切入點(diǎn)表達(dá)式(Pointcut Expression),它指定了哪些方法將被這個(gè)環(huán)繞通知攔截。在上面的例子中,切入點(diǎn)表達(dá)式"execution(* com.example.service.*.*(..))"匹配了com.example.service包下所有類的所有方法。創(chuàng)建代理:Spring AOP 會(huì)在運(yùn)行時(shí)為匹配到的方法創(chuàng)建代理對(duì)象。當(dāng)這些方法被調(diào)用時(shí),實(shí)際上調(diào)用的是代理對(duì)象的方法。
執(zhí)行環(huán)繞通知:當(dāng)代理對(duì)象的方法被調(diào)用時(shí),Spring AOP 會(huì)先執(zhí)行環(huán)繞通知中的邏輯。在環(huán)繞通知中,你可以通過調(diào)用**
ProceedingJoinPoint的proceed**方法來執(zhí)行目標(biāo)方法。你也可以選擇不調(diào)用proceed方法,從而阻止目標(biāo)方法的執(zhí)行。處理返回值和異常:環(huán)繞通知可以獲取目標(biāo)方法的返回值,并在必要時(shí)進(jìn)行修改。同時(shí),它也可以捕獲目標(biāo)方法拋出的異常,并進(jìn)行相應(yīng)的處理。
以下是一些常見的@Around注解應(yīng)用場(chǎng)景:
日志記錄:在目標(biāo)方法執(zhí)行之前和之后記錄日志,可以幫助開發(fā)者了解方法的執(zhí)行流程、輸入?yún)?shù)、返回值以及執(zhí)行時(shí)間等信息。這對(duì)于調(diào)試和監(jiān)控應(yīng)用程序的狀態(tài)非常有幫助。
性能監(jiān)控:通過在目標(biāo)方法執(zhí)行前后記錄時(shí)間戳,可以計(jì)算出方法的執(zhí)行時(shí)間。這對(duì)于性能優(yōu)化和瓶頸識(shí)別非常重要,可以幫助開發(fā)者找出需要優(yōu)化的代碼段。
事務(wù)管理:在目標(biāo)方法執(zhí)行之前開啟一個(gè)事務(wù),并在方法執(zhí)行成功后提交事務(wù);如果方法執(zhí)行失敗,則回滾事務(wù)。這樣可以確保數(shù)據(jù)的一致性和完整性。
緩存管理:在目標(biāo)方法執(zhí)行之前檢查緩存中是否存在所需的數(shù)據(jù);如果存在,則直接返回緩存中的數(shù)據(jù),避免重復(fù)執(zhí)行耗時(shí)的方法;如果不存在,則執(zhí)行方法并將結(jié)果存入緩存中。
權(quán)限檢查:在目標(biāo)方法執(zhí)行之前檢查當(dāng)前用戶是否具有執(zhí)行該方法的權(quán)限;如果沒有權(quán)限,則拋出異?;蚍祷劐e(cuò)誤提示,從而保護(hù)系統(tǒng)的安全性。
異常處理:捕獲目標(biāo)方法拋出的異常,并進(jìn)行統(tǒng)一處理,如記錄異常日志、發(fā)送報(bào)警通知或返回友好的錯(cuò)誤提示給用戶。這可以提高系統(tǒng)的健壯性和用戶體驗(yàn)。
輸入?yún)?shù)校驗(yàn):在目標(biāo)方法執(zhí)行之前對(duì)輸入?yún)?shù)進(jìn)行校驗(yàn),確保參數(shù)的有效性和合法性。如果參數(shù)無效或不合法,則拋出異常或返回錯(cuò)誤提示,避免執(zhí)行無效的操作。
結(jié)果后處理:在目標(biāo)方法執(zhí)行之后對(duì)返回結(jié)果進(jìn)行后處理,如格式化數(shù)據(jù)、轉(zhuǎn)換數(shù)據(jù)類型或添加額外的信息。這可以滿足不同的業(yè)務(wù)需求和數(shù)據(jù)展示要求。
綜上所述,@Around注解在Spring AOP中具有廣泛的應(yīng)用場(chǎng)景,它能夠幫助開發(fā)者在不修改目標(biāo)方法代碼的情況下實(shí)現(xiàn)各種復(fù)雜的功能和邏輯。通過合理地使用@Around注解,可以提高代碼的可讀性、可維護(hù)性和可擴(kuò)展性。
@Around 注解常用場(chǎng)景實(shí)例
權(quán)限校驗(yàn)
以下是一個(gè)使用@Around注解進(jìn)行權(quán)限校驗(yàn)的示例代碼:
@Around("@annotation(authCheck)")
public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
String mustRole = authCheck.mustRole();
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
User loginUser = userService.getLoginUser(request);
if (!loginUser.hasRole(mustRole)) {
throw new AccessDeniedException("用戶沒有權(quán)限執(zhí)行此操作");
}
return joinPoint.proceed(); // 繼續(xù)執(zhí)行目標(biāo)方法
}
在這個(gè)示例中,doInterceptor方法會(huì)在被@AuthCheck注解標(biāo)記的方法執(zhí)行前后運(yùn)行。首先檢查用戶是否有足夠的權(quán)限,如果沒有權(quán)限則拋出異常,否則繼續(xù)執(zhí)行目標(biāo)方法。
日志記錄和性能監(jiān)控
以下是一個(gè)使用@Around注解的具體實(shí)例,該實(shí)例展示了如何在Spring AOP中實(shí)現(xiàn)日志記錄和性能監(jiān)控的功能。
首先,我們需要定義一個(gè)切面類,并在其中使用@Around注解來標(biāo)注環(huán)繞通知方法。
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAndPerformanceAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object logAndMeasureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
// 記錄方法開始執(zhí)行的時(shí)間
long startTime = System.currentTimeMillis();
// 記錄日志:方法開始執(zhí)行
System.out.println("Method " + joinPoint.getSignature().getName() + " is starting with arguments: " + Arrays.toString(joinPoint.getArgs()));
try {
// 執(zhí)行目標(biāo)方法
Object result = joinPoint.proceed();
// 記錄方法執(zhí)行結(jié)束的時(shí)間
long endTime = System.currentTimeMillis();
// 記錄日志:方法執(zhí)行結(jié)束,并輸出執(zhí)行時(shí)間
System.out.println("Method " + joinPoint.getSignature().getName() + " executed in " + (endTime - startTime) + " milliseconds with result: " + result);
// 返回目標(biāo)方法的執(zhí)行結(jié)果
return result;
} catch (Throwable throwable) {
// 記錄異常日志
System.out.println("Exception occurred in method " + joinPoint.getSignature().getName() + ": " + throwable.getMessage());
// 重新拋出異常,以便上層調(diào)用者處理
throw throwable;
}
}
}
在這個(gè)例子中,LoggingAndPerformanceAspect是一個(gè)切面類,它包含了一個(gè)使用@Around注解標(biāo)注的環(huán)繞通知方法logAndMeasureExecutionTime。這個(gè)方法會(huì)在匹配到的方法執(zhí)行之前和之后分別記錄日志,并測(cè)量方法的執(zhí)行時(shí)間。
接下來,我們需要確保Spring容器能夠識(shí)別這個(gè)切面類,并將其應(yīng)用到相應(yīng)的目標(biāo)方法上。通常,這可以通過在Spring配置文件中啟用AOP自動(dòng)代理或者通過@EnableAspectJAutoProxy注解來實(shí)現(xiàn)。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
// 其他Bean定義...
// 確保LoggingAndPerformanceAspect被Spring容器管理
@Bean
public LoggingAndPerformanceAspect loggingAndPerformanceAspect() {
return new LoggingAndPerformanceAspect();
}
}
現(xiàn)在,當(dāng)Spring容器中的任何匹配到切入點(diǎn)表達(dá)式"execution(* com.example.service.*.*(..))"的方法被執(zhí)行時(shí),logAndMeasureExecutionTime環(huán)繞通知都會(huì)被觸發(fā),從而記錄日志和測(cè)量執(zhí)行時(shí)間。
例如,如果你有一個(gè)服務(wù)類MyService,其中有一個(gè)方法doSomething,那么當(dāng)這個(gè)方法被調(diào)用時(shí),你會(huì)在控制臺(tái)看到類似以下的輸出:
Method doSomething is starting with arguments: [...] Method doSomething executed in XXX milliseconds with result: ...
這樣,你就成功地使用@Around注解實(shí)現(xiàn)了日志記錄和性能監(jiān)控的功能。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java中@EnableAutoConfiguration注解使用
在Spring Boot框架中,@EnableAutoConfiguration是一種非常重要的注解,本文就來介紹一下java中@EnableAutoConfiguration注解使用,感興趣的可以了解一下2023-11-11
Spring 開發(fā)過程中Value 注解的使用場(chǎng)景
這篇文章主要介紹了Spring 開發(fā)過程中Value 注解的使用場(chǎng)景,幫助大家更好的理解和使用spring框架,感興趣的朋友可以了解下2020-11-11
maven打生產(chǎn)環(huán)境可執(zhí)行包的實(shí)現(xiàn)
本文主要介紹了maven打生產(chǎn)環(huán)境可執(zhí)行包的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01
計(jì)算機(jī)二級(jí)考試java軟件操作教程 教大家如何學(xué)習(xí)java
如何成為一名知識(shí)豐富的Java程序員,順利通過計(jì)算機(jī)二級(jí)Java考試,這篇文章主要主要教大家如何學(xué)習(xí)java,java的學(xué)習(xí)路線是什么,從何學(xué)起,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
springboot項(xiàng)目不同環(huán)境的配置讀取方式
SpringBoot支持application.properties、application.yml、application.yaml三種配置文件類型,可同時(shí)存在并合并配置,配置文件的讀取優(yōu)先級(jí)為:application.properties > application.yml > application.yaml,不同位置的相同類型配置文件2024-11-11
springboot中縮短一個(gè)url鏈接的實(shí)現(xiàn)
縮短 URL 是現(xiàn)代應(yīng)用程序中常見的需求,通常用于減少長(zhǎng) URL 的長(zhǎng)度,使其更易于分享,URL 縮短服務(wù)的核心思路是將長(zhǎng) URL 映射到一個(gè)唯一的短代碼,本文主要介紹了springboot中縮短一個(gè)url鏈接的實(shí)現(xiàn),感興趣的可以了解一下2024-09-09
mybatis-plus如何修改日志只打印SQL語句不打印查詢結(jié)果
這篇文章主要介紹了mybatis-plus如何修改日志只打印SQL語句不打印查詢結(jié)果問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06

