背景信息
- 当前工程环境是jdk8+springboot2.7.18
先说几个结论
虚拟线程目前不建议在web服务类应用中使用
- 不建议在web服务类的应用中使用的主要原因有两个:
1.当前jdk21的最新release note,依然有时不时关于虚拟线程的bug修复
2.需要对代码中使用synchronized关键字和Threadlocal类的地方做改造,使用synchronized改成使用ReentrantLock实现,使用Threadlocal改成正常的局部对象
- synchronized的改造是最大的卡点,虽然大部分广泛使用的开源框架都已经开始改造支持虚拟线程了,但是我们自己服务里广泛应用了很多内部类库,想推动这些内部老类库升级迭代的难度我想各位就不用我多说了吧: )
- 而且估计未来jdk也无法从jvm层面支持synchronized对虚拟线程的优化,因为这些wait/notify/synchronized关键字都是native实现,想在native层面支持虚拟线程我看没什么可行性
- springboot默认也依然使用老线程模型,没有默认启用虚拟线程
- 如果是工具类的客户端执行的工程用一用问题不大,这种应用的第三方依赖普遍较少,运行时间普遍很短,所以一般来说不会有什么大问题
从jdk8 -> jdk21值得关注的地方
- 最重要的是gc,升到jdk21后除了g1和分代zgc以外,其他的垃圾回收器可以完全不用关注
- instanceof的增强绝对是值得一用的,代码简洁很多(没有强制类型转换的代码看着很干净)
- 新命令jwebserver值得一用,临时起一个文件服务器很方便,可以取代之前用python起文件服务器了
python -m SimpleHTTPServer、python3 -m http.server - 其他的switch增强、文本块、密封类多少有点用,有总比没有强,HttpClient也不适合大规模用,很多功能无法设置(连接池无法设置就是硬伤,请求超时必须每个Request单独设置,同步异步请求走同一套逻辑造成了同步请求实际也需要跑在别的线程里)
升级到jdk21的改造点
jvm启动参数改造,直接上8和21的配置截图
终于默认取消偏向锁这个纯学院派没有卵用的东西了,所以这个参数不支持了
-XX:-UseBiasedLocking

image.png

image.png
pom中properties设置
springboot3.5默认java.version是17,需要改成21
<properties>
<java.version>21</java.version>
</properties>
升级到springboot3.5的改造点
knife4j依赖升级(没用到这个的可以不用管)
knife4j是使用spring-doc自动生成接口api文档的工具库
- 按照官方文档,需要将依赖从
knife4j-openapi3-spring-boot-starter改为knife4j-openapi3-jakarta-spring-boot-starter -
springdoc-openapi-starter-webmvc-ui按照文档提示升级到2.8.9,2.7以上才支持springboot3.4+
knife4j-openapi3-jakarta-spring-boot-starter默认依赖的springdoc-openapi-starter-webmvc-ui是2.3.0版本,不支持springboot3.5
代码修改
- 将代码中的
javax.annotation.Resource、javax.annotation.PreDestroy、javax.annotation.PostConstruct以及javax.validation.下的各种校验类全部换成jakarta.annotation.开头的对应类 -
application.yml删除server.shutdown: graceful设置,该设置已经改成了默认graceful -
application.yml增加如下配置,否则日志中会打印spring.application.name和spring.application.group中设置的内容,每行日志会变很长
logging:
include-application-name: false
include-application-group: false
- Yaml类创建方式修改,改造后如果会打印重复key的warn日志,可以设置
loaderOptions.setWarnOnDuplicateKeys(false)
new Yaml(new SafeConstructor());
改为
LoaderOptions loaderOptions = new LoaderOptions();
new Yaml(new SafeConstructor(loaderOptions));
-
logback-spring.xml修改,springboot3.5使用了新版logback,新版logback对配置文件有额外的检查,springProfile标签只允许在最外层,之前的这种写法不允许了
<root level="INFO">
<springProfile name="local">
<appender-ref ref="consoleAppender"/>
</springProfile>
<appender-ref ref="infoAppender"/>
<appender-ref ref="errorAppender"/>
</root>
改成如下:
<springProfile name="local">
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<!-- 内容自己设置-->
</appender>
<root level="DEBUG">
<appender-ref ref="consoleAppender"/>
</root>
</springProfile>
<springProfile name="!local">
<appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 内容自己设置-->
</appender>
<appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 内容自己设置-->
</appender>
<root level="INFO">
<appender-ref ref="infoAppender"/>
<appender-ref ref="errorAppender"/>
</root>
</springProfile>
- 如果用到了okhttp,需要自己设置版本号
springboot3.5已经不维护okhttp的版本了,所以需要我们自己在pom中指定版本,研究了一下升级到
4.12.0,23年的4版本的最后一个release,5版本刚出还不太稳定,详见https://square.github.io/okhttp/changelogs/changelog/