1. 代理失效:内部方法调用陷阱
最常见的问题之一是在同类内部方法调用时AOP失效:
@Service
public class UserService {
public void createUser(User user) {
// 此注解会生效
validateUser(user);
// 内部调用不会触发AOP
internalUpdate(user);
}
@Transactional
public void internalUpdate(User user) {
// 此处事务注解不会生效
userRepository.save(user);
}
}
解决方案:通过自注入或拆分Bean解决
@Service
@AllArgsConstructor
public class UserService {
private final UserService self;
public void createUser(User user) {
self.internalUpdate(user); // 通过代理对象调用
}
}
2. 切面优先级混乱
多个切面执行顺序不可控会导致业务逻辑错误:
@Aspect
@Order(1)
public class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object log(ProceedingJoinPoint pjp) throws Throwable {
// 日志逻辑
}
}
@Aspect
@Order(2)
public class TransactionAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object manageTransaction(ProceedingJoinPoint pjp) throws Throwable {
// 事务逻辑
}
}
3. 错误的重抛异常模式
异常处理不当会导致异常信息丢失:
// 错误做法
try {
return pjp.proceed();
} catch (Exception e) {
log.error("操作失败", e);
throw new Exception("操作失败"); // 原始异常信息丢失
}
// 正确做法
try {
return pjp.proceed();
} catch (BusinessException e) {
log.error("业务操作失败", e);
throw e; // 保留原始异常
} catch (Exception e) {
log.error("系统异常", e);
throw new BusinessException("操作失败", e); // 包装原始异常
}
4. 切入点表达式过于宽泛
不精确的切入点会导致性能问题和意外拦截:
// 过于宽泛
@Before("execution(* com.example..*.*(..))")
// 精确控制
@Before("execution(public * com.example.service.*Service.*(..)) && args(userId,..)")
最佳实践总结
- 代理选择原则:理解JDK动态代理与CGLIB差异
- 切面粒度控制:每个切面只关注单一横切关注点
- 性能考量:避免在切面中执行重操作
- 异常处理:始终保留原始异常信息
- 测试策略:为切面编写专门的集成测试
掌握这些避坑技巧将显著提升你的AOP应用质量,避免在生产环境中出现难以调试的问题。

被折叠的 条评论
为什么被折叠?



