Spring Boot包含一组额外的工具,这些工具可以使应用程序开发体验更加愉快。spring-boot-devtools
模块可以被引入到任何项目中,以提供额外的开发时功能。要引入devtools支持,请将模块依赖项添加到您的构建中,如下面所示的Maven和Gradle清单:
Maven
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
Gradle
dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
}
运行完全打包的应用程序时,将自动禁用此开发人员工具。如果您的应用程序是通过
java -jar
启动的,或者从某个特殊的类加载器启动的,则将其视为“生产应用程序”。如果那对您不适用(即,如果您从容器中运行应用程序),请考虑排除devtools或设置-Dspring.devtools.restart.enabled=false
系统属性。在Maven中将依赖项标记为可选,或在Gradle中使
developmentOnly
用配置(如上所示)可以防止将devtools过渡地应用到使用此项目的其他模块。重新打包的存档默认情况下不包含devtools。如果要使用某个远程devtools功能,则需要引入它。使用Maven插件时,请将
excludeDevtools
属性设置为false
。使用Gradle插件时,请配置任务的classpath以包括developmentOnly
配置。
8.1 属性默认值
Spring Boot支持的一些库使用缓存来提高性能。例如,模板引擎缓存已编译的模板,以避免重复解析模板文件。同样,Spring MVC可以在提供静态资源时向响应添加HTTP缓存头。
尽管缓存在生产中非常有益,但在开发过程中可能适得其反,从而使您无法看到刚刚在应用程序中所做的更改。因此,默认情况下,spring-boot-devtools禁用缓存选项。
缓存选项通常由application.properties
文件中的设置配置。例如,Thymeleaf提供了spring.thymeleaf.cache
属性。spring-boot-devtools
模块无需手动设置这些属性,而是自动应用合理的开发时配置。
由于在开发Spring MVC和Spring WebFlux应用程序时需要有关Web请求的更多信息,因此开发人员工具开启web
日志组的DEBUG
选项来记录日志。这将为您提供有关传入请求、处理该请求的处理器、响应结果等的信息。如果您希望记录所有请求的详细信息(包括潜在的敏感信息),则可以打开spring.mvc.log-request-details
或spring.codec.log-request-details
配置属性。
如果你不想属性的默认值被应用,可以在
application.properties
中设置spring.devtools.add-properties
为false
。有关devtools应用的完整属性列表,请参见DevToolsPropertyDefaultsPostProcessor。
8.2 自动重启
应用了spring-boot-devtools
的应用程序,只要classpath上的文件发生变化,应用程序就会自动重新启动。当在IDE中工作时,这可能是一个有用的功能,因为它为代码更改提供了非常快速的反馈循环。默认情况下,将监视类路径上指向目录的任何条目的更改。请注意,某些资源(例如静态资源和视图模板)不需要重新启动应用程序。
触发重启 当DevTools监视类路径资源时,触发重启的唯一方法是类路径中资源更新。导致类路径更新的方式取决于您使用的IDE。在Eclipse中,保存修改后的文件将导致类路径被更新并触发重新启动。在IntelliJ IDEA中,构建项目(
Build +→+ Build Project
)具有相同的效果。因为DevTools需要隔离的应用程序类加载器才能正常运行,只要启用了分叉(forking),您还可以使用受支持的构建插件(Maven和Gradle)启动应用程序。默认情况下,Gradle和Maven插件会分叉(fork)应用程序进程。
与LiveReload一起使用时,自动重新启动效果很好。 有关详细信息,请参见LiveReload部分。如果使用JRebel,则禁用自动重新启动,而支持动态类重新加载。其他devtools功能(例如LiveReload和属性重载)仍可以使用。
DevTools依靠应用程序上下文的关闭钩子(hook)在重新启动期间将其关闭。如果您禁用了关闭钩子(
SpringApplication.setRegisterShutdownHook(false)
),它将无法正常工作。当在classpath中的条目发生变化时候,DevTools自动忽略项目命名为
spring-boot
,spring-boot-devtools
,spring-boot-autoconfigure
,spring-boot-actuator
,和spring-boot-starter
的项目,而不触发重启。DevTools需要使用
ApplicationContext
来定制ResourceLoader
。如果您的应用程序已经提供了,它将被隐藏。不支持直接覆盖ApplicationContext
的getResource
方法。重新启动与重新加载 Spring Boot提供的重启技术通过使用两个类加载器来工作。不变的类(例如,来自第三方的jar包)将被加载到基本类加载器中。您正在积极开发的类将加载到重新启动类加载器中。重新启动应用程序后,将丢弃原有的重新启动类加载器,并创建一个新的。这种方法意味着应用程序的重启通常比“冷启动”要快得多,因为基本类加载器已经可用并已自动填充。 如果发现重新启动对于您的应用程序而言不够快,或者遇到类加载问题,则可以考虑重新加载技术,例如ZeroTurnaround的JRebel的技术。这些方法通过在加载类时重写类来使其更易于重新加载。
8.2.1 记录状态诊断中的变化
默认情况下,每次应用程序重新启动时,都会记录一个报告,其中显示了状态诊断的增量信息。该报告显示了在进行更改(例如,添加或删除Bean以及设置配置属性)时对应用程序自动配置的更改。
要禁用报告的此日志记录,请设置以下属性:
Properties:
spring.devtools.restart.log-condition-evaluation-delta=false
Yaml:
spring:
devtools:
restart:
log-condition-evaluation-delta: false
8.2.2 排除资源
某些资源在更改后不是必然需要触发重新启动。例如,Thymeleaf模板可以就地编辑。默认情况下,改变资源/META-INF/maven
,/META-INF/resources
,/resources
,/static
,/public
,或/templates
不触发重新启动,但确会触发实时重新装载(live reload)。如果要自定义这些排除项,则可以使用spring.devtools.restart.exclude
属性。例如,仅排除/static
,/public
您将设置以下属性:
Properties:
spring.devtools.restart.exclude=static/**,public/**
Yaml:
spring:
devtools:
restart:
exclude: "static/**,public/**"
如果要保留这些默认值并添加其他排除项,使用
spring.devtools.restart.additional-exclude
属性。
8.2.3 观看其他路径
当您对不在类路径上的文件进行更改时,您可能希望重新启动或重新加载应用程序。为此,请使用该spring.devtools.restart.additional-paths
属性来配置其他路径以监视更改。您可以使用前面描述的spring.devtools.restart.exclude
属性来控制其他路径下的更改是触发完全重新启动还是实时重新加载(live reload)。
8.2.4 禁用重启
如果您不想使用重新启动功能,则可以使用spring.devtools.restart.enabled
属性将其禁用。在大多数情况下,您可以在您的application.properties
中设置此属性(这样做仍会初始化重新启动类加载器,但它不会监视文件更改)。
如果您需要完全禁用重启支持(例如,因为它不适用于特定的库),则需要在调用SpringApplication.run(…)
之前将System
属性spring.devtools.restart.enabled
设置为false,如以下示例所示:
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(MyApp.class, args);
}
8.2.5 使用触发文件
如果使用持续编译更改文件的IDE,则可能更喜欢仅在特定时间触发重新启动。为此,您可以使用“触发文件”,这是一个特殊文件,当您要实际触发重新启动检查时必须对其进行修改。
对文件的任何更新都会触发检查,但是只有在Devtools检测到确实需要的情况下,重启才会真正发生。
要使用触发文件,请将spring.devtools.restart.trigger-file
属性设置为触发文件的名称(不包括任何路径)。触发文件必须出现在类路径上的某个位置。
例如,如果您的项目具有以下结构:
src
+- main
+- resources
+- .reloadtrigger
那么您的trigger-file
属性将是:
Properties:
spring.devtools.restart.trigger-file=.reloadtrigger
Yaml:
spring:
devtools:
restart:
trigger-file: ".reloadtrigger"
现在,仅当src/main/resources/.reloadtrigger
更新时才重新启动。
您可能希望将
spring.devtools.restart.trigger-file
设置为全局设置,以便所有项目以相同的方式运行。
某些IDE具有使您不必手动更新触发器文件的功能。 Spring Tools for Eclipse和IntelliJ IDEA(旗舰版)都具有这种支持。使用Spring Tools,您可以从控制台视图中使用“重新加载”按钮(只要您的trigger-file
文件名为.reloadtrigger
)。对于IntelliJ IDEA,您可以按照其文档中的说明进行操作。
8.2.6 自定义重启类加载器(Restart Classloader)
如前面的“重新启动与重新加载”部分所述,重新启动功能是通过使用两个类加载器实现的。对于大多数应用程序,此方法效果很好。但是,有时可能会导致类加载问题。
默认情况下,IDE中的任何打开的项目均使用“重新启动”类加载器加载,而任何常规.jar
文件均使用“基本”类加载器加载。如果您在多模块项目上工作,并且并非每个模块都导入到IDE中,则可能需要自定义类它(重启类加载器)。为此,您可以创建一个META-INF/spring-devtools.properties
文件。spring-devtools.properties
文件可以包含以restart.exclude
和restart.include
开头的属性。include
元素是应该被拉高到“重启”类加载器中的项目,以及exclude
元素是应该被推入“基础”类加载器的项目。该属性的值是应用于类路径的正则表达式模式,如以下示例所示:
Properties:
restart.exclude.companycommonlibs=/mycorp-common-[\\w\\d-\\.]+\\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w\\d-\\.]+\\.jar
Yaml :
restart:
exclude:
companycommonlibs: "/mycorp-common-[\\w\\d-\\.]+\\.jar"
include:
projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"
所有属性的键都必须是唯一的。只要属性以
restart.include.
或restart.exclude.
开头,就可以认为是相关属性。所有类路径下的
META-INF/spring-devtools.properties
都会被加载。您可以将文件打包在项目内部或项目使用的库中。
8.2.7 已知局限性
重新启动功能不适用于通过使用标准ObjectInputStream
反序列化的对象。如果你需要反序列化的数据,你可能需要使用Thread.currentThread().getContextClassLoader()
结合Spring的ConfigurableObjectInputStream
实现。
不幸的是,一些第三方库在不考虑上下文类加载器的情况下反序列化。如果发现这样的问题,则需要向原始作者请求修复。
8.3 实时重载(LiveReload)
spring-boot-devtools
模块包括一个嵌入式的LiveReload服务器,该服务器可用于在资源变化时触发浏览器刷新。可从livereload.com免费获得适用于Chrome、Firefox和Safari的LiveReload浏览器扩展。
如果您不想在应用程序运行时启动LiveReload服务器,则可以将spring.devtools.livereload.enabled
属性设置为false
。
一次只能运行一台LiveReload服务器。在启动应用程序之前,请确保没有其他LiveReload服务器正在运行。如果从IDE启动多个应用程序,则只有第一个具有LiveReload支持。
要在文件更改时触发LiveReload,必须启用自动重启。
8.4 全局设置
您可以通过将以下任何文件添加到$HOME/.config/spring-boot
目录来配置全局devtools设置:
spring-boot-devtools.properties
spring-boot-devtools.yaml
spring-boot-devtools.yml
添加到这些文件的任何属性都将应用于在您计算机上使用devtools的_所有_Spring Boot应用程序。例如,要将重新启动配置为始终使用触发文件,您可以在你的spring-boot-devtools
文件中添加以下属性:
Properties:
spring.devtools.restart.trigger-file=.reloadtrigger
Yaml :
spring:
devtools:
restart:
trigger-file: ".reloadtrigger"
如果在
$HOME/.config/spring-boot
目录中找不到devtools配置文件,则在$HOME
的根目录中搜索是否存在.spring-boot-devtools.properties
文件。这使您可以在与不支持$HOME/.config/spring-boot
位置的旧版Spring Boot上的应用程序上共享devtools全局配置。devtools的properties/yaml文件中不支持配置(指的是特定于不同环境等的配置,例如
spring-boot-devtools-<profile>.properties
)。 任何在.spring-boot-devtools.properties
文件中激活的配置都不会影响特定配置的配置文件的加载。特定配置的文件名(格式为spring-boot-devtools-<profile>.properties
)以及spring.config.activate.on-profile
文档在properties和yaml格式文件上都不被支持。
8.4.1 配置文件系统观察器
FileSystemWatcher的工作方式是按一定时间间隔轮询类的更改,然后等待预定义的静默期以确保没有更多更改。由于Spring Boot完全依赖IDE来编译文件并将其复制到Spring Boot可以读取的位置,因此您可能会发现,有时候devtools重新启动应用程序时某些更改未反映出来。如果您经常观察到此类问题,请尝试增加spring.devtools.restart.poll-interval
和spring.devtools.restart.quiet-period
参数,设置适合您的开发环境的值:
Properties:
spring.devtools.restart.poll-interval=2s
spring.devtools.restart.quiet-period=1s
Yaml :
spring:
devtools:
restart:
poll-interval: "2s"
quiet-period: "1s"
现在每2秒轮询一次受监视的类路径目录以查找更改,并保持1秒钟的静默时间以确保没有其他类被更改。
8.5 远程应用
Spring Boot开发人员工具不仅限于本地开发。远程运行应用程序时,您还可以使用多种功能。远程支持选项被启用可能会带来安全风险。仅当在受信任的网络上运行或使用SSL保护时,才应启用它。如果这两个选项都不可用,则不应使用DevTools的远程支持。您永远不要在生产部署上启用此支持。
要启用它,您需要确保已将devtools
引入到重新打包的存档中,如以下清单所示:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
</plugins>
</build>
然后,您需要设置spring.devtools.remote.secret
属性。像任何重要的密码或机密一样,该值应唯一且强壮,以免被猜测或强行使用。
远程devtools支持分为两个部分:接受连接的服务器端终结点和在IDE中运行的客户端应用程序。spring.devtools.remote.secret
属性被设置后,将自动启用服务器组件,客户端组件必须手动启动。
8.5.1 运行远程客户端应用程序
远程客户端应用程序旨在在您的IDE中运行。您需要使用与所连接的远程项目相同的类路径下运行org.springframework.boot.devtools.RemoteSpringApplication
。应用程序的唯一必需参数是它要连接到远程的URL。
例如,如果您正在使用Eclipse或STS,并且有一个my-app
已部署到Cloud Foundry的项目,则应执行以下操作:
- 从
Run
菜单选择Run Configurations…
。 - 创建一个新的
Java Application
“启动配置”。 - 浏览该
my-app
项目。 - 使用
org.springframework.boot.devtools.RemoteSpringApplication
作为主类。 - 添加
[https://myapp.cfapps.io](https://myapp.cfapps.io)
(或者任意远程的URL)到Program arguments
。
正在运行的远程客户端可能类似于以下清单:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \
\\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) )
' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
=========|_|==============|___/===================================/_/_/_/
:: Spring Boot Remote :: 2.4.0-SNAPSHOT
2015-06-10 18:25:06.632 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication : Starting RemoteSpringApplication on pwmbp with PID 14938 (/Users/pwebb/projects/spring-boot/code/spring-boot-project/spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code)
2015-06-10 18:25:06.671 INFO 14938 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2a17b7b6: startup date [Wed Jun 10 18:25:06 PDT 2015]; root of context hierarchy
2015-06-10 18:25:07.043 WARN 14938 --- [ main] o.s.b.d.r.c.RemoteClientConfiguration : The connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'.
2015-06-10 18:25:07.074 INFO 14938 --- [ main] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2015-06-10 18:25:07.130 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication : Started RemoteSpringApplication in 0.74 seconds (JVM running for 1.105)
因为远程客户端使用与真实应用程序相同的类路径,所以它可以直接读取应用程序属性。这就是
spring.devtools.remote.secret
读取属性并将其传递给服务器进行身份验证的方式。始终建议将其
https://
用作连接协议,以便对数据流进行加密并且不被截获密码。如果您需要使用代理来访问远程应用程序,请配置
spring.devtools.remote.proxy.host
和spring.devtools.remote.proxy.port
属性。
8.5.2 远程更新
远程客户端以与本地重新启动相同的方式监视应用程序类路径中的更改。任何更新的资源都会推送到远程应用程序,并且(如果需要)会触发重新启动。如果您迭代使用本地没有的云服务的功能,这将很有帮助。通常,远程更新和重新启动比完整的重新构建和部署周期要快得多。
在较慢的开发环境中,可能会发生由于静默期时长不足而导致类中的更改被切割到不同的批次。第一批次更改的类上传后,服务器将重新启动。由于服务器正在重新启动,因此下一批次不能发送到应用程序。
这通常通过RemoteSpringApplication
日志中存在关于无法上传某些类的警告以及随后的重试来体现。但是,这也可能导致在第一批次的变化上传后应用程序代码不一致和重新启动失败。如果您经常观察到此类问题,请尝试将spring.devtools.restart.poll-interval
和spring.devtools.restart.quiet-period
参数的值增加到适合您的开发环境。请参阅“配置文件系统监视程序”部分以配置这些属性。
仅在远程客户端运行时才监视文件。如果在启动远程客户端之前更改文件,则不会将其推送到远程服务器。