在 Spring Boot 开发阶段,重启一次应用通常需要几秒到十几秒,频繁修改代码时会累积大量等待时间。Spring Loaded 是一个基于 JVM 的类重载工具,通过挂载 javaagent 拦截类加载过程,让方法体级别的改动即时生效,从而避免反复重启。本文从原理、配置、验证和对比几个维度展开,说明如何将 Spring Loaded 整合到 Spring Boot 项目中。

Spring Loaded 热部署的实现原理
Spring Loaded 的核心思路是在 JVM 启动时通过 javaagent 参数注册一个类转换器。当某个类被加载到虚拟机时,这个转换器会检查类的字节码,并保留一份原始结构信息。后续编译产物发生变化时,Spring Loaded 能够定位到已经加载的类,对方法体等可热替换的部分进行字节码替换。由于不涉及类的重新初始化,对象状态得以保留,应用无需像 devtools 那样通过类加载器重启来生效。
这种机制决定了它能处理的范围是有限的。方法体内部逻辑的修改、常量值的调整等通常可以即时生效;但新增方法、修改方法签名、修改继承关系、新增或删除字段等结构性变化,往往无法通过这种字节码替换完成。原因是这些改动会改变类的内存布局或方法分派表,JVM 很难在不重启的前提下安全完成更新。理解这个边界有助于后续排查热部署不生效的问题。
除此之外,Spring Loaded 还需要配合 -noverify 参数使用。JVM 默认会对加载的类进行字节码验证,如果类被动态替换后字节码与原始版本存在差异,验证过程可能失败。关闭验证可以避免这类冲突,让替换更顺利。虽然 -noverify 会跳过一些安全校验,但在本地开发环境中影响很小,属于可接受的取舍。
在 Spring Boot 项目中配置 Spring Loaded
整合 Spring Loaded 的方式主要有两种:一种是通过 Maven 插件在 spring-boot:run 时自动挂载 javaagent,另一种是直接在 IDE 的启动参数中指定 jar 包路径。两种方式本质相同,都是让 Spring Boot 应用在 JVM 启动时加载 Spring Loaded 的 agent。
如果使用 Maven 插件方式,可以在 pom.xml 中为 spring-boot-maven-plugin 增加对 springloaded 的依赖。这样在执行 mvn spring-boot:run 时,插件会自动把 springloaded 作为 javaagent 挂载到启动的 JVM 上。
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.8.RELEASE</version>
</dependency>
</dependencies>
</plugin>
如果使用 IDE 直接启动,需要在运行配置的 VM options 中加入 javaagent 参数。假设 springloaded 的 jar 包放在 C:\springloaded\springloaded-1.2.8.RELEASE.jar,则参数可以写成:
-javaagent:C:\springloaded\springloaded-1.2.8.RELEASE.jar -noverify
在 IntelliJ IDEA 中,打开 Run/Debug Configurations,找到对应的 Spring Boot 应用,将上述内容填入 VM options 一栏即可。在 Eclipse 中,也可以在运行配置的 VM arguments 里添加同样的参数。配置完成后启动应用,Spring Loaded 就会在后台监听 class 文件的变化。需要注意的是,Spring Loaded 只对已经加载到 JVM 的类进行重载,因此修改代码后需要触发类文件重新编译,常见的做法是在 IDE 中开启自动编译,或者手动执行编译命令。
验证热部署效果与常见问题排查
为了验证配置是否成功,可以先启动 Spring Boot 应用,然后修改某个 Controller 方法中的返回值或日志输出。例如把原本返回 Hello 的字符串改成 Hello Spring Loaded,保存并编译后,直接刷新浏览器或重新调用接口,观察是否返回了新内容。如果新内容立即生效,说明热部署已经正常工作。如果仍然显示旧内容,需要从多个角度排查。
首先要确认 JVM 启动时是否真正加载了 Spring Loaded。可以在启动日志中查找 springloaded 相关的输出,或者使用 jps 和 jinfo 命令查看 JVM 参数,确认 -javaagent 是否生效。其次要检查是否添加了 -noverify 参数,缺少该参数可能导致替换失败而回退到旧版本。另外一个常见原因是只修改了方法签名或新增了字段,这类结构性修改不在 Spring Loaded 的支持范围内,只能重启应用。
还有一种情况是 IDE 没有重新编译修改后的类文件。例如在 IntelliJ IDEA 中如果没有开启 Build Project Automatically,保存 Java 文件并不会自动触发编译,Spring Loaded 自然检测不到变化。可以手动执行 Ctrl+F9 编译,或者开启自动编译功能。如果以上都排查过了依然不生效,可能是 Spring Loaded 与某些类加载器存在兼容问题,此时可以尝试切换到官方的 spring-boot-devtools 作为替代方案。
Spring Loaded 与 Spring Boot Devtools 的差异
很多开发者会拿 Spring Loaded 和 spring-boot-devtools 做比较。两者的目标都是提升开发效率,但实现方式完全不同。Spring Loaded 直接替换 JVM 中已加载类的字节码,属于真正意义上的热替换;而 devtools 通过建立两个类加载器,在检测到 classpath 变化后重新加载应用类,属于快速重启。前者速度更快,但支持范围窄;后者支持更全面的变更,但本质上仍然发生了重启。
从使用体验上看,Spring Loaded 更适合纯方法体逻辑的频繁微调,比如调整业务计算、修改日志输出、改变返回值等。devtools 则适合需要修改类结构、配置属性、模板文件等更广泛的场景。实际开发中,不少团队会优先采用 devtools,因为它的稳定性更好,而且与 Spring Boot 的集成更紧密。Spring Loaded 由于已经停止维护,对新版本 JDK 和复杂框架的兼容性可能不足,因此建议只在特定场景下作为补充方案使用。
如果决定在 Spring Boot 中使用 Spring Loaded,建议将其限制在本地开发环境,不要在生产环境开启。热部署工具通常都会带来额外的内存和 CPU 开销,而且关闭字节码验证也会降低一定的安全边界。生产环境应当以稳定性和安全性优先,通过完整的发布流程来更新应用。
Spring BootSpring Loaded热部署修改时间:2026-08-25 23:47:06