@around是唯一能阻断方法执行的aop通知,通过proceedingjoinpoint.proceed()控制是否调用目标方法;@before和@after无法中断流程,权限校验必须在proceed前抛异常。

@Around 拦截必须用环绕通知,不是 @Before 或 @After
Spring AOP 中真正能做权限放行/阻断的只有 @Around。它拿到的是 ProceedingJoinPoint,可以决定是否调用 joinPoint.proceed();而 @Before 只能执行前置逻辑,无法阻止方法执行;@After 更是在方法已结束之后才触发,此时抛异常也晚了。
- 权限校验失败时,必须在
joinPoint.proceed()之前 throw 异常(如AccessDeniedException),否则业务方法照常执行 - 不要试图在
@Before里 throw 异常来“中断”流程——Spring AOP 不会因此跳过原方法 - 若需记录执行耗时或返回结果,
@Around也能统一包裹,比组合多个通知更简洁
PermissionCheck 注解必须带 @Retention(RetentionPolicy.RUNTIME)
自定义注解若在运行期被 @Around("@annotation(permissionCheck)") 匹配,就必须保留到运行时。常见错误是只加了 @Retention(RetentionPolicy.CLASS) 或漏写 @Retention(默认为 SOURCE),导致切面根本找不到该注解。
- 缺少
@Retention(RetentionPolicy.RUNTIME)→ 切面匹配失败,方法被静默放过 -
@Target至少要包含ElementType.METHOD,否则无法标注在方法上 - 如果还想支持类级别统一控制,额外加上
ElementType.TYPE
authService.hasPermission() 调用前必须确保上下文可用
权限判断依赖当前用户身份,而 Spring Security 的 SecurityContextHolder.getContext().getAuthentication() 或自研的 AuthService.getCurrentUserId(request) 都要求请求上下文存在。常见失效场景包括:
- 在异步线程(如
@Async方法)中调用被切面的方法 →RequestContextHolder为空,getCurrentUserId()抛IllegalStateException - 单元测试未模拟
ServletRequestAttributes→RequestContextHolder.currentRequestAttributes()返回 null - Filter 链顺序错误,认证信息未提前注入(如自定义 JWT Filter 放在 Spring Security Filter 之后)
建议在切面开头加空值防护:
ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
if (attrs == null || attrs.getRequest() == null) {
throw new IllegalStateException("No HTTP request context available");
}
@Aspect 类必须被 Spring 容器管理且启用 AOP
即使写了 @Aspect 和 @Component,若没开启 AOP 支持,切面不会生效。Spring Boot 2.6+ 默认启用,但老项目或手动配置时容易遗漏:
- 确保引入了
spring-boot-starter-aop(含aspectjweaver) - 检查是否误加了
@EnableAspectJAutoProxy(proxyTargetClass = false)却让目标类没实现接口 → 导致 JDK 代理失败,CGLIB 未启用 - 若目标方法是
private或final,AOP 无法代理(CGLIB 也不支持 final 方法) - 切面类不能是
new出来的对象,必须由 Spring 容器实例化(否则@Autowired的authService为 null)
最常被忽略的一点:权限判断逻辑本身不该依赖被代理方法的参数,除非你显式从 joinPoint.getArgs() 提取并传入 hasPermission() —— 否则像“删除 ID 为 X 的用户”这类细粒度权限,光靠注解字符串 "user:delete" 是不够的,得结合运行时参数做二次校验。










