ThreadLocal有哪些应用场景,开源框架中都是如何使用的?

公众号:Hoeller,有精品面试题(不是很多,150道,但很经典)

前几天发了一篇关于ThreadLocal和ScopedValue的文章,发现很多同学对ThreadLocal在实战中一般会用在那些场景不太清楚,所以这篇文章我结合我看过的源码来给大家总结一下。

第一种场景:Spring事务

先看第一种场景,直接上代码:

这是再简单不过的Spring事务的代码,那么执行上面两个SQL的数据连接是谁创建的呢?

答案是Spring,而不是JdbcTemplate或Mybatis。为什么?假如数据库连接是JdbcTemplate创建的,它是不会去修改数据库连接的autocommit属性的,这个属性的值将是true ,那么执行完一个SQL就会自动提交,等到抛NullPointerException时,由于SQL已经提交了也就不会回滚了,也就没有达到Spring事务想要的效果。

所以,Spring需要自己创建数据库连接,并将它的autocommit属性改为false ,并且JdbcTemplate或者Mybatis需要拿到Spring所创建的数据库连接,这样执行SQL时才不会自动提交,等到执行完整个方法后,Spring才判断是需要回滚还是提交,反正Connection连接对象是Spring自己创建的,所以Spring自己调用Connection的commit()rollback()方法即可。

Spring为了能够让JdbcTemplate或者Mybatis拿到数据库连接,所以会将数据库连接存到ThreadLocal中,JdbcTemplate或者Mybatis从ThreadLocal获取即可。

第二种场景:分布式事务

再来看第二种场景,一般分布式事务的设计中,都会包含两种ID:全局ID和分支ID。

每个微服务需要创建自己的分支id(branchId),但是微服务A作为全局事务的发起者,它还要负责创建一个表示该全局事务的id,也就是全局id(globalId),并且微服务A需要将全局id传递给下游,从而使得微服务B和微服务C知道自己的分支事务是属于哪个全局事务的。

如何传递呢?比如调用微服务的是http请求,则把全局id添加到请求头即可,如果是其他rpc协议,比如dubbo协议,也可以利用它的扩展机制将全局id添加到请求数据中传递给下游服务。

重点在于下游微服务B如何接收全局id呢?像Seata中用的就是mvc拦截器,拦截请求取出请求头中的全局id,并保存到ThreadLocal中,后续逻辑中,比如注册分支事务到全局事务管理器时,直接从ThreadLocal中取出全局id即可。

第三种场景:AopContext和RpcContext

在Spring Aop中,如果想要拿到代理对象,可以通过以下代码拿到:

其中核心就是AopContext.currentProxy(),它能够拿到当前在调用test()方法的代理对象,而它的内部用的也是ThreadLocal,比如该方法的源码为:

其中currentProxy是一个常量为:

其中NamedThreadLocal是Spring自己定义的:

和AopContext类似的还有Dubbo中的RpcContext,Dubbo服务被调用时可以通过RpcContext拿到服务消费者的URL等信息,它们的共同点是:方便在业务代码中获取框架内部生成的对象

第四种场景:SpringBoot 3.0

SpringBoot3.0中在SpringBoot启动过程中新增了一个机制,叫做:SpringApplicationHook ,通过这个机制可以用来在项目启动时设置启动监听器,比如:

withHook()方法有两个参数,第一个参数是一个SpringApplicationHook对象,第二个参数是一个Runnable对象,都是函数式接口,所以上面代码都传入的Lambda表达式,上面代码运行时会先启动SpringBoot,在启动的最后会执行started()方法中的打印语句。

withHook()方法会把SpringApplicationHook对象设置到ThreadLocal中,在SpringBoot启动过程的最后会从ThreadLocal中取出SpringApplicationHook对象并执行。

自然,肯定还有很多场景和源码中会用到ThreadLocal,大家可以把自己遇到的分享在评论区哦。

我是爱读源码的大都督周瑜,欢迎关注我的公众号:Hoeller。公众号里有跟多高质量干货系列文章和精品面试宝典。

相关推荐
AI人工智能+电脑小能手5 小时前
【大白话说Java面试题 第87题】【Mysql篇】第17题:分布式事务的实现原理?
java·数据库·分布式·mysql·面试
红尘散仙5 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
来杯@Java6 小时前
图书管理系统(基于springboot+vue前后端分离的项目)计算机毕业设计java
java·spring boot·spring·vue·毕业设计·mybatis·课程设计
卷毛的技术笔记6 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
编程大师哥6 小时前
匿名函数 lambda + 高阶函数
java·python·算法
会编程的土豆7 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木7 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
adrninistrat0r7 小时前
Java调用链MCP分析工具
java·python·ai编程
喵个咪7 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
噜噜噜阿鲁~7 小时前
python学习笔记 | 11.3、面向对象高级编程-多重继承
java·开发语言