栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring-框架专区 - @Transactional 或 @Async 注解失效原因分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring-框架专区 - @Transactional 或 @Async 注解失效原因分析

其实 @Transactional 或 @Async 注解失效原因很简单:它们的原理都是动态代理,也就是说只有通过代理类去调用方法才能够使方法有"增强“的效果。这里以 @Async 为例。

  下面定义一个 Service:两个异步执行的方法 test03() 和 test02() 用来模拟项目中可能出现的耗时的操作,然后 test() 方法调用这两个耗时的方法:



定义 Controller:



执行方法,返回结果:



  方法执行结果明显与我们的预期不符,方法的输出顺序表示了 test02() 和 test03() 两个异步方法居然同步执行了,也就是说 @Aysnc 注解失效了!

  失效的原因是因为我们是在 test() 方法中直接调用的 test02() 和 test03() 方法,相当于是 this.test02() 和 this.test03() 调用的,也就是说真正调用 test02() 和 test03() 方法的是 TestService 对象本身调用的,而 @Async 和 @Transactional 注解本质使用的是动态代理,真正应该是 TestService 的代理对象调用 test02() 和 test03() 方法。其实 Spring 容器在初始化的时候 Spring 容器会将含有 AOP 注解的类对象“替换”为代理对象(简单这么理解),那么注解失效的原因就很明显了,就是因为调用方法的是对象本身而不是代理对象,因为没有经过Spring 容器,那么解决方法也会沿着这个思路来解决。

  网上有不少博客说解决方法就是将要异步执行的方法单独抽取成一个类,这样的确可以解决异步注解失效的问题,原理就是当你把执行异步的方法单独抽取成一个类的时候,这个类肯定是被 Spring 管理的,其他 Spring 组件需要调用的时候肯定会注入进去,这时候实际上注入进去的就是代理类了,其实还有其他的解决方法,并不一定非要单独抽取成一个类。

解决方式一:在 TestService 中通过上下文获取自己的代理对象调用异步方法

其实我们的注入对象都是从 Spring 容器中给当前 Spring 组件进行成员变量的赋值,由于 TestService 使用了AOP注解,那么实际上 TestService 在 Spring 容器中实际存在的是它的代理对象。

(工具类可以参考:

https://blog.csdn.net/Dongguabai/article/details/80788646 )



执行结果,异步方法异步执行了:



. 解决方式二:开启 CGLIB 代理,手动获取 Spring 代理类

在 Spring Boot 启动类上加上:



使用 AopContext.currentProxy() 获取当前代理类:

这里为了证明 Spring 容器中的对象就是当前代理类对象特地输出了一句话:



运行结果:



OK,问题完美解决!

原文链接: https://www.cnblogs.com/liboware/p/12469245.html

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/333133.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号