Spring AOP 失效的原因
1. Spring AOP 不能拦截 protected 方法
核心原因
Spring AOP 基于代理实现:无论是 JDK 动态代理还是 CGLIB 代理,都只对 public 方法 进行增强。
JDK 动态代理:基于接口,只能代理 public 方法(接口方法默认为 public)。
CGLIB 代理:通过继承目标类生成子类,虽然理论上可以覆盖 protected 方法,但 Spring AOP 明确排除了对 non-public 方法的拦截,以保持行为一致性。
具体表现
在 protected 方法上使用 @Transactional 等注解时,事务不会生效,且 不会抛出异常,只是被静默忽略
Spring 在创建代理时,会通过 AbstractFallbackTransactionAttributeSource.computeTransactionAttribute() 方法判断方法可见性,若非 public,则返回 null,导致无事务增强
- 即使 CGLIB 生成了代理类,protected 方法进入拦截链时,拦截器链为空,因此无法应用切面逻辑
2. 内部方法调用(自调用)
@Service
public class MyService {
public void methodA() {
methodB(); // 这里不会触发AOP
}
public void methodB() {
// 事务逻辑
}
}
解决方案:
使用 AopContext.currentProxy() 获取当前代理对象并调用。
原因:
Spring 容器会为 MyService 创建一个代理对象(假设为 MyServiceProxy)。
当外部调用 methodA() 时,实际调用的是 MyServiceProxy.methodA(),此时代理对象可以正常拦截并执行切面逻辑。
但在 methodA() 内部,methodB() 的调用是通过 this.methodB() 实现的,这里的 this 指向的是原始目标对象(即 MyService 实例),而非 MyServiceProxy。
由于调用未经过代理对象,因此 @Transactional 等基于 AOP 的注解不会生效
浙公网安备 33010602011771号