导读:本期聚焦于芒果创作的《Spring Boot DevTools 热部署为什么能自动重启?原理与配置详解》,敬请观看详情。修改代码后每次都要重启应用才能看到效果吗?Spring Boot DevTools 提供了一条更轻量的路径,它不修改字节码,而是用双类加载器缩短恢复时间。应用启动时,基础依赖类被放入 base 类加载器,开发者自己的类由 restart 类加载器加载。文件一旦变化,DevTools 会丢弃并重建 restart 类加载器,只重新加载项目类,避免了整机冷启动的高昂开销。配置核心是引入 spring-boot-devtools 依赖并控制 spring.devtools.restart 相关属性,通常还要排除静态资源,避免前端文件修改触发无意义重启。理解这样一套加载与触发机制后,就能根据项目特点调整自动重启的路径、排除目录和监听范围。

Spring Boot 开发中有一个很常见的场景:改完一个 Service 方法后,如果不重启,接口返回的仍然是旧逻辑。手动重启通常需要十秒到几十秒,而 Spring Boot DevTools 可以在几秒内完成自动重启。它的核心并非字节码热替换,而是把项目类与依赖类拆分成两个加载器,每次只重建项目的那个部分。

Spring Boot DevTools 热部署为什么能自动重启?原理与配置详解

这种设计大幅缩短了等待时间,但也决定了它仍然属于重启范畴,而不是完全无感的热部署。接下来从类加载器机制、依赖配置、触发策略和 IDE 配合几个角度展开。

一、双类加载器机制:为什么秒级就能恢复上下文

应用正常启动时,JVM 会把所有类按需加载到方法区。DevTools 接入后,Spring Boot 会把类加载器拆成 base 和 restart 两个层次。base 类加载器加载来自 Maven 或 Gradle 仓库的依赖,例如 spring-webmvc、commons-lang 这些稳定不变的 jar 包;restart 类加载器则负责加载 target/classes 或 build/classes 下的项目类。项目类会因为开发修改而频繁变化,所以每次变更只需要丢弃 restart 类加载器,再重新扫描项目 class 路径即可。

可以打印一个控制器类的类加载器来验证。启用 DevTools 后,大部分项目类会由 org.springframework.boot.devtools.restart.classloader.RestartClassLoader 加载,而 String、List 等 JDK 类仍然由 bootstrap 类加载器负责。这样的隔离让基础依赖不需要重新装载,节省了类加载和部分初始化开销。Spring 容器会重新刷新,但并不是所有对象都从零开始创建,一些基础 Bean 的元数据仍然可以复用。

@RestController
public class LoaderController {

    @GetMapping("/loader")
    public String loader() {
        return LoaderController.class.getClassLoader().getClass().getName();
    }
}

这个接口返回的通常是 RestartClassLoader 的类名。需要注意的是,如果修改了方法体内部的逻辑,类名不变,但类加载器会换成新的实例。旧实例被丢弃后由 GC 回收。因此它并不能保留对象运行时的现场,像 JRebel 那样做到方法体替换,这也是后面要讨论的边界所在。

二、依赖引入与常用配置

要让项目启用 DevTools,Maven 工程只需在 pom.xml 中加入一个依赖,并且建议同时声明 optional 为 true。optional 的作用是阻止这个依赖传递到其他模块或可执行 jar 中,避免开发工具混入生产部署。scope 设为 runtime 是因为编译期不需要引用 DevTools 的类,它只在运行期介入。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

Gradle 工程可以使用 developmentOnly 来声明同等语义,这个配置不会把依赖打进正式产物。如果使用 Spring Boot Gradle 插件,也可以直接用 bootRun 配合 devtools。

dependencies {
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
}

配置文件中最常用的控制项是 spring.devtools.restart.enabled,默认为 true,可以设置为 false 关闭自动重启。另一个常被关心的参数是 spring.devtools.restart.exclude,它用来指定哪些路径变化时不触发重启。关于排除路径,后续触发策略一节会展开。还可以通过 spring.devtools.restart.additional-paths 把非 classpath 的目录纳入监听范围,比如某些资源目录被单独放在工程外时就会用到。

spring.devtools.restart.enabled=true
spring.devtools.restart.exclude=static/**,public/**
spring.devtools.restart.additional-paths=src/main/resources

这些属性能够应对大部分后端开发场景。实际工作中,配置不生效往往不是因为属性写错,而是 IDE 没有把修改后的 class 文件输出到 DevTools 监听的目录。因此依赖配置完成之后,还需要确认 IDE 的编译行为。

三、触发条件、排除目录与触发文件

DevTools 监听的是 classpath 条目的变更。默认情况下,很多静态资源目录已经被排除在重启触发之外,比如 /resources、/static、/public、/templates。因为前端静态资源通常希望直接热加载而不是重启整个 Spring 上下文。但如果你的项目把模板或自定义静态资源放在其他目录,就需要追加到 spring.devtools.restart.exclude 里,避免改一个 HTML 就触发一次重启,增加无谓等待。

对于需要控制重启时机的场景,可以使用 trigger-file。比如某些外部工具会不断修改 classpath 文件,但你不想每次修改都触发重启,就可以指定一个触发文件。只有这个文件发生变化时,DevTools 才会执行重启。典型配置如下:

spring.devtools.restart.trigger-file=.triggerfile

手工触发时可以执行 touch .triggerfile 生成新时间戳,这样比直接修改代码文件更可控。还有全局配置文件 .spring-boot-devtools.properties,可以放在用户主目录下,这样多个项目共享默认配置。例如公司内部统一把自动重启关闭或统一排除目录,就不需要每个工程重复写相同属性。

另一个容易混淆的点是 additional-paths。它不会把你指定的目录纳入 classpath,而是额外增加一个监控路径。例如 src/main/resources 默认已经监控,但在某些多模块结构中,配置目录可能不在当前模块 classpath 下,此时可以手动添加。理解了监听与触发的关系,排查为什么不重启和为什么频繁重启就会轻松很多。

四、IDE 配合与实际使用边界

IDE 是 DevTools 使用体验的关键一环。IntelliJ IDEA 默认不会在应用运行时自动编译修改后的类,需要开启 Build Project Automatically,并在注册表中允许 automake 在应用运行时工作。Eclipse 通常会自动编译保存的文件,体验相对顺畅。很多开发者配置了 DevTools 却看不到重启效果,问题多半出在 IDE 没有把新 class 写到输出目录,而不是依赖或 YAML 配置错误。

还有一个常见的误解是把 DevTools 当成 JRebel 或 DCEVM 这类真正的热替换工具。DevTools 可以自动重启、可以刷新静态资源,但遇到修改方法签名、改变继承关系、调整注解元数据等结构变化时,它仍然需要重建类加载器和 Spring 上下文。方法体内部的简单修改虽然也要重启,但时间被控制得很短。如果希望连方法体修改都不丢失状态,那需要引入字节码热替换方案,而不是继续叠加 DevTools 配置。

最后要强调生产安全。spring-boot-devtools 的 optional 和 scope 设置意味着它不应该被传递到最终部署包。官方也保证从完整打包的可执行文件启动时 DevTools 默认禁用。如果发现生产日志中出现了 DevTools 相关输出,首先检查构建链路是否把开发环境依赖打进去了。将重启关闭、排除目录设置好后,DevTools 会成为开发阶段非常实用的效率工具,而不是一个不稳定的黑盒。

Spring Boot DevTools热部署自动重启修改时间:2026-09-26 05:16:16

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0926/62002.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。