如何使用DevTools加快Spring Boot的开发速度并使此过程更加有趣和高效?
客制化
和往常一样,在Spring Boot上进行开发时,设置非常简单。 您所要做的就是添加正确的依赖关系,您已完成。 Spring Boot会找到它并相应地自动配置DevTools。
如果您使用的是Maven:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
如果使用Gradle:
configurations { developmentOnly runtimeClasspath { extendsFrom developmentOnly } } dependencies { developmentOnly("org.springframework.boot:spring-boot-devtools") }
请注意,该依赖项被声明为可选。 这很重要,因为这样的依赖项声明会阻止DevTools依赖项根据您的项目被传递性地应用于其他模块。
自动重启
每当您的类路径中发生文件更改时,DevTools都会使用新更改自动重启您的工作应用程序。 对于本地开发,这很有用,因为您无需手动重新部署应用程序。
仅此一项并没有什么用,因为重新启动仍然会花费太多时间。 幸运的是,由于DevTools使用了棘手的技巧,因此这种重启比常规重启快得多。
事实是,在开发应用程序时,您通常会更改一个或多个类,并希望在运行的应用程序中检查结果以获取反馈。 您可以对应用程序进行较小的更改,而大多数已加载的类都来自框架和第三方库。
在Spring DevTools的内部,使用了两个类加载器-base和
restart 。 不变的类由基本加载器
base加载。 您使用的类是使用
重新启动加载器加载的。 每次重新启动时,都会重新创建引导加载程序。 因此,重新启动应用程序的速度比平常快得多,并且可以作为使用诸如JRebel之类的工具重新加载动态类的真正选择。
在IDE中初始化重启
每当类路径中的文件发生更改时,都会触发重新启动。 但是,此过程取决于您的IDE。 这意味着仅更改Java文件是不够的。 重要的是,当您的IDE实际更新类路径中的.class文件时。
使用IntelliJ IDEA时,需要在项目中运行build命令(
Ctrl + F9或
Build→Build Project )。 您还
可以将build命令配置为在IDEA中自动运行 。 另外,您可以打开Spring Boot启动配置并确定应用程序更新开始时会发生什么(
Ctrl + F10 ):

在第一个组合框中,您可以选择“
更新”触发文件,以在每次执行“
更新”操作时启动DevTools重新启动。 另外,您甚至可以选择“
热交换”选项,并仅在
热交换执行失败时尝试使用DevTools重新启动应用程序。
在第二个组合框中,可以配置当IDEA窗口失去焦点时(例如,切换到浏览器窗口时)所有静态资源和模板的重新引导。
在Eclipse中,保存文件非常容易。
仅开发
Spring Boot DevTools仅用于开发,而不用于应用程序的生产操作。 如果您的应用程序检测到您正在生产环境中工作,则将自动禁用DevTools。
为此,无论何时将应用程序作为完全打包的工件(例如具有集成应用程序服务器的jar)启动时,都将其视为生产应用程序:
java -jar devtools-example-1.0.0.jar
当通过特殊的类加载器(例如,在应用程序服务器上)启动应用程序时,也是如此。
相反,当您运行解压缩的工件时(例如,在IDE中),则将您的应用程序视为处于开发模式。 使用spring-boot-plugin运行应用程序也是如此:
Maven:
mvn spring-boot:run
摇篮:
gradle bootRun
LiveReload
LiveReload是一个有用的工具,可让您在更改HTML,CSS,图像等文件时立即刷新浏览器中的页面。 它甚至可以根据需要预处理文件-这意味着可以自动编译SASS或LESS文件。

Spring DevTools自动启动LiveReload服务器的本地实例来跟踪您的文件。 您所要做的就是
为浏览器安装
扩展程序 ,您已完成。 它不仅对开发应用程序的外部接口很有用(以防您将其作为Spring应用程序工件的一部分进行分发),而且还可以用于监视和重新加载REST API的输出。
财产超控
在本地开发应用程序时,通常与在生产环境中工作时具有不同的配置需求。 一个例子就是缓存。 在生产环境中,对各种缓存(例如引擎模板缓存,静态资源的缓存头等)的依赖性非常重要。 在开发过程中,它可能会使用旧数据,而不反映您的最新更改。 另一个示例是高级日志记录,它在开发中可能有用,但对于生产环境来说太详细了。
自己管理两种类型的配置太困难了。 好消息是,默认情况下,Spring Boot DevTools为您的本地开发设置了许多属性。
spring.thymeleaf.cache=false spring.freemarker.cache=false spring.groovy.template.cache=false spring.mustache.cache=false server.servlet.session.persistent=true spring.h2.console.enabled=true spring.resources.cache.period=0 spring.resources.chain.cache=false spring.template.provider.cache=false spring.mvc.log-resolved-exception=true server.servlet.jsp.init-parameters.development=true spring.reactor.stacktrace-mode.enabled=true
您可以在
DevToolsPropertyDefaultsPostProcessor类中找到所有属性的列表。
远程连接
除了本地开发之外,您还可以连接到运行DevTools的远程应用程序。 该工具不适用于生产环境,因为它可能会带来严重的安全风险。 但是,它在预生产环境中可能非常有用。
启用远程连接
默认情况下不启用远程连接。 您需要通过修改pom文件来显式启用它:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludeDevtools>false</excludeDevtools> </configuration> </plugin> </plugins> </build>
或使用gradle,您需要设置
excludeDevtools = false :
bootWar { excludeDevtools = false }
然后,您需要设置一个密码,该密码将在连接到远程应用程序时用于身份验证:
spring.devtools.remote.secret=somesecret
连接到远程应用程序
启动远程应用程序后,您可以启动远程连接会话。 现在,您要做的就是运行
org.springframework.boot.devtools.RemoteSpringApplication ,并将远程应用程序的URL作为参数。 请注意,如果可能,您应该使用
https 。
在您的IDE中,开始远程连接很容易。 在IDEA中,您只需要创建一个新的启动配置。 转到
运行→编辑配置...,然后使用左上角的
+图标创建一个新配置。 选择一个应用程序类型。
对于Main类,从DevTools模块中选择
RemoteSpringApplication ,然后将远程应用程序的URL作为参数传递给程序。

启动此配置后,如果与远程应用程序的连接成功,您应该会看到类似的输出。

连接到远程应用程序后,DevTools以与本地开发相同的方式监视类路径更改。 但是,它代替本地重启,而是将更改传输到远程服务器并在那里启动重启。 这比创建应用程序并将其部署到远程计算机要快得多。
全局配置
您可以像其他任何Spring应用程序一样使用配置属性来自定义DevTools。 这通常意味着编辑项目的
application.properties 。 对于每个应用程序,此配置都是单独的。
但是,在某些情况下,为在同一计算机上运行的所有应用程序进行全局配置可能会很方便。 您可以在
$ HOME目录中创建一个名为
.spring-boot-devtools.properties的属性文件。 该文件中声明的声明适用于所有使用DevTools的应用程序。
局限性
实时重载
使用DevTools的Spring应用程序会自动启动LiveReload服务器。 不幸的是,一次只能启动该服务器的一个实例。 更准确地说,只有一审才可以。 这不仅适用于带有DevTools的Spring应用程序的多个实例,而且还适用于在后台也使用LiverReload的任何其他应用程序,例如处于开发模式的
Gatsby 。
如果要配置Spring应用程序,使其不启动LiveReload服务器,则可以在
application.properties文件中完成:
spring.devtools.livereload.enabled=false
关机钩
DevTools依赖于
SpringApplication类的
shutdown hook属性。 如果使用以下命令手动禁用了该属性,则该类将无法正常工作:
springApplication.setRegisterShutdownHook(false);
该属性默认情况下处于启用状态,因此您无需担心,除非您明确禁用它。
与第三方库的冲突
尽管DevTools通常应该可以正常运行,但是它们可能与第三方库有冲突。 特别是,使用标准
ObjectInputStream进行反序列化存在一个已知问题。
如果发生此类冲突,可以通过设置以下方式禁用自动重启:
spring.devtools.restart.enabled=false
重新启动将不再起作用。 但是,仍将使用
重新启动类加载器。 如果需要完全禁用类加载器,则必须在启动应用程序之前执行以下操作:
public static void main(String[] args) { System.setProperty("spring.devtools.restart.enabled", "false"); SpringApplication.run(MyApp.class, args); }
即使您不使用自动重启,您仍然可以使用其他DevTools功能。
启用延迟初始化
您可以使用注释将各个组件标记为延迟初始化
。 此功能已经存在了一段时间。 从Spring Boot 2.2开始,您可以使用
spring.main.lazy-initialization = true切换所有bean组件的延迟初始化。
它可以单独使用,也可以
与DevTools结合使用,以实现更快的重启 。
DevTools允许您在同一JVM中热重启应用程序。 热重启的一个重要优点是,它为JIT提供了更多选项来优化用于启动应用程序的代码。 几次重启后,2500 ms的初始时间减少了近80%,接近500 ms。 通过延迟初始化,我们可以获得更好的结果。 安装
spring.main.lazy-initialization时,我们的应用程序会在400毫秒后直接在IDE中重新启动。
在生产应用程序中对所有bean使用延迟初始化是令人怀疑的。 由于对各个bean组件的首次请求时间较长,因此此过程可提供卓越的启动性能。 更重要的是,您的应用程序不会很快停止运行。 但是,它不会在启动应用程序时立即崩溃,而只会在直接请求配置错误的组件后才会失败。 这可能非常危险,因为直到为时已晚,您才会发现很多错误。 但是,大量延迟的初始化对于加快开发时间很有用,因为使用某些功能时,您通常只在应用程序的一部分上工作,而不使用其余部分。 理想的折衷方案是仅针对本地开发(例如,使用spring配置文件)启用大规模延迟初始化,并针对已部署的更高环境禁用它。
结论
DevTools通过提供自动重启和LiveReload功能来加速并简化Spring Boot应用程序的开发。 除此之外,它还为更适合本地开发的值设置了各种属性。 另外,它允许您远程连接到您的应用程序,同时使用其大部分功能。 在生产环境中启动应用程序时,不使用DevTools。 有关详细信息,请参见
官方文档 。