Spring Boot Devtools打印Starting application后延迟原因及优化方法
延迟根因
这5秒固定延迟没有任何日志输出,核心是这段逻辑执行在devtools重启流程的日志系统初始化之前,即使把根日志级别开到TRACE也无法捕获输出,常见触发原因有两个:
- devtools默认等待旧应用线程终止的超时
devtools触发重启时,会先中断上一次运行的应用主线程,默认调用thread.join(5000)等待旧线程完全退出,避免新旧上下文出现端口、连接池之类的资源冲突。如果旧Spring上下文里存在不响应中断的组件——比如没开优雅关闭的数据库连接池、常驻的定时任务线程、没设超时的阻塞异步任务、卡住的Bean销毁逻辑——devtools会等满5秒超时才会强制启动新应用,这段等待过程新应用的日志组件还没完成初始化,不会打任何日志。 - 本机主机名DNS解析超时
如果本地开发机/服务器的hosts文件没有把当前主机名映射到本地回环地址,Spring Boot在初始化日志系统、绑定端口前会调用InetAddress.getLocalHost()获取本机IP,触发DNS反向查询,默认超时刚好是5秒,这段逻辑同样早于日志系统初始化,没有输出。
可落地的优化方案
- 先排查hosts配置问题
执行hostname命令拿到当前机器的主机名,检查hosts文件(Linux/macOS路径是/etc/hosts,Windows路径是C:\Windows\System32\drivers\etc\hosts)里是否存在127.0.0.1 你的主机名、::1 你的主机名两行映射,缺失就补上,保存后测试重启速度,先排除DNS解析的影响。 - 调整devtools重启相关参数
在application.yml中添加以下配置,压缩无意义的等待时间:spring: devtools: restart: # 旧应用终止等待超时,单位毫秒,默认值5000,根据自己项目的资源释放速度调整,最低可设为500 await-termination-timeout: 1000 # 检测到文件变更后的静默等待期,默认400ms,用来等所有编译文件写入完成,避免重复触发重启,可降到200 quiet-period: 200 # 文件变更轮询间隔,默认1000ms,可降到500 poll-interval: 500 # 排除不需要热重载的路径,减少不必要的重启触发 exclude: static/**,public/**,logs/**,*.log - 优化旧上下文的销毁逻辑
如果缩短等待超时后出现端口占用、连接冲突的问题,说明旧应用的销毁逻辑存在阻塞,给核心组件配置快速释放资源的参数:
自定义的异步线程池、定时任务线程池要在销毁逻辑里主动调用spring: lifecycle: # 每个Bean销毁阶段的最大等待时间 timeout-per-shutdown-phase: 2s datasource: hikari: connection-timeout: 1000 validation-timeout: 1000shutdownNow()响应中断,不要无限期阻塞等待存量任务执行完成。
内容的提问来源于stack exchange,提问作者mowwwalker
相关产品推荐
相关产品推荐

