Spring 切面执行链的实现示例
在实际应用中,一个方法通常会被多个切面拦截。例如,我们有一个方法,既需要记录其执行日志,又需要应用一些安全限制。这类职责通常由专门的切面来处理,因此在该场景下,会有两个切面作用于同一个方法的执行过程。同时使用多个切面没有任何问题,但有时切面的执行顺序非常重要,因为有些切面会控制切入点方法的执行,比如鉴权的切面在鉴权失败后便不会继续执行切入点方法。这种情况下其他切面可能就没有机会执行了。
// 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());
// 定义日志环绕通知
@Around("@annotation(dev.xyz.annotation.ToLog)")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 切入点方法执行前执行
logger.info("Logging before method: " + joinPoint.getSignature().getName());
// 执行切入点方法
Object result = joinPoint.proceed();
// 切入点方法执行后执行
logger.info("Logging after method: " + joinPoint.getSignature().getName());
// 修改切入点方法的返回值
return result;
}
}
// SecurityAspect.java
// 定义鉴权切面
@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.");
// 这里模拟鉴权失败
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 配置,创建两个切面 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 方法中进行测试
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");
}
}这里先执行了 SecurityAspect 切面,因为鉴权失败,所以 LoggingAspect 切面不会执行。

这种情况下,可以使用 @Order 注解来控制切面执行的顺序,给注解传递一个数值作为参数,数值越小越先执行,现在给切面类添加上 @Order 注解,让 LoggingAspect 先于 SecurityAspect 执行:
// LoggingAspect.java
// 定义日志切面
@Aspect
@Order(1)
public class LoggingAspect {
// 这里的代码不变
// ...
}
// SecurityAspect.java
// 定义鉴权切面
@Aspect
public class SecurityAspect {
// 这里的代码不变
// ...
}现在结果变的不一样了,先执行了 LoggingAspect 切面:

如果存在多个 @Order 数值一样的切面,这时的结果又和不使用 @Order 一样了。不使用 @Order 注解的切面永远晚于使用 @Order 注解的切面执行。
到此这篇关于Spring 切面执行链的实现示例的文章就介绍到这了,更多相关Spring 切面执行链内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Java遍历输出指定目录、树形结构所有文件包括子目录下的文件
这篇文章主要介绍了Java遍历输出指定目录、树形结构下的所有文件包括子目录中的文件,需要的朋友可以参考下2015-07-07
Java实现int、long、Integer、Long之间的相互转换
本文主要介绍了Java实现int、long、Integer、Long之间的相互转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2023-08-08
Java中CompletableFuture四种调用模式的实现
CompletableFuture有就地执行、异步执行等三种模式,就地执行适合轻量级任务,但可能导致线程阻塞,异步执行有上下文切换开销,本文介绍了第四种调用模式,解决了以上问题2025-08-08
在Java和Java Web中放置图片、视频、音频、图像文件的方法
在Java软件中放置图片,通常涉及将图片文件(如JPEG、PNG等)作为资源包含在我们的项目中,并在代码中通过适当的方式引用这些资源,这可以通过多种方式实现,但最常见的是在Java桌面应用(如Swing或JavaFX)或Web应用(如Servlet/JSP)中2024-11-11


最新评论