Spring 切面執(zhí)行鏈的實(shí)現(xiàn)示例
在實(shí)際應(yīng)用中,一個(gè)方法通常會(huì)被多個(gè)切面攔截。例如,我們有一個(gè)方法,既需要記錄其執(zhí)行日志,又需要應(yīng)用一些安全限制。這類職責(zé)通常由專門的切面來(lái)處理,因此在該場(chǎng)景下,會(huì)有兩個(gè)切面作用于同一個(gè)方法的執(zhí)行過(guò)程。同時(shí)使用多個(gè)切面沒(méi)有任何問(wèn)題,但有時(shí)切面的執(zhí)行順序非常重要,因?yàn)橛行┣忻鏁?huì)控制切入點(diǎn)方法的執(zhí)行,比如鑒權(quán)的切面在鑒權(quán)失敗后便不會(huì)繼續(xù)執(zhí)行切入點(diǎn)方法。這種情況下其他切面可能就沒(méi)有機(jī)會(huì)執(zhí)行了。
// UserService.java
@Service
public class UserService {
private final Logger logger = Logger.getLogger(UserService.class.getName());
@ToLog
public String getUser(String username) throws Exception {
logger.info("getUser method called with username: " + username);
return username;
}
}
// LoggingAspect.java
// 定義日志切面
@Aspect
public class LoggingAspect {
// 定義日志記錄器
private final Logger logger = Logger.getLogger(LoggingAspect.class.getName());
// 定義日志環(huán)繞通知
@Around("@annotation(dev.xyz.annotation.ToLog)")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 切入點(diǎn)方法執(zhí)行前執(zhí)行
logger.info("Logging before method: " + joinPoint.getSignature().getName());
// 執(zhí)行切入點(diǎn)方法
Object result = joinPoint.proceed();
// 切入點(diǎn)方法執(zhí)行后執(zhí)行
logger.info("Logging after method: " + joinPoint.getSignature().getName());
// 修改切入點(diǎn)方法的返回值
return result;
}
}
// SecurityAspect.java
// 定義鑒權(quán)切面
@Aspect
public class SecurityAspect {
private final Logger logger = Logger.getLogger(SecurityAspect.class.getName());
@Around("@annotation(dev.xyz.annotation.ToLog)")
public Object checkSecurity(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("Security check performed.");
// 這里模擬鑒權(quán)失敗
if (joinPoint.getArgs()[0].equals("Mark")) {
throw new Exception("Security check failed.");
}
Object result = joinPoint.proceed();
logger.info("Security check passed.");
return result;
}
}
// ProjectConfig.java
// Spring 配置,創(chuàng)建兩個(gè)切面 bean
@Configuration
@ComponentScan(basePackages = "dev.xyz.service")
@EnableAspectJAutoProxy
public class ProjectConfig {
@Bean
SecurityAspect securityAspect() {
return new SecurityAspect();
}
@Bean
LoggingAspect loggingAspect() {
return new LoggingAspect();
}
}
// Main.java
// 在 main 方法中進(jìn)行測(cè)試
public class Main {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProjectConfig.class);
UserService userService = context.getBean(UserService.class);
userService.getUser("Mark");
}
}這里先執(zhí)行了 SecurityAspect 切面,因?yàn)殍b權(quán)失敗,所以 LoggingAspect 切面不會(huì)執(zhí)行。

這種情況下,可以使用 @Order 注解來(lái)控制切面執(zhí)行的順序,給注解傳遞一個(gè)數(shù)值作為參數(shù),數(shù)值越小越先執(zhí)行,現(xiàn)在給切面類添加上 @Order 注解,讓 LoggingAspect 先于 SecurityAspect 執(zhí)行:
// LoggingAspect.java
// 定義日志切面
@Aspect
@Order(1)
public class LoggingAspect {
// 這里的代碼不變
// ...
}
// SecurityAspect.java
// 定義鑒權(quán)切面
@Aspect
public class SecurityAspect {
// 這里的代碼不變
// ...
}現(xiàn)在結(jié)果變的不一樣了,先執(zhí)行了 LoggingAspect 切面:

如果存在多個(gè) @Order 數(shù)值一樣的切面,這時(shí)的結(jié)果又和不使用 @Order 一樣了。不使用 @Order 注解的切面永遠(yuǎn)晚于使用 @Order 注解的切面執(zhí)行。
到此這篇關(guān)于Spring 切面執(zhí)行鏈的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Spring 切面執(zhí)行鏈內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring AOP 切面@Around注解的用法說(shuō)明
- 解決springboot的aop切面不起作用問(wèn)題(失效的排查)
- spring使用aspect注解切面不起作用的排查過(guò)程及解決
- Spring AOP面向切面編程實(shí)現(xiàn)原理方法詳解
- 詳解spring面向切面aop攔截器
- springboot切面添加日志功能實(shí)例詳解
- 詳解spring切面使用傳遞給被通知方法的參數(shù)
- 詳解Spring AOP 實(shí)現(xiàn)“切面式”valid校驗(yàn)
- springboot配置aop切面日志打印過(guò)程解析
- Spring AOP使用之多切面運(yùn)行順序
相關(guān)文章
SpringBoot 項(xiàng)目如何在tomcat容器中運(yùn)行的實(shí)現(xiàn)方法
這篇文章主要介紹了SpringBoot 項(xiàng)目如何在tomcat容器中運(yùn)行的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
SpringBoot整合SpringDataRedis的示例代碼
這篇文章主要介紹了SpringBoot整合SpringDataRedis的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
解析SpringBoot中@Autowire注解的實(shí)現(xiàn)原理
在開(kāi)發(fā)Java項(xiàng)目時(shí),依賴注入是一種常見(jiàn)的實(shí)現(xiàn)方式,SpringBoot框架通過(guò)@Autowired注解來(lái)實(shí)現(xiàn)依賴注入的功能,本文將介紹SpringBoot中 Autowired注解實(shí)現(xiàn)的原理2023-06-06
spring boot使用@Async異步注解的實(shí)現(xiàn)原理+源碼
通常我們都是采用多線程的方式來(lái)實(shí)現(xiàn)上述業(yè)務(wù)功能,但spring 提供更優(yōu)雅的方式來(lái)實(shí)現(xiàn)上述功能,就是@Async 異步注解,在方法上添加@Async,spring就會(huì)借助AOP,異步執(zhí)行方法,接下來(lái)通過(guò)本文給大家介紹spring boot異步注解的相關(guān)知識(shí),一起看看吧2021-06-06
從HelloWorld和文檔注釋開(kāi)始入門Java編程
這篇文章主要介紹了從HelloWorld和文檔注釋開(kāi)始入門Java編程,涉及到Javadoc工具的使用,需要的朋友可以參考下2015-10-10
Java實(shí)現(xiàn)簡(jiǎn)單抽獎(jiǎng)功能界面
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)單抽獎(jiǎng)功能界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11
關(guān)于JDK15的新特性之TextBlocks文本塊的引入和使用
這篇文章主要介紹了關(guān)于JDK15的新特性之文本塊的引入和使用,如果具有一種語(yǔ)言學(xué)機(jī)制,可以比多行文字更直觀地表示字符串,而且可以跨越多行,而且不會(huì)出現(xiàn)轉(zhuǎn)義的視覺(jué)混亂,那么這將提高廣泛Java類程序的可讀性和可寫性,需要的朋友可以參考下2023-07-07
java實(shí)現(xiàn)電腦定時(shí)關(guān)機(jī)的方法
這篇文章主要介紹了java實(shí)現(xiàn)電腦定時(shí)關(guān)機(jī)的方法,首先通過(guò)java注冊(cè)windows服務(wù)程序,再以一個(gè)簡(jiǎn)單的java程序?qū)崿F(xiàn)定時(shí)關(guān)機(jī)的功能,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-11-11

