本文目录导读:

在Java AOP中,控制切面(Aspect)的执行顺序是一个常见需求,我会通过几种不同的方式来说明如何控制切面顺序。
使用 @Order 注解(最常用)
示例代码
// 第一个切面 - 权限校验
@Aspect
@Component
@Order(1) // 数值越小,优先级越高,越先执行
public class PermissionAspect {
@Around("@annotation(permissionCheck)")
public Object checkPermission(ProceedingJoinPoint joinPoint, PermissionCheck permissionCheck) throws Throwable {
System.out.println("【权限切面】开始执行 - Order 1");
// 模拟权限校验
String permission = permissionCheck.value();
System.out.println("检查权限: " + permission);
Object result = joinPoint.proceed();
System.out.println("【权限切面】执行结束");
return result;
}
}
// 第二个切面 - 日志记录
@Aspect
@Component
@Order(2) // 数值较大,优先级较低,后执行
public class LogAspect {
@Around("@annotation(LogRecord)")
public Object logAround(ProceedingJoinPoint joinPoint, LogRecord logRecord) throws Throwable {
System.out.println("【日志切面】开始执行 - Order 2");
System.out.println("记录日志: " + logRecord.value());
Object result = joinPoint.proceed();
System.out.println("【日志切面】执行结束");
return result;
}
}
// 第三个切面 - 事务管理
@Aspect
@Component
@Order(3) // 数值最大,最后执行
public class TransactionAspect {
@Around("@annotation(transactional)")
public Object manageTransaction(ProceedingJoinPoint joinPoint, Transactional transactional) throws Throwable {
System.out.println("【事务切面】开始执行 - Order 3");
System.out.println("开始事务");
try {
Object result = joinPoint.proceed();
System.out.println("提交事务");
return result;
} catch (Exception e) {
System.out.println("回滚事务");
throw e;
}
}
}
// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface PermissionCheck {
String value();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface LogRecord {
String value();
}
执行顺序说明
// 业务方法
@Service
public class UserService {
@PermissionCheck("admin")
@LogRecord("查询用户信息")
@Transactional
public User getUserById(Long id) {
System.out.println("【业务方法】执行查询");
return new User(id, "测试用户");
}
}
执行顺序:
- 权限切面(@Order(1))先执行
- 日志切面(@Order(2))后执行
- 事务切面(@Order(3))最后执行
实现 Ordered 接口
@Aspect
@Component
public class FirstAspect implements Ordered {
@Override
public int getOrder() {
return 1; // 优先级最高
}
@Around("execution(* com.example.*.*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("第一个切面执行");
return joinPoint.proceed();
}
}
@Aspect
@Component
public class SecondAspect implements Ordered {
@Override
public int getOrder() {
return 2;
}
@Around("execution(* com.example.*.*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("第二个切面执行");
return joinPoint.proceed();
}
}
在配置类中统一管理顺序
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
@Bean
@Order(1)
public PermissionAspect permissionAspect() {
return new PermissionAspect();
}
@Bean
@Order(2)
public LogAspect logAspect() {
return new LogAspect();
}
}
复杂场景:同一连接点多个切面
// 更详细的示例,展示 Around 通知的执行流程
@Aspect
@Component
@Order(1)
public class FirstAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object firstAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("【第一切面】前置逻辑 - 开始执行");
System.out.println("【第一切面】当前时间: " + System.currentTimeMillis());
try {
Object result = joinPoint.proceed();
System.out.println("【第一切面】后置逻辑 - 执行成功");
return result;
} catch (Exception e) {
System.out.println("【第一切面】异常处理 - 捕捉异常");
throw e;
} finally {
System.out.println("【第一切面】最终处理 - 清理资源");
}
}
}
@Aspect
@Component
@Order(2)
public class SecondAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object secondAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("【第二切面】前置逻辑 - 开始执行");
System.out.println("【第二切面】方法参数: " + Arrays.toString(joinPoint.getArgs()));
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
System.out.println("【第二切面】后置逻辑 - 方法执行耗时: " + (endTime - startTime) + "ms");
return result;
}
}
注意点与最佳实践
执行顺序规则
// 对于 Around 通知,执行顺序如下: // @Order(1) 的前置逻辑 // @Order(2) 的前置逻辑 // 实际方法调用 // @Order(2) 的后置逻辑 // @Order(1) 的后置逻辑 // 形象比喻:就像层层包装 // 最外层包装(Order最小)先开始,最后结束 // 最内层包装(Order最大)后开始,先结束
最佳实践建议
@Component
@Order(Ordered.HIGHEST_PRECEDENCE) // 最高优先级
public class PerformanceMonitorAspect {
// 性能监控应该在最外层
}
@Component
@Order(Ordered.LOWEST_PRECEDENCE) // 最低优先级
public class SecurityCheckAspect {
// 安全检查应该在最后执行
}
常见的切面顺序建议
- 缓存切面 - 最外层(@Order(1))
- 日志切面 - 第二层(@Order(2))
- 事务切面 - 第三层(@Order(3))
- 校验切面 - 最内层(@Order(4))
通过合理控制切面顺序,可以更好地组织和管理横切关注点,确保系统行为符合预期。