@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)解决同类方法调用时异步和事务不生效:
我们在开启springboot启动类上添加@EnableAsync,从而启动异步注解@Async
启动之后,我们可以在需要异步执行的方法上面添加@Async注解,即可实现异步,但是有一点,如果我们需要用同一个类中的方法调用另一个加了@Async注解的方法,这时@Async不起作用,原因和事务注解@Transactional失效的原因一样,没有用到代理类导致,这时我们可以通过在启动类添加@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)来解决问题。
该注解两个参数作用分别为:
一个是控制aop的具体实现方式,为true的话使用cglib,为false的话使用java的Proxy,默认为false。
第二个参数控制代理的暴露方式,解决内部调用不能使用代理的场景,默认为false。
具体解决办法:
/** * 1、首先要知道spring的aop切面的原理是什么? * 答:Spring是采用动态代理(AOP)实现对bean的管理和切片,它为我们的每个class生成一个代理对象。 * 只有在代理对象之间进行调用时,可以触发切面逻辑,也就是切面才可以切进去,才能执行切面里编写的代码。 * 而在同一个class中,方法B调用方法A,调用的是原对象的方法,而不通过代理对象。所以Spring无法切到这次调用。 * 2、所以想必你大致也明白了为什么在同一个类里面一个方法调用另外一个带有@Async的方法不起作用了? * 不仅仅是这个,同一个类里面一个方法调用另外一个开启事物(@Transactional)的的方法,事物也是不起作用的。 * 3、自定义的注解在同一个类里面方法调用也是不起作用的,总的来说同一个类里面总的来说只要是同一个类里面的方法间调用, * 那么切面都是无效的,aop都无法切入进入。 * 4、解决办法用AopContext.currentProxy()获取一个代理类,然后用代理类再去调用就好了 代码示例: */ @Service public class serviceImpl implements service { @Async @TargetDataSource("db1") @Override public void do(String value) { /** * 获取本对象的代理对象,再进行调用这个类里面的其他方法,那么被调用的那个方法上面如果有切面 * 那么切面就可以生效了,本代码示例就是在开启事物之前先动态切换数据源, * 这样下面的dosomething上的@Transactional开启事物方法就可以生效了, * 动态切换数据源要注意一个问题,就是在开启事物之前要先切换成需要的数据源,不要在开启事物 * 之后在切换数据源不然会切换失败,因为一个事物的开启是建立在与一个数据源建立连接的基础上开启的 * 所以如果先开启事物然后再切换数据源会报错,切换会失败 */ ((serviceImpl) AopContext.currentProxy()).dosomething(value); } /** * 要注意 * @Transactional是否是生效的 * * @param value */ @Transactional @Override public void dosomething(String value) { //dosomething() } }
————————————————
版权声明:本文为CSDN博主「LiZhen798」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/LiZhen314/article/details/120495143