注解定义是AOP切面识别的入口,必须声明@Retention(RetentionPolicy.RUNTIME)和@Target(ElementType.METHOD),切面通过@annotation(全限定名)匹配并执行@Before或@Around等通知,目标方法须为Spring管理的public Bean且调用经代理。

注解定义是 AOP 切面识别的入口
要让 AOP 知道“在哪些方法上执行日志或权限检查”,得先自定义注解,标记目标方法。注解本身不带逻辑,只起标识作用,但必须声明为 @Retention(RetentionPolicy.RUNTIME),否则运行时无法被切面读取。
例如权限注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequireRole {
String value() default "USER";
}
日志注解可更轻量:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {}
注意:不需要实现类,也不需要继承——纯元数据标记。
立即学习“Java免费学习笔记(深入)”;
切面类用 @Around 或 @Before 绑定注解逻辑
Spring AOP 通过切点表达式(pointcut)匹配带指定注解的方法,再用通知(advice)插入逻辑。权限拦截适合用 @Before 阻断非法调用;日志记录常用 @Around 测量耗时并捕获返回值/异常。
示例:权限拦截切面
@Aspect
@Component
public class AuthorizationAspect {
@Before("@annotation(requireRole)")
public void checkPermission(JoinPoint joinPoint, RequireRole requireRole) {
String requiredRole = requireRole.value();
String currentUserRole = getCurrentUserRole(); // 从 SecurityContext 或 ThreadLocal 获取
if (!currentUserRole.equals(requiredRole)) {
throw new AccessDeniedException("Access denied: requires role " + requiredRole);
}
}
private String getCurrentUserRole() {
return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
.map(Authentication::getAuthorities)
.map(Collection::stream)
.flatMap(s -> s.map(GrantedAuthority::getAuthority))
.findFirst()
.orElse("ANONYMOUS");
}
}
日志切面兼顾性能与可读性
记录方法执行时间、参数和结果,但避免打印敏感字段(如密码)、大对象或 toString() 可能阻塞的内容。
- 用 StopWatch 或 System.nanoTime() 计算耗时,比 new Date() 更精准
- 参数建议只打简单类型(String、Number、枚举),复杂对象转 JSON 前加长度限制或白名单字段
- 异常统一捕获并记录堆栈,但生产环境避免全量打印,可只记异常类名+消息
- 日志级别按场景区分:入口方法用 INFO,内部服务调用用 DEBUG
确保 AOP 生效的关键配置
Spring Boot 默认开启 AOP,但仍需确认几点:
- 项目依赖包含 spring-boot-starter-aop(Maven 中检查是否引入)
- 切面类被 Spring 扫描到(加 @Component 或显式 @Bean 注册)
- 目标方法必须是 Spring 管理的 Bean 中的 public 方法(private / final / static 方法无法代理)
- 避免在同一个类中调用本类带注解的方法——这会绕过代理,AOP 不生效(应改为注入自身 Bean 调用)
若需对非 Spring Bean 或 private 方法增强,需改用 AspectJ 编译时织入,而非 Spring AOP 的运行时代理。


















