You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用AspectJ控制切面执行顺序并按需阻止后续切面运行?

AspectJ 实现切面执行控制方案

针对你的需求,我们可以通过切面执行优先级控制、异常中断和通知类型选择来实现,具体方案如下:

核心思路

  1. 强制监控逻辑始终执行:通过 try-finally 包裹监控切面的执行逻辑,确保无论后续是否抛出异常,监控代码都会完成。
  2. 控制切面执行顺序:指定监控切面先执行,再执行权限校验切面,最后执行审计切面。
  3. 权限校验不通过时中断流程:权限切面校验失败直接抛出异常,中断后续审计切面的执行。
  4. 审计逻辑仅在权限通过时触发:利用方法正常返回的通知类型,确保只有权限校验通过、方法正常执行时才触发审计。

代码实现

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 05:15:45