You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot自动重启后静态ThreadLocal统计SQL执行次数始终为0问题

问题根因

该异常由Spring Boot DevTools热重启的类加载器隔离机制导致:

  • DevTools为提升重启效率采用双类加载器设计:
    • 基础类加载器:负责加载不会频繁变动的第三方依赖(如P6spy核心组件、JDBC接口等)
    • 重启类加载器:负责加载项目自研代码,每次触发热重启都会生成新的实例替换旧加载器
  • 首次启动时P6spyListener被注册到P6spy框架中,而P6spy由基础类加载器持有,热重启后旧的P6spyListener实例不会被销毁,它操作的是旧重启类加载器加载的App类下的静态ThreadLocal变量
  • 热重启后新的RequestInitInterceptor由新的重启类加载器加载,引用的是新App类中的静态ThreadLocal实例,两个ThreadLocal完全独立,因此会出现监听器累加的是旧实例值,拦截器读取的新实例值始终为0的问题。

解决方案

方案1:配置DevTools排除自定义监听器加载(开发环境推荐)

在application.properties中添加配置,将P6spyListener归入基础类加载器的加载范围,热重启时不会重新加载该类,保证引用的ThreadLocal实例统一:

# 排除单个类
spring.devtools.restart.additional-exclude=**/P6spyListener.class
# 也可以直接排除整个监听器所在包
# spring.devtools.restart.additional-exclude=com/xxx/listener/**

方案2:关闭DevTools热重启

热重启仅为开发调试功能,不需要时可直接关闭:

spring.devtools.restart.enabled=false

生产环境打包时Spring Boot默认不会引入DevTools依赖,不会出现该问题。

方案3:迁移ThreadLocal到非重启加载范围

将App.count这个静态ThreadLocal变量移动到独立的第三方依赖模块中,这类模块不会被重启类加载器加载,天然保证实例全局唯一。

内容的提问来源于stack exchange,提问作者Cao Vison

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 14:15:01