如何用AspectJ控制切面执行顺序并按需阻止后续切面运行?
AspectJ 实现切面执行控制方案
针对你的需求,我们可以通过切面执行优先级控制、异常中断和通知类型选择来实现,具体方案如下:
核心思路
- 强制监控逻辑始终执行:通过
try-finally包裹监控切面的执行逻辑,确保无论后续是否抛出异常,监控代码都会完成。 - 控制切面执行顺序:指定监控切面先执行,再执行权限校验切面,最后执行审计切面。
- 权限校验不通过时中断流程:权限切面校验失败直接抛出异常,中断后续审计切面的执行。
- 审计逻辑仅在权限通过时触发:利用方法正常返回的通知类型,确保只有权限校验通过、方法正常执行时才触发审计。
代码实现
1. 定义切面执行优先级
通过 @DeclarePrecedence 注解直接指定切面执行顺序,或者实现 Ordered 接口设置优先级(两种方式二选一即可)。
方式一:使用 @DeclarePrecedence
@Aspect public class MonitoringAspect { // 声明切面执行顺序:监控 → 权限 → 审计 @DeclarePrecedence("MonitoringAspect, SecuredAspect, AuditAspect") private static final String PRECEDENCE = ""; @Around("@annotation(com.example.Monitored)") public Object monitor(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); try { // 继续执行后续切面和目标方法 return joinPoint.proceed(); } finally { // 无论是否异常,都会执行监控收尾逻辑 long elapsedTime = System.currentTimeMillis() - startTime; System.out.println("方法[" + joinPoint.getSignature().getName() + "]执行耗时:" + elapsedTime + "ms"); } } }
方式二:实现 Ordered 接口
@Aspect public class MonitoringAspect implements Ordered { @Override public int getOrder() { return 1; // 数值越小,优先级越高 } // 监控逻辑同上述代码 } @Aspect public class SecuredAspect implements Ordered { @Override public int getOrder() { return 2; } // 权限校验逻辑见下文 } @Aspect public class AuditAspect implements Ordered { @Override public int getOrder() { return 3; } // 审计逻辑见下文 }
2. 权限校验切面
在监控之后执行权限校验,失败则抛出运行时异常中断流程:
@Aspect public class SecuredAspect { @Around("@annotation(com.example.Secured)") public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable { // 获取方法上的@Secured注解 Secured securedAnno = joinPoint.getSignature().getDeclaringType() .getMethod(joinPoint.getSignature().getName()) .getAnnotation(Secured.class); Permission requiredPerm = securedAnno.value(); // 模拟权限检查逻辑(替换为实际业务逻辑) if (!currentUserHasPermission(requiredPerm)) { throw new SecurityException("权限不足:缺少" + requiredPerm + "权限"); } // 权限通过,继续执行后续切面和目标方法 return joinPoint.proceed(); } // 实际权限检查方法 private boolean currentUserHasPermission(Permission permission) { // 示例:仅当权限为SOME_PERMISSION时通过 return Permission.SOME_PERMISSION.equals(permission); } }
3. 审计切面
使用 @AfterReturning 通知,仅在方法正常返回(权限校验通过)时执行审计:
@Aspect public class AuditAspect { @AfterReturning(pointcut = "@annotation(com.example.Audited)", returning = "result") public void audit(JoinPoint joinPoint, Object result) { // 审计逻辑:记录操作人、方法、结果等 String methodName = joinPoint.getSignature().getName(); System.out.println("审计日志:方法[" + methodName + "]执行完成,返回结果:" + result); } }
方案验证
- 监控逻辑:无论权限校验是否通过,
finally块中的监控代码都会执行,满足需求1。 - 权限校验顺序:通过优先级控制,权限切面在监控之后执行,失败则抛异常中断流程,满足需求2。
- 审计逻辑:仅当方法正常返回(权限通过)时,
@AfterReturning通知才会触发,满足需求3。
内容的提问来源于stack exchange,提问作者Rinat
相关产品推荐
相关产品推荐

