在Spring 的AOP实现有两种代理方式:
- Java动态代理 :通过反射生成一个实现了代理方法的匿名类来完成代理,只能为接口创建代理类
- cglib代理 :通过Asm修改字节码文件,生成一个子类来完成代理
Spring在项目中会根据被代理对象是否实现了接口来自动切换上述两种代理方式
在Spring 的AOP配置文件中存在下面两个配置值得注意:
- proxy-target-class :如果将这个属性设置为true,那么就是强制要求Spring 使用cglib来完成动态代理
- expose-proxy : 对于目标内部的方法调用将无法完成切面增强
这里思考以下为什么内部方法调用不能完成切面增强呢?在文章尾部会进行解释,可以先思考一下
下面是一个例子来说明Spring怎么解决这种方法内部调用且完成切面增强 :
public interface Aservice {
public void a();
public void b();
}
@Service
public class AServiceImpl implements Aservice{
@Transactional(propagation = Propagation.REQUIRED)
public void a() {
this.b();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void b() {
}
}
此处的this指向目标对象,因此调用this.b()将不会执行b事务切面,即不会执行事务增强,因此b方法的事务定义将不会被实施。为了解决这个问题,我们可以进行以下配置:
<aop:aspectj-autoproxy expose-proxy="true"/>
然后将上述代码中的this.b() 修改为((AService)AopContent.currentProxy()).b() ,这样就可以完成方法a 和 b 的同时切面增强了。
最后回答上面的问题:因为在方法内部调用内部方法,其实调用的根本不是代理类中的那个方法啊,所以根本没法完成切面增强,
所以我们这里通过AopContent.currentProxy()的方式来获取一下当前类的代理类,然后执行代理类中的那个b()方法,这样就能够完成切面增强了,怎么样,和你想的一样不
所以问题的根本是在b方法中调用的不是代理类对象中的方法,那么除了用上述方式解决内部调用不会被切面处理的问题,就是在当前service的内部,再注入一个自己,然后在下面通过自己注入
对象来调用对应方法,有时间的自己试试吧!