开发者工具

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")
}
Devtools 可能会导致类加载问题,尤其是在多模块项目中。 诊断类加载问题 解释了如何诊断和解决这些问题。
在运行完全打包的应用程序时,开发人员工具会自动禁用。如果您的应用程序是从 java -jar 启动的,或者是从特殊的类加载器启动的,那么它被认为是“生产应用程序”。您可以使用 spring.devtools.restart.enabled 系统属性来控制此行为。要启用 devtools,无论用于启动应用程序的类加载器如何,请设置 -Dspring.devtools.restart.enabled=true 系统属性。这不能在运行 devtools 会造成安全风险的生产环境中进行。要禁用 devtools,请排除依赖项或设置 -Dspring.devtools.restart.enabled=false 系统属性。
在 Maven 中将依赖项标记为可选,或在 Gradle 中使用 developmentOnly 配置(如上所示)可以防止 devtools 被传递应用到使用您的项目的其他模块。
默认情况下,重新打包的存档不包含 devtools。如果您想使用 某些远程 devtools 功能,则需要包含它。使用 Maven 插件时,将 excludeDevtools 属性设置为 false。使用 Gradle 插件时,配置任务的类路径以包含 developmentOnly 配置

诊断类加载问题

重启与重新加载 部分所述,重启功能是通过使用两个类加载器来实现的。对于大多数应用程序来说,这种方法效果很好。但是,它有时会导致类加载问题,尤其是在多模块项目中。

要诊断类加载问题是否确实是由于 devtools 及其两个类加载器造成的,尝试禁用重启。如果这解决了您的问题,自定义重启类加载器 以包含您的整个项目。

属性默认值

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

虽然缓存对生产环境非常有利,但在开发过程中却可能适得其反,阻止您看到对应用程序所做的更改。为此,spring-boot-devtools 默认情况下会禁用缓存选项。

缓存选项通常通过您 application.properties 文件中的设置进行配置。例如,Thymeleaf 提供了 spring.thymeleaf.cache 属性。spring-boot-devtools 模块会自动应用合理的开发时配置,而不是需要手动设置这些属性。

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

名称 默认值

server.error.include-binding-errors

always

server.error.include-message

always

server.error.include-stacktrace

always

server.servlet.jsp.init-parameters.development

true

server.servlet.session.persistent

true

spring.docker.compose.readiness.wait

only-if-started

spring.freemarker.cache

false

spring.graphql.graphiql.enabled

true

spring.groovy.template.cache

false

spring.h2.console.enabled

true

spring.mustache.servlet.cache

false

spring.mvc.log-resolved-exception

true

spring.reactor.netty.shutdown-quiet-period

0s

spring.template.provider.cache

false

spring.thymeleaf.cache

false

spring.web.resources.cache.period

0

spring.web.resources.chain.cache

false

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

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

自动重启

使用 spring-boot-devtools 的应用程序会在类路径上的文件发生更改时自动重启。这在使用 IDE 时可能是一个有用的功能,因为它为代码更改提供了非常快速的反馈循环。默认情况下,类路径上指向目录的任何条目都会被监控以进行更改。请注意,某些资源(例如静态资产和视图模板)不需要重启应用程序

触发重启

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

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

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

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

如果使用构建插件通过 Maven 或 Gradle 重启,必须将 forking 设置为 enabled。如果禁用 forking,devtools 使用的隔离应用程序类加载器将不会创建,重启将无法正常工作。
自动重启与 LiveReload 一起使用时效果很好。有关详细信息,请参阅 LiveReload 部分。如果您使用 JRebel,则会禁用自动重启,转而使用动态类重新加载。其他 devtools 功能(如 LiveReload 和属性覆盖)仍然可以使用。
DevTools 依赖于应用程序上下文的关闭钩子在重启期间关闭它。如果您禁用了关闭钩子(SpringApplication.setRegisterShutdownHook(false)),它将无法正常工作。
DevTools 需要自定义 ApplicationContext 使用的 ResourceLoader。如果您的应用程序已经提供了一个,它将被包装。不支持直接覆盖 ApplicationContext 上的 getResource 方法。
使用 AspectJ 织入时不支持自动重启。
重启与重新加载

Spring Boot 提供的重启技术使用两个类加载器。不会更改的类(例如,来自第三方 jar 的类)加载到 基本 类加载器中。您正在积极开发的类加载到 重启 类加载器中。当应用程序重启时,重启 类加载器将被丢弃,并创建一个新的类加载器。这种方法意味着应用程序重启通常比“冷启动”快得多,因为 基本 类加载器已经可用并已填充。

如果您发现重启对于您的应用程序不够快,或者您遇到类加载问题,您可以考虑使用 ZeroTurnaround 的 JRebel 等重新加载技术。这些技术通过在加载类时重写类来使它们更容易重新加载。

记录条件评估中的更改

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

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

  • 属性

  • YAML

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

排除资源

某些资源不一定需要在更改时触发重启。例如,Thymeleaf 模板可以在原地编辑。默认情况下,更改 /META-INF/maven/META-INF/resources/resources/static/public/templates 中的资源不会触发重启,但会触发 实时重新加载。如果您想自定义这些排除项,可以使用 spring.devtools.restart.exclude 属性。例如,要仅排除 /static/public,您将设置以下属性

  • 属性

  • YAML

spring.devtools.restart.exclude=static/**,public/**
spring:
  devtools:
    restart:
      exclude: "static/**,public/**"
如果您想保留这些默认值并添加其他排除项,请使用spring.devtools.restart.additional-exclude属性。

监视其他路径

您可能希望在更改类路径之外的文件时重新启动或重新加载应用程序。为此,请使用spring.devtools.restart.additional-paths属性配置要监视更改的其他路径。您可以使用spring.devtools.restart.exclude属性如前所述来控制其他路径下的更改是否触发完全重启或实时重新加载

禁用重启

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

如果您需要完全禁用重启支持(例如,因为它不适用于特定库),您需要在调用SpringApplication.run(…​)之前将spring.devtools.restart.enabledSystem属性设置为false,如以下示例所示

  • Java

  • Kotlin

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		System.setProperty("spring.devtools.restart.enabled", "false");
		SpringApplication.run(MyApplication.class, args);
	}

}
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication

@SpringBootApplication
object MyApplication {

	@JvmStatic
	fun main(args: Array<String>) {
		System.setProperty("spring.devtools.restart.enabled", "false")
		SpringApplication.run(MyApplication::class.java, *args)
	}

}

使用触发文件

如果您使用的是持续编译更改文件的 IDE,您可能更喜欢仅在特定时间触发重启。为此,您可以使用“触发文件”,这是一个特殊文件,您需要在实际触发重启检查时修改它。

对该文件的任何更新都会触发检查,但只有在 Devtools 检测到它有操作时才会实际重启。

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

例如,如果您有一个具有以下结构的项目

src
+- main
   +- resources
      +- .reloadtrigger

那么您的trigger-file属性将是

  • 属性

  • YAML

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

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

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

一些 IDE 具有可以免除您手动更新触发文件的特性。 Spring Tools for EclipseIntelliJ IDEA(终极版) 都具有此类支持。使用 Spring Tools,您可以从控制台视图中使用“重新加载”按钮(只要您的trigger-file名为.reloadtrigger)。对于 IntelliJ IDEA,您可以按照其文档中的说明进行操作。

自定义重启类加载器

如之前在重启与重新加载部分所述,重启功能是通过使用两个类加载器实现的。如果这会导致问题,您可以使用spring.devtools.restart.enabled系统属性诊断问题,如果应用程序在关闭重启的情况下工作,您可能需要自定义哪个类加载器加载什么内容。

默认情况下,IDE 中的任何打开的项目都使用“重启”类加载器加载,任何常规的.jar文件都使用“基础”类加载器加载。如果您使用mvn spring-boot:rungradle bootRun,情况也是如此:包含您的@SpringBootApplication的项目使用“重启”类加载器加载,其他所有内容使用“基础”类加载器加载。当您启动应用程序时,类路径会打印在控制台上,这有助于识别任何有问题的条目。反射使用的类,尤其是注释,可以在应用程序类使用它们之前在启动时加载到父(固定)类加载器中,这可能导致 Spring 在应用程序中无法检测到它们。

您可以通过创建一个META-INF/spring-devtools.properties文件来指示 Spring Boot 使用不同的类加载器加载项目的部分内容。spring-devtools.properties文件可以包含以restart.excluderestart.include为前缀的属性。include元素是应该拉到“重启”类加载器中的项目,exclude元素是应该推到“基础”类加载器中的项目。属性的值是一个正则表达式模式,它应用于启动时传递给 JVM 的类路径。以下是一个示例,其中一些本地类文件被排除,一些额外的库被包含在重启类加载器中

restart:
  exclude:
    companycommonlibs: "/mycorp-common-[\\w\\d-\\.]/(build|bin|out|target)/"
  include:
    projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"
所有属性键必须是唯一的。只要属性以restart.include.restart.exclude.开头,就会被考虑。
所有来自类路径的META-INF/spring-devtools.properties都会被加载。您可以将文件打包到项目中,或者打包到项目使用的库中。系统属性不能使用,只能使用属性文件。

已知限制

重启功能与使用标准ObjectInputStream反序列化的对象不兼容。如果您需要反序列化数据,您可能需要使用 Spring 的ConfigurableObjectInputStream结合Thread.currentThread().getContextClassLoader()

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

实时重新加载

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

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

您一次只能运行一个 LiveReload 服务器。在启动应用程序之前,请确保没有其他 LiveReload 服务器正在运行。如果您从 IDE 启动多个应用程序,则只有第一个应用程序支持 LiveReload。
要触发文件更改时的 LiveReload,必须启用 自动重启

全局设置

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

  1. spring-boot-devtools.properties

  2. spring-boot-devtools.yaml

  3. spring-boot-devtools.yml

添加到这些文件中的任何属性都适用于您机器上使用 devtools 的所有 Spring Boot 应用程序。例如,要将重启配置为始终使用 触发文件,您需要将以下属性添加到您的 spring-boot-devtools 文件中

  • 属性

  • YAML

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

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

如果在 $HOME/.config/spring-boot 中找不到 devtools 配置文件,则会搜索 $HOME 目录的根目录以查找 .spring-boot-devtools.properties 文件。这允许您与使用不支持 $HOME/.config/spring-boot 位置的旧版 Spring Boot 的应用程序共享 devtools 全局配置。

devtools 属性/yaml 文件不支持配置文件。

.spring-boot-devtools.properties 中激活的任何配置文件都不会影响 特定于配置文件的配置文件 的加载。YAML 和属性文件中的特定于配置文件的文件名(格式为 spring-boot-devtools-<profile>.properties)和 spring.config.activate.on-profile 文档不受支持。

配置文件系统监视器

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

  • 属性

  • YAML

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

现在每 2 秒轮询一次监视的类路径目录以查找更改,并保持 1 秒的静默期以确保没有其他类更改。

远程应用程序

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 属性时,服务器组件会自动启用。客户端组件必须手动启动。

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

运行远程客户端应用程序

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

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

  • 运行 菜单中选择 运行配置…​

  • 创建一个新的Java Application“启动配置”。

  • 浏览到my-app项目。

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

  • https://myapp.cfapps.io添加到程序参数(或您的远程 URL)。

运行中的远程客户端可能类似于以下列表

  .   ____          _                                              __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _          ___               _      \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` |        | _ \___ _ __  ___| |_ ___ \ \ \ \
 \\/  ___)| |_)| | | | | || (_| []::::::[]   / -_) '  \/ _ \  _/ -_) ) ) ) )
  '  |____| .__|_| |_|_| |_\__, |        |_|_\___|_|_|_\___/\__\___|/ / / /
 =========|_|==============|___/===================================/_/_/_/
 :: Spring Boot Remote ::  (v3.3.0)

2024-05-23T12:38:22.336Z  INFO 111074 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Starting RemoteSpringApplication v3.3.0 using Java 17.0.11 with PID 111074 (/Users/myuser/.m2/repository/org/springframework/boot/spring-boot-devtools/3.3.0/spring-boot-devtools-3.3.0.jar started by myuser in /opt/apps/)
2024-05-23T12:38:22.354Z  INFO 111074 --- [           main] o.s.b.devtools.RemoteSpringApplication   : No active profile set, falling back to 1 default profile: "default"
2024-05-23T12:38:23.720Z  INFO 111074 --- [           main] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2024-05-23T12:38:23.827Z  INFO 111074 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Started RemoteSpringApplication in 3.049 seconds (process running for 3.931)
由于远程客户端使用与实际应用程序相同的类路径,因此它可以直接读取应用程序属性。这就是spring.devtools.remote.secret属性如何读取并传递到服务器以进行身份验证的方式。
始终建议使用https://作为连接协议,以便对流量进行加密,并且无法拦截密码。
如果您需要使用代理访问远程应用程序,请配置spring.devtools.remote.proxy.hostspring.devtools.remote.proxy.port属性。

远程更新

远程客户端监控您的应用程序类路径以查找与本地重启相同方式的更改。任何更新的资源都会被推送到远程应用程序,并且(如果需要)会触发重启。如果您迭代使用本地没有的云服务的特性,这将非常有用。通常,远程更新和重启比完整的重建和部署周期快得多。

在较慢的开发环境中,静默期可能不够,类中的更改可能会被分成批次。服务器在第一批类更改上传后重启。下一批无法发送到应用程序,因为服务器正在重启。

这通常表现为RemoteSpringApplication日志中有关无法上传某些类的警告,以及随后的重试。但这也会导致应用程序代码不一致,并在第一批更改上传后无法重启。如果您经常观察到此类问题,请尝试将spring.devtools.restart.poll-intervalspring.devtools.restart.quiet-period参数增加到适合您的开发环境的值。有关配置这些属性的信息,请参见配置文件系统监视器部分。

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