我们的项目组使用了 spring-boot-devtools,开发 IDE 是 IDEA 的社区版,社区版并不具备商业版的自动 update 热加载方案。所以我们以前的工作流是:修改某个 class——保存——选菜单,build——build 这个 class,因为 build 过程中会触发 class 文件更新被 spring-boot-devtools 捕捉到,就会完成热加载过程。这个方案一直工作的很好。
知道今天同事反映,有一个模块 A,有些奇怪,修改了 Controller,触发热重载,然后这个 Controller 下的所有 api 路径全部就 404 了,只能停止并重启才能正常。我很奇怪于是研究了一下,发现是这个被修改的 Controller 并没有在热重载时被载入,也就是这个 class“被丢失了”。进一步发现这个问题在所有人的 IDE 上都会复现,每次都一定出现。
我就觉得很奇怪了,首先去网上搜索了一下方案,发现 spring 提到了两个变量 spring.devtools.restart.poll-interval spring.devtools.restart.quiet-period
前者是 spring devtools 多久去检测一次 class 变动,后者是 devtools 缄默间隔时间。网上有个解释,说,如果你编译时间太长,超过了 devtools 的检测时间,就会导致 devtools 认为你这个 class 被删除了,所以不会重新载入。
我尝试拉长第一个选项到 3 秒,确实能解决这个问题。
但是很奇怪,因为这个项目不止这个模块,其它模块可没有设置这个选项啊,为啥其它模块没有这个问题?
然后我开始了漫长的对比测试,最终发现,出问题的这个模块 A,执行 build——build class 这个过程中,所花费的时间,和别的模块没有区别,但是离谱的是,从日志滚动可以看出,A 模块的 spring-boot-devtools 比其它模块,更早的开始执行热重载(日志开始有动作的时间点)。这一点是导致 A 模块丢失编译的类文件的核心问题。
我做了很多测试,包含把上面两个配置给 A 模块和其它模块都配上,而且都设置为系统默认的时长,poll-interval 为 1000ms,quiet-period 为 400ms 。但是没用,A 模块每次都会更早的(编译进度条还没跑完)热重载。实在想不通这是哪个环节造成的问题。
A 模块和其它模块都在一个项目下面,执行他们的时候都在同一个 IDEA,应该可以排除 IDE 问题,我看了一下 IDE 生成的 IML 文件,也没发现异常。