AOPDEMO:Spring Boot AOP 切面示例
Spring Boot AOP 基础示例,演示 @Aspect 和切入点表达式。
AOPDEMO:Spring Boot AOP 切面编程示例
什么是 AOP
AOP(面向切面编程)的核心思想是:在不修改业务代码的前提下,在方法执行前后插入横切逻辑。业务代码不需要知道切面的存在,切面也不侵入业务逻辑。
Spring AOP 基于动态代理实现:
- JDK 动态代理:目标类实现接口时使用,代理接口方法
- CGLIB 代理:目标类没有接口时使用,生成子类代理
这个区别在实际工作中影响很大——如果你用 @Transactional 注解在非接口方法上,默认走 CGLIB,需要额外配置才能生效。
通知类型
Spring 支持 6 种通知类型:
@Aspect
@Component
public class LoggingAspect {
// @Before:方法执行前
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint jp) {
log.info("方法调用: {}", jp.getSignature());
}
// @After:方法执行后(无论成功还是异常)
@After("execution(* com.example.service.*.*(..))")
public void logAfter() {
log.info("方法结束");
}
// @AfterReturning:方法成功返回后
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void logReturn(Object result) {
log.info("返回结果: {}", result);
}
// @AfterThrowing:方法抛出异常后
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
public void logException(Exception ex) {
log.error("方法异常", ex);
}
// @Around:最强大的通知,可完全控制方法执行
@Around("@annotation(com.example.annotation.Monitor)")
public Object measureTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
return pjp.proceed(); // 执行目标方法
} finally {
long cost = System.currentTimeMillis() - start;
log.info("执行耗时: {}ms", cost);
if (cost > 1000) {
// 超过 1 秒的慢查询告警
alertService.sendSlowQueryAlert(pjp.getSignature().toShortString(), cost);
}
}
}
}
@Around 的应用场景
@Around 是唯一一个可以完全控制方法调用的通知类型——可以在目标方法前/后插入逻辑、修改返回值、捕获异常、甚至跳过方法执行。常用场景:
- 性能监控:记录方法执行时间,慢查询告警
- 缓存:先查缓存,命中直接返回,不执行方法
- 重试:方法异常时自动重试
- 限流:超出阈值直接返回错误
@Around("@annotation(rateLimiter)")
public Object rateLimit(ProceedingJoinPoint pjp, RateLimiter rateLimiter) throws Throwable {
String key = rateLimiter.key();
if (!redisTemplate.opsForValue().setIfAbsent(key, "1", 1, TimeUnit.SECONDS)) {
throw new RateLimitException("请求太频繁");
}
return pjp.proceed();
}
切入点表达式
execution(修饰符 返回类型 包.类.方法(参数))
常用模式:
| 表达式 | 匹配目标 |
|---|---|
execution(* com.example.service.*.*(..)) | service 包下所有方法 |
execution(* com.example..*.*(..)) | com.example 及其子包 |
@annotation(com.example.annotation.Monitor) | 标注了 @Monitor 的方法 |
within(com.example.service.*) | service 包下的所有类 |
最大坑:自调用
同类中方法 A 调用方法 B,B 上的 AOP 不生效:
@Service
public class UserService {
@Transactional
public void createUser(User user) { ... }
public void batchCreate(List<User> users) {
for (User user : users) {
this.createUser(user); // @Transactional 不生效!
}
}
}
原因:this 指向原始对象,不是代理对象。AOP 增强只对代理对象上的方法调用生效。
解决方案:
// 方法1:注入自身代理
@Service
public class UserService {
@Autowired
private UserService self; // 注入代理对象
public void batchCreate(List<User> users) {
for (User user : users) {
self.createUser(user); // 通过代理调用,AOP 生效
}
}
}
// 方法2:使用 AopContext
public void batchCreate(List<User> users) {
for (User user : users) {
((UserService) AopContext.currentProxy()).createUser(user);
}
}
实际应用
在我的项目中,AOP 的主要应用:
- 接口性能监控:
@Around记录所有 API 接口的响应时间,超过阈值自动告警 - Redis 缓存:
@Cacheable内置基于 AOP 实现 - 参数校验:
@Before对敏感接口做二次校验 - 操作日志:记录关键业务操作(谁做了什么、参数、结果)