Developer Tools

Spring Boot 包含了另外一组可以使应用程序开发体验更愉快的工具。任何项目都可以包含`spring-boot-devtools`模块,以提供额外的开发时间功能。如以下针对 Maven 和 Gradle 的清单所示,要包含 devtools 支持,请将模块依赖项添加到您的构建中:

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")
}

Devtools 可能会导致类加载问题,特别是在多模块项目中。Diagnosing Classloading Issues说明了如何诊断和解决它们。

在运行完全打包的应用程序时,开发人员工具会自动禁用。如果您的应用程序从`java -jar`启动,或者从特殊类加载器启动,则它被视为"`production application`"。您可以使用`spring.devtools.restart.enabled`系统属性来控制此行为。要启用 devtools,无论用来启动应用程序的类加载器如何,请设置`-Dspring.devtools.restart.enabled=true`系统属性。不能在生产环境中执行此操作,因为在此环境下运行 devtools 是一个安全风险。要禁用 devtools,请排除依赖项或设置 -Dspring.devtools.restart.enabled=false 系统属性。

以可选形式在 Maven 中标记依赖项或使用 Gradle 中的`developmentOnly`配置(如上所示),可以防止 devtools 传递性地应用于使用您的项目的其他模块。

重新打包的存档默认情况下不包含 devtools。如果您想使用 certain remote devtools feature,您需要包括它。使用 Maven 插件时,将 excludeDevtools 属性设置为 false。使用 Gradle 插件时,configure the task’s classpath to include the developmentOnly configuration

Diagnosing Classloading Issues

正如 Restart vs Reload 部分中所述,重新启动功能是通过使用两个类加载器实现的。对于大多数应用程序,此方法运行良好。但是,它有时会导致类加载问题,特别是在多模块项目中。

若要诊断类加载问题实际上是由 devtools 及其两个类加载器导致的,try disabling restart。如果这解决了您的问题,customize the restart classloader 以包含您的整个项目。

Property Defaults

Spring Boot 支持的几个库使用缓存来提高性能。例如,template engines 缓存编译的模板以避免重复解析模板文件。此外,Spring MVC 可以在提供静态资源时为响应添加 HTTP 缓存标头。

虽然缓存对于生产非常有益,但它在开发过程中可能适得其反,从而阻止您看到您刚刚在应用程序中所做的更改。出于此原因,spring-boot-devtools 默认禁用缓存选项。

缓存选项通常由 application.properties 文件中的设置配置。例如,Thymeleaf 提供 configprop:spring.thymeleaf.cache[] 属性。spring-boot-devtools 模块会自动应用合理的开发时间配置,而无需手动设置这些属性。

下表列出了应用的所有属性:

Unresolved include directive in modules/ROOT/pages/using/devtools.adoc - include::ROOT:partial$propertydefaults/devtools-property-defaults.adoc[]

如果您不希望应用属性默认值,您可以在 application.properties 中将 configprop:spring.devtools.add-properties[] 设置为 false

由于您在开发 Spring MVC 和 Spring WebFlux 应用程序时需要更多有关网络请求的信息,开发人员工具建议您为 web 日志组启用 DEBUG 日志记录。这将为您提供有关传入请求、哪个处理程序正在处理它、响应结果和其他详细信息的信息。如果您希望记录所有请求详细信息(包括可能包含敏感信息),则可以打开 configprop:spring.mvc.log-request-details[] 或 configprop:spring.codec.log-request-details[] 配置属性。

Automatic Restart

使用 spring-boot-devtools 的应用程序会在类路径上的文件发生更改时自动重新启动。由于这为代码更改提供了非常快的反馈环路,因此当在 IDE 中工作时,这可能是一个有用的功能。默认情况下,指向目录的类路径上的任何条目都将受到更改的监视。请注意,诸如静态资源和视图模板等特定资源,do not need to restart the application

Triggering a restart

由于 DevTools 监视类路径资源,因此触发重启的唯一方法是更新类路径。无论您使用的是 IDE 还是其中一个构建插件,都必须重新编译已修改的文件才能触发重启。导致类路径更新的方式取决于您正在使用的工具:

  • 在 Eclipse 中,保存修改后的文件会导致类路径更新并触发重启。

  • 在 IntelliJ IDEA 中,构建项目 (Build -> Build Project) 会产生相同的效果。

  • 如果使用构建插件,运行 Maven 的 mvn compile 或 Gradle 的 gradle build 会触发重启。

如果您使用构建插件通过 Maven 或 Gradle 重新启动,则必须将 forking 设置为 enabled。如果您禁用派生,devtools 使用的孤立应用程序类加载器将不会被创建,并且重启将无法正常运行。

当与 LiveReload 一起使用时,自动重启效果很好。See the LiveReload section 有关详细信息。如果您使用 JRebel,则为了动态类重新加载而禁用了自动重启。其他 devtools 功能(例如 LiveReload 和属性覆盖)仍然可以使用。

DevTools 依赖于应用程序上下文的关闭钩子在重启期间关闭它。如果您禁用了关闭钩子 (SpringApplication.setRegisterShutdownHook(false)),它将无法正常工作。

DevTools 需要自定义 ApplicationContext 使用的 ResourceLoader。如果您的应用程序已经提供了一个,它将被包装。不支持直接覆盖 ApplicationContextgetResource 方法。

使用 AspectJ 织入时不支持自动重新启动。

Restart vs Reload

Spring Boot 提供的重新启动技术使用两个类加载器。不会更改的类(例如,来自第三方文件 jar 的类)将加载到 base 类加载器中。正在积极开发的类将加载到 restart 类加载器中。在重新启动应用程序时,将丢弃 restart 类加载器并创建一个新的类加载器。这种方法意味着应用程序的重新启动通常比 “cold starts” 快得多,因为 base 类加载器已可用且已填充。 如果你发现你的应用程序的重新启动速度不够快,或遇到类加载问题,可以考虑使用 ZeroTurnaround 的 JRebel 等重新加载技术。它们通过以更适合重新加载的方式重写加载的类来工作。

Logging Changes in Condition Evaluation

默认情况下,每次你的应用程序重新启动时,都会记录一份显示条件评估增量差的报告。该报告显示你的应用程序的自动配置的更改,例如添加或删除 Bean 以及设置配置属性。

若要禁用报告的记录,请设置以下属性:

spring:
  devtools:
    restart:
      log-condition-evaluation-delta: false

Excluding Resources

某些资源不一定需要在更改时触发重新启动。例如,Thymeleaf 模板可以就地编辑。默认情况下,在 /META-INF/maven, /META-INF/resources, /resources, /static, /public/templates 中更改资源不会触发重新启动,只会触发 live reload。如果你想自定义这些排除项,可以使用 configprop:spring.devtools.restart.exclude[] 属性。例如,若只想排除 /static/public,则需设置以下属性:

spring:
  devtools:
    restart:
      exclude: "static/**,public/**"

如果你想保留这些默认设置并 add 其他排除项,请改用 configprop:spring.devtools.restart.additional-exclude[] 属性。

Watching Additional Paths

你可能希望在对不在类路径上的文件进行更改时重新启动或重新加载你的应用程序。为此,请使用 configprop:spring.devtools.restart.additional-paths[] 属性来配置要监视的用于更改的其他路径。可以使用 configprop:spring.devtools.restart.exclude[] 属性 described earlier 控制其他路径下的更改是触发完全重新启动还是 live reload

Disabling Restart

如果你不想使用重新启动功能,可以使用 configprop:spring.devtools.restart.enabled[] 属性将其禁用。在大多数情况下,你可以在 application.properties 中设置此属性(这样做仍然会初始化重新启动类加载器,但不会监视文件更改)。

如果你需要 completely 禁用重新启动支持(例如,因为它不适用于特定库),你需要在调用 SpringApplication.run(…​) 之前将 configprop:spring.devtools.restart.enabled[] System 属性设置为 false,如下例所示:

Using a Trigger File

如果你使用的是不断编译已更改文件的 IDE,你可能更喜欢只在特定时间触发重新启动。为此,可以使用 “trigger file”,该 “trigger file” 是一个特殊文件,你需要在想要实际触发重新启动检查时对其进行修改。

对该文件的任何更新都将触发检查,但仅在 Devtools 检测到其有任务要做的前提下才会真正重新启动。

若要使用触发器文件,请将 configprop:spring.devtools.restart.trigger-file[] 属性设置为触发器文件的名称(不包括任何路径)。触发器文件必须出现在你的类路径的某个位置。

例如,如果你有一个如下结构的项目:

src
+- main
   +- resources
      +- .reloadtrigger

则你的 trigger-file 属性将为:

spring:
  devtools:
    restart:
      trigger-file: ".reloadtrigger"

现在只有在 src/main/resources/.reloadtrigger 更新时才会重新启动。

你可能希望将 spring.devtools.restart.trigger-file 设置为 global setting,以便你的所有项目都以相同的方式运行。

有些 IDE 具有无需手动更新触发器文件就能自动保存的特性。 Spring Tools for EclipseIntelliJ IDEA (Ultimate Edition) 都具有此类支持。对于 Spring Tools,可以使用控制台视图中的 “reload” 按钮(只要你的 trigger-file 命名为 .reloadtrigger)。对于 IntelliJ IDEA,可以按照 instructions in their documentation 的说明进行操作。

Customizing the Restart Classloader

Restart vs Reload 部分中前面所述,重新启动功能是通过使用两个类加载器实现的。如果这样会导致问题,你可能需要自定义哪个类加载器加载什么内容。

默认情况下,IDE 中任何打开的项目都会使用 “restart” 类加载器加载,任何常规 .jar 文件都会使用 “base” 类加载器加载。如果您使用 mvn spring-boot:rungradle bootRun,情况也是如此:包含 @SpringBootApplication 的项目使用 “restart” 类加载器加载,其他所有内容都使用 “base” 类加载器加载。

您可以通过创建 META-INF/spring-devtools.properties 文件指示 Spring Boot 使用不同的类加载器加载项目的各个部分。spring-devtools.properties 文件可以包含以 restart.excluderestart.include 为前缀的属性。include 元素应提升到 “restart” 类加载器中的项,exclude 元素应压入到 “base” 类加载器中的项。该属性值是一种正则表达式模式,适用于类路径,如下例所示:

restart:
  exclude:
    companycommonlibs: "/mycorp-common-[\\w\\d-\\.]+\\.jar"
  include:
    projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"

所有属性键必须唯一。只要属性以 restart.include.restart.exclude. 开头,就会考虑它。

来自类路径的所有 META-INF/spring-devtools.properties 都已加载。您可以在项目中或项目使用的库中打包文件。

Known Limitations

重新启动功能不适用于使用标准 ObjectInputStream 反序列化的对象。如果您需要反序列化数据,可能需要将 Spring 的 ConfigurableObjectInputStreamThread.currentThread().getContextClassLoader() 结合使用。

不幸的是,一些第三方库在反序列化时没有考虑上下文类加载器。如果您发现此类问题,您需要向原始作者报告。

LiveReload

spring-boot-devtools 模块包含一个嵌入式 LiveReload 服务器,当资源更改时可以使用该服务器触发浏览器刷新。LiveReload 浏览器扩展程序可免费用于 Chrome、Firefox 和 Safari。您可以在所选浏览器的市场或商店中搜索“LiveReload”来查找这些扩展程序。

如果您不想在应用程序运行时启动 LiveReload 服务器,则可以将 configprop:spring.devtools.livereload.enabled[] 属性设置为 false

您一次只能运行一个 LiveReload 服务器。启动应用程序之前,请确保没有其他 LiveReload 服务器正在运行。如果您从 IDE 启动多个应用程序,则只有第一个应用程序有 LiveReload 支持。

要在文件更改时触发 LiveReload,必须启用 Automatic Restart

Global Settings

您可以通过将以下任何文件添加到 $HOME/.config/spring-boot 目录,来配置全局 DevTools 设置:

  1. spring-boot-devtools.properties

  2. spring-boot-devtools.yaml

  3. spring-boot-devtools.yml

添加到这些文件的任何属性都适用于计算机上使用 DevTools 的 all Spring Boot 应用程序。例如,要配置重新启动始终使用 trigger file,您需要将以下属性添加到 spring-boot-devtools 文件:

spring:
  devtools:
    restart:
      trigger-file: ".reloadtrigger"

默认情况下,$HOME 是用户的 home 目录。要自定义此位置,请设置 SPRING_DEVTOOLS_HOME 环境变量或 spring.devtools.home 系统属性。

如果在 $HOME/.config/spring-boot 中找不到 DevTools 配置文件,则会搜索 $HOME 目录的根目录是否存在 .spring-boot-devtools.properties 文件。这允许您将 DevTools 全局配置与运行在不支持 $HOME/.config/spring-boot 位置的较旧版本 Spring Boot 上的应用程序共享。

配置文件不受 DevTools 属性/yaml 文件支持。 在 .spring-boot-devtools.properties 中激活的任何配置文件都不会影响 profile-specific configuration files 的加载。YAML 和属性文件中的特定于配置文件的文件名(采用 spring-boot-devtools-<profile>.properties 形式)和 spring.config.activate.on-profile 文档不受支持。

Configuring File System Watcher

{code-spring-boot-devtools-src}/filewatch/FileSystemWatcher.java[FileSystemWatcher] 通过以特定时间间隔轮询类更改来工作,然后等待预定义的静默期以确保没有更多更改。由于 Spring Boot 完全依赖于 IDE 将文件编译并复制到 Spring Boot 可以读取它们的位置,因此您可能会发现某些更改在 DevTools 重启应用程序时未反映出来。如果您不断观察到此类问题,请尝试将 spring.devtools.restart.poll-intervalspring.devtools.restart.quiet-period 参数增加到适合您的开发环境的值:

spring:
  devtools:
    restart:
      poll-interval: "2s"
      quiet-period: "1s"

现在,每 2 秒就会轮询被监视的类路径目录是否有更改,并维持 1 秒的静默期以确保没有其他类更改。

Remote Applications

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>

然后,您需要设置 configprop:spring.devtools.remote.secret[] 属性。像任何重要的密码或秘密一样,该值应该唯一且可靠,以致无法猜测或暴力破解。

远程 devtools 支持分为两部分提供:接受连接的服务器端端点和您在 IDE 中运行的客户端应用程序。当 configprop:spring.devtools.remote.secret[] 属性时,会自动启用服务器组件。客户端组件必须手动启动。

不支持 Spring WebFlux 应用程序的远程 devtools。

Running the Remote Client Application

远程客户端应用程序设计用于在您的 IDE 中运行。您需要使用与连接到的远程项目相同的类路径运行 org.springframework.boot.devtools.RemoteSpringApplication。该应用程序的唯一必需参数是它连接到的远程 URL。

例如,如果您使用 Eclipse 或 Spring Tools,并且已经将名为 my-app 的项目部署到 Cloud Foundry,则您将执行以下操作:

  • Run 菜单中选择 Run Configurations&#8230;&#8203;

  • 创建一个新的 Java Application “launch configuration”。

  • 浏览 my-app 项目。

  • 使用 org.springframework.boot.devtools.RemoteSpringApplication 作为主类。

  • Program arguments 中添加 https://myapp.cfapps.io(或您的远程 URL)。

正在运行的远程客户端可能如下所示:

Unresolved include directive in modules/ROOT/pages/using/devtools.adoc - include::ROOT:example$remote-spring-application.txt[]

由于远程客户端使用与实际应用程序相同的类路径,因此它可以直接读取应用程序属性。这就是读取 configprop:spring.devtools.remote.secret[] 属性并将其传递给服务器以进行身份验证的方式。

始终建议将 https:// 用作连接协议,以便对流量进行加密且无法截获密码。

如果您需要使用代理访问远程应用程序,请配置 spring.devtools.remote.proxy.hostspring.devtools.remote.proxy.port 属性。

Remote Update

远程客户端以与 local restart 相同的方式监视应用程序类路径是否有变化。将任何更新的资源推送到远程应用程序,并且 (if required) 触发重启。如果您正在使用本地没有的云服务的功能,这将很有用。通常,远程更新和重启比完全重建和部署周期快得多。

在较慢的开发环境中,可能会发生安静时间不足,并且类中的更改可能会分成批次。在上传第一批类更改后重新启动服务器。由于服务器正在重新启动,因此无法将下一批发送到应用程序。

这通常由 RemoteSpringApplication 日志中有关无法上传某些类的警告以及随后的重试来体现。但它也可能导致应用程序代码不一致,并在上传第一批更改后无法重新启动。如果您经常观察到此类问题,请尝试将 spring.devtools.restart.poll-intervalspring.devtools.restart.quiet-period 参数增加为您满足您的开发环境的值。请参阅 Configuring File System Watcher 部分来配置这些属性。

只有在远程客户端运行时才监控文件。如果您在启动远程客户端之前更改了文件,则不会将其推送到远程服务器。