2018年11月2日 上次更新时间:2019年4月28日
Spring Boot开发者工具
DevTools 支持 自动刷新与 自动重启 –自动刷新(或自动加载)是指在浏览器中重新加载UI,以查看静态内容的更改。自动重新启动是指重新加载服务器端代码和配置,然后重新启动服务器。
如何使用DevTools进一步加快Spring Boot开发的速度,并使之更加有趣和高效?
设定
像通常使用Spring Boot一样,设置非常简单。您需要做的就是添加正确的依赖关系,您就可以开始工作了。Spring Boot会检测到这一点,并相应地自动配置DevTools。
如果您使用的是Maven:
org.springframework.boot
spring-boot-devtools
true
另外,在使用Gradle时:
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
}
dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
}
请注意,该依赖项被声明为可选。这个很重要。这样可以防止将DevTools依赖项过渡性地应用于依赖于项目的其他模块。
自动重启
只要您的类路径上的文件发生更改,DevTools就会在应用了新更改的情况下自动重启正在运行的应用程序。在本地进行开发时,这很有用,因为您无需手动重新部署应用程序。
就其本身而言,它并不是那么有用,因为重新启动仍会花费大量时间。幸运的是,由于DevTools使用了一个巧妙的技巧,这些重启比常规重启快得多。
您会看到,在开发应用程序时,通常会更改一个或几个类,并希望在运行的应用程序中检查结果以获取反馈。您更改了应用程序的一小部分,因为大多数已加载的类来自框架和第三方库。
引擎盖下,春DevTools使用两个类加载器-基地和重启。不变的类由基本类加载器加载。您正在使用的类由重新启动类加载器加载。每当触发重新启动时,重新启动类加载器都会被丢弃并重新创建。这种重启应用程序的速度比平常快得多,并且可以替代使用诸如JRebel之类的动态类来重新加载应用程序。
在IDE中触发重启
只要类路径发生更改,就会触发重新启动。但是,这取决于您的IDE。这意味着仅更改.java文件是不够的。重要的是您的IDE实际上会更新.class类路径上的文件。
使用IntelliJ IDEA时,需要构建项目(Ctrl+ F9或Build → Build Project)。您还可以将IDEA配置为自动重建。另外,您可以打开Spring Boot运行配置并定义触发应用程序更新(Ctrl+ F10)时发生的情况:
Intellij IDEA Spring Boot运行配置
在第一个组合框中,可以选择Update trigger file在调用Update操作时触发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:
gradle bootRun
实时重载
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文件显式启用它:
org.springframework.boot
spring-boot-maven-plugin
false
或使用gradle,您需要设置 excludeDevtools = false:
bootWar {
excludeDevtools = false
}
然后,您需要设置一个秘密密码,以便在连接到远程应用程序时用于身份验证
spring.devtools.remote.secret=somesecret
连接到远程应用
远程应用程序运行后,您可以启动远程连接会话。现在,您所需要做的就是以org.springframework.boot.devtools.RemoteSpringApplication
远程应用程序的URL作为参数启动。请注意,如果可能,应使用https。
在您的IDE中,运行远程连接非常容易。在IDEA中,您只需创建一个新的运行配置。转到Run → Edit Configurations...并使用左上角的[+]图标创建新配置。选择Application类型。
作为Main类,RemoteSpringApplication从DevTools模块中选择,并作为程序参数传递远程应用程序的URL。
IDEA中的远程连接配置
运行此配置后,如果与远程应用程序的连接成功,您应该会看到类似的输出。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \
\\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) )
' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
=========|_|==============|___/===================================/_/_/_/
:: Spring Boot Remote :: (v2.0.6.RELEASE)
2018-11-02 17:24:42.126 INFO 16640 --- [ main] o.s.b.devtools.RemoteSpringApplication : Starting RemoteSpringApplication v2.0.6.RELEASE on DESKTOP-6NJV4ON with PID 16640 (C:\Users\vojte\.m2\repository\org\springframework\boot\spring-boot-devtools\2.0.6.RELEASE\spring-boot-devtools-2.0.6.RELEASE.jar started by vojte in C:\projects\rest-docs-starter)
2018-11-02 17:24:42.130 INFO 16640 --- [ main] o.s.b.devtools.RemoteSpringApplication : No active profile set, falling back to default profiles: default
2018-11-02 17:24:42.172 INFO 16640 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@3daa422a: startup date [Fri Nov 02 17:24:42 CET 2018]; root of context hierarchy
2018-11-02 17:24:42.679 WARN 16640 --- [ main] o.s.b.d.r.c.RemoteClientConfiguration : The connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'.
2018-11-02 17:24:42.800 WARN 16640 --- [ main] o.s.b.d.a.OptionalLiveReloadServer : Unable to start LiveReload server
2018-11-02 17:24:42.829 INFO 16640 --- [ main] o.s.b.devtools.RemoteSpringApplication : Started RemoteSpringApplication in 1.212 seconds (JVM running for 1.877)
连接到远程应用程序后,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。如果您使用以下方式手动禁用了挂接,它将无法正常工作:
springApplication.setRegisterShutdownHook(false);
默认情况下,挂钩是启用的,因此除非明确禁用它,否则您不必担心。
与第三方库的冲突
尽管DevTools通常应该可以正常运行,但它可能与第三方库有冲突。特别是,使用standard进行反序列化存在一个已知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提供的其他功能中受益。
启用延迟初始化
您可以使用@Lazy
注释将各个bean标记为延迟初始化。这个功能在Spring已经有一段时间了。从Spring Boot 2.2开始,您可以使用切换所有bean的延迟初始化spring.main.lazy-initialization=true
。可以单独使用它,也可以将它与DevTools组合使用,以更快地重启。
DevTools可以在同一JVM中热重启您的应用程序。热重启的一个重要好处是,它为JIT提供了更多机会来优化启动应用程序所涉及的代码。重启几次后,原来的2500ms时间减少了近80%,接近500ms。通过延迟初始化,我们可以做得更好。设置spring.main.lazy-initialization 可以看到我们的应用程序直接在IDE中在400毫秒内重新启动。
在生产应用程序中对所有bean使用延迟初始化是有问题的。它为启动提供了出色的性能提升,但代价是单个 Bean 的首次请求时间较长。更重要的是,您的应用程序不再快速失败。它不会在启动应用程序时立即崩溃,而只会在直接请求配置错误的bean之后失败。这可能非常危险,因为直到为时已晚,您才发现很多错误。尽管如此,大规模延迟初始化对于加快开发时间还是很有用的,因为在使用某些功能时,您通常只在应用程序的一部分上工作,而其余部分则不使用。理想的折衷方法是仅对本地开发启用大规模延迟初始化(假设使用spring配置文件),而对于已部署的更高环境禁用它。
结论
通过提供自动重启和LiveReload功能,DevTools使您的Spring Boot应用程序开发更加轻松快捷。除此之外,它还将各种属性设置为更适合本地开发的值。此外,它允许您远程连接到应用程序,并且仍使用其大多数功能。在生产环境中运行时,不使用DevTools。有关详细信息,请参阅官方文档。