JiuyeXD's Blog
九叶
九叶博主

越努力 越幸运

登录
夜间

[笔记] AOP或事务无法拦截this.methodName()解决方案

1. 问题

今天搞注解拦截的时候发现有个方法没有被拦截到 具体代码如下

public void methodName(){
        this.generateConclusionsByRecordID(recordID);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CalculateAdditionInfo(recordId = "scaleRecordID", regenerate = true)
    public void generateConclusionsByRecordID(String scaleRecordID) throws Exception {
        //dosomething()
    }

分析原因可能是 this指向目标对象,走的不是代理 所以无法被拦截到,因此调用generateConclusionsByRecordID()方法不会执行事物切面,即不会执行事务增强,因此generateConclusionsByRecordID()的事务@Transactional不会执行。

2. 解决办法

使用AopContext.currentProxy()函数调用方法

public void methodName(){
        ((ServiceClass)AopContext.currentProxy()).generateConclusionsByRecordID(recordID);
    }

3. 可能遇到的问题

3.1 Cannot find current proxy: Set ‘exposeProxy’ property on Advised to ‘true’ to make it available.

出现这个报错通常是因为使用了AopContext.currentProxy()函数却没有添加相应的配置造成的。

通过注解添加配置(加在启动类上):

@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)

或通过xml配置文件添加配置:

<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

4. 总结

Spring是采用动态代理(AOP)实现对bean的管理和切片,它为我们的每个class生成一个代理对象。

只有在代理对象之间进行调用时,可以触发切面逻辑,也就是切面才可以切进去,才能执行切面里编写的代码。

而在同一个class中,方法B调用方法A,调用的是原对象的方法,而不通过代理对象。所以Spring无法切到这次调用。 获取本对象的代理对象,再进行调用这个类里面的其他方法,那么被调用的那个方法上面如果有切面 那么切面就可以生效了

这样下面的dosomething上的@Transactional开启事物方法就可以生效了

THE END