核心是定义注解、编写@aspect切面类并启用aop支持;spring boot默认使用基于代理的spring aop,添加spring-boot-starter-aop依赖后,通过@target、@retention定义运行时注解,用@around等通知绑定@annotation切点,即可实现方法级拦截与增强。

在 Spring Boot 中使用 AspectJ 实现自定义注解切面,核心是:定义注解 + 编写切面类 + 启用 AOP 支持。Spring Boot 默认集成的是基于代理的 Spring AOP(不支持 private 方法、构造器等),若需完整 AspectJ 功能(如拦截任意方法、字段访问),需额外引入 spring-boot-starter-aop 并配置 AspectJ 编译或加载时织入(LTW)。但绝大多数业务场景下,用 Spring AOP + 自定义注解已足够。
1. 添加依赖(确保 AOP 支持)
Spring Boot 2.6+ 默认启用 CGLIB 代理(可代理类方法),但仍需显式引入 AOP starter:
<dependency><groupid>org.springframework.boot</groupid><artifactid>spring-boot-starter-aop</artifactid></dependency>
注意:无需额外引入 aspectjweaver(starter 已包含);若要用 @AspectJ 风格(非 schema-based),也不需要额外配置——Spring Boot 自动识别 @Aspect 类。
2. 定义自定义注解
创建一个运行时保留、可作用于方法的注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogExecutionTime {
String value() default "";
}-
必须加
@Retention(RUNTIME):否则切面无法在运行时读取注解 -
推荐加
@Documented:让 Javadoc 包含该注解说明 - 参数按需设计,比如增加
level()控制日志级别,或includeArgs()决定是否打印入参
3. 编写切面类
使用 @Aspect 和 @Component 声明切面,并通过 @Around 或 @Before 等通知绑定自定义注解:
@Aspect
@Component
public class LoggingAspect {
<pre class="brush:java;toolbar:false;">private static final Logger log = LoggerFactory.getLogger(LoggingAspect.class);
@Around("@annotation(logExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
long start = System.currentTimeMillis();
String methodName = joinPoint.getSignature().toShortString();
try {
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - start;
log.info("{} executed in {} ms", methodName, duration);
return result;
} catch (Throwable ex) {
long duration = System.currentTimeMillis() - start;
log.error("{} failed after {} ms: {}", methodName, duration, ex.getMessage(), ex);
throw ex;
}
}}
-
切点表达式
@annotation(logExecutionTime):匹配所有标注了@LogExecutionTime的方法 -
通知方法参数顺序很重要:第一个是
ProceedingJoinPoint,第二个起是绑定的注解对象(名字要和切点中一致) -
必须调用
joinPoint.proceed()才会执行原方法;不调则“拦截”生效(如权限校验直接 return)
4. 在业务方法上使用注解
直接加在 Controller、Service 或 Repository 方法上即可:
@RestController
public class UserController {
<pre class="brush:java;toolbar:false;">@LogExecutionTime
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
// 模拟耗时操作
try { Thread.sleep(100); } catch (InterruptedException e) {}
return new User(id, "Alice");
}}
启动应用后访问该接口,控制台将输出类似:getUser(Long) executed in 102 ms
如果需要更高级能力(如拦截 private 方法、构造器、字段赋值),就得切换到完整 AspectJ —— 此时需启用 Load-Time Weaving(LTW),添加 -javaagent:/path/to/aspectjweaver.jar JVM 参数,并在配置类中加 @EnableLoadTimeWeaving。但对 95% 的日志、事务、权限等场景,Spring AOP 已完全够用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











