在AspectJ的切面编程场景中,多个切面可能会作用于同一个连接点,当某个切面的逻辑校验不通过或者已经完成了所有需要的处理时,我们往往需要阻止后续切面的执行,避免不必要的逻辑运行或者错误的结果产生。AspectJ本身提供了多种机制来实现这个需求,下面我们逐一介绍具体的实现方式。

方式一:通过切面优先级控制执行顺序
AspectJ中切面的执行顺序可以通过设置优先级来决定,优先级高的切面会先执行,其around通知中如果不调用proceed()方法,就可以直接阻止后续所有优先级更低的切面以及目标方法的执行。我们可以通过@Order注解或者实现Ordered接口来设置切面的优先级,数值越小优先级越高。
下面是一个使用@Order注解设置切面优先级的示例:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
// 优先级为1,优先级最高
@Aspect
@Component
@Order(1)
public class FirstAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object aroundFirst(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("第一个切面执行前置逻辑");
// 不调用proceed()方法,直接返回,后续切面和目标方法都不会执行
// return joinPoint.proceed(); 如果调用这行,才会继续执行后续逻辑
return null;
}
}
// 优先级为2,优先级低于第一个切面
@Aspect
@Component
@Order(2)
public class SecondAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object aroundSecond(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("第二个切面执行逻辑");
return joinPoint.proceed();
}
}
方式二:在around通知中根据条件控制执行
除了直接不调用proceed()方法,我们还可以在around通知中根据业务条件判断是否需要继续执行后续逻辑,这种方式更加灵活,适合需要根据运行时参数决定是否阻止后续切面执行的场景。
示例代码如下:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class CheckAspect {
@Around("execution(* com.example.service.UserService.login(..))")
public Object checkLogin(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
// 假设第一个参数是用户名,校验用户名是否为空
if (args.length > 0 && args[0] == null) {
System.out.println("用户名为空,阻止后续执行");
return "用户名不能为空";
}
// 校验通过,继续执行后续切面和目标方法
return joinPoint.proceed();
}
}
方式三:通过抛出异常中断执行链
如果在切面中抛出异常,并且没有在切面内部捕获,那么后续的切面和目标方法也不会执行,异常会向上抛出给调用方。这种方式适合校验失败需要明确告知调用方错误的场景。
示例代码如下:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AuthAspect {
@Around("execution(* com.example.service.*.delete*(..))")
public Object checkAuth(ProceedingJoinPoint joinPoint) throws Throwable {
// 模拟权限校验,假设当前用户没有删除权限
boolean hasAuth = false;
if (!hasAuth) {
throw new RuntimeException("没有删除权限,操作被阻止");
}
return joinPoint.proceed();
}
}
不同方式的适用场景对比
我们可以通过下面的表格来对比三种方式的适用场景:
| 实现方式 | 适用场景 | 注意事项 |
|---|---|---|
| 设置切面优先级不调用proceed() | 固定需要某个切面优先执行且执行后不需要后续逻辑的场景 | 优先级设置需要全局统一规划,避免混乱 |
| around通知中条件判断 | 需要根据运行时参数动态决定是否阻止后续执行的场景 | 条件判断逻辑需要清晰,避免遗漏正常执行流程 |
| 抛出异常中断执行链 | 校验失败需要明确错误信息的场景 | 异常需要被上层合理捕获处理,避免导致系统异常 |
注意事项
- 如果在
around通知中调用了proceed()方法,就一定要确保返回该方法的返回值,否则可能会导致目标方法的返回值丢失。 - 多个切面的优先级设置需要合理,避免因为优先级混乱导致执行顺序不符合预期。
- 使用异常中断执行链时,要确保异常类型是调用方能够识别的,避免抛出过于通用的异常类型。
需要注意的是,AspectJ的切面执行顺序不仅和@Order注解有关,在没有设置优先级的情况下,切面的加载顺序也可能会影响执行顺序,所以建议显式设置优先级来保证执行顺序可控。
AspectJ阻止Aspect执行切面优先级around_通知切面执行控制修改时间:2026-07-11 14:00:35