Bootstrap

Spring Boot DevTools(官网文档解读)

摘要

       Spring Boot DevTools 是专为开发者设计的辅助工具模块,它旨在提升开发效率,加速应用的开发与部署流程。本文基于Spring官方文档中关于DevTools的指导,旨在为广大学习者和开发者提供一个实用的参考资料。

devtools 启用

        要启用 Spring Boot devtools 的功能,只需在项目的依赖中加入 spring-boot-devtools 即可。

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-devtools</artifactId>
		<optional>true</optional>
	</dependency>
</dependencies>
  • 其中<optional>true</optional> 可以使该依赖只适用于开发环境,在打包引入依赖时不会添加此依赖。

  • 运行完整打包的应用程序时,开发人员工具会自动禁用。如果您的应用程序是从java -jar特殊类加载器启动的,则它被视为“生产应用程序”。您可以使用spring.devtools.restart.enabled系统属性控制此行为。

    • 要启用 devtools(无论用于启动应用程序的类加载器是什么),请设置-Dspring.devtools.restart.enabled=true系统属性。在运行 devtools 存在安全风险的生产环境中,不得执行此操作。

    • 要禁用 devtools,请排除依赖项或设置-Dspring.devtools.restart.enabled=false系统属性。

属性默认值设置

        Spring Boot 支持的多个库都使用缓存来提高性能。例如,模板引擎会缓存已编译的模板,以避免重复解析模板文件。此外,Spring MVC 可以在提供静态资源时向响应添加 HTTP 缓存标头。虽然缓存在生产环境中非常有用,但在开发过程中可能会适得其反,导致您无法看到刚刚在应用程序中所做的更改。

        因此spring-boot-devtools 默认禁用一系列模块的缓存选项。以下是官网提供的devTools 属性默认值参数列表以及补充说明:

属性默认值说明

server.error.include-binding-errors

always

控制是否在服务器错误响应中包含数据绑定错误。

server.error.include-message

always

控制是否在服务器错误响应中包含异常的具体消息。

server.error.include-stacktrace

always

控制是否在服务器错误响应中包含异常的堆栈跟踪信息。

server.servlet.jsp.init-parameters.development

true

控制JSPServlet的初始化参数,设置为true表示启用开发模式,会影响JSP页面的编译和重新加载行为。

server.servlet.session.persistent

true

控制服务器是否应该将HTTP会话持久化到磁盘上。

spring.docker.compose.readiness.wait

only-if-started

控制Spring Boot应用在Docker Compose环境中启动时,是否等待服务就绪。设置为only-if-started表示只有当服务启动后才进行等待。

spring.freemarker.cache

false

控制Freemarker模板引擎是否启用模板缓存。设置为false表示禁用缓存,适用于开发环境。

spring.graphql.graphiql.enabled

true

控制是否启用GraphiQL IDE,这是一个用于测试和调试GraphQL API的交互式浏览器界面。设置为true表示启用。

spring.groovy.template.cache

false

控制Groovy模板引擎是否启用模板缓存。设置为false表示禁用缓存,适用于开发环境。

spring.h2.console.enabled

true

控制是否启用H2数据库控制台,这是一个内嵌的数据库管理界面。设置为true表示启用。

spring.mustache.servlet.cache

false

控制Mustache模板引擎的Servlet是否启用缓存。设置为false表示禁用缓存,适用于开发环境。

spring.mvc.log-resolved-exception

true

控制是否记录Spring MVC处理异常时解析的异常。设置为true表示记录。

spring.reactor.netty.shutdown-quiet-period

0s

控制Reactor Netty在关闭时等待的静默期。设置为0s表示立即关闭,不等待。

spring.template.provider.cache

 

false

控制模板提供者是否启用缓存。设置为false表示禁用缓存,适用于开发环境。

spring.thymeleaf.cache

false

控制Thymeleaf模板引擎是否启用模板缓存。设置为false表示禁用缓存,适用于开发环境。

spring.web.resources.cache.period

0

控制静态资源缓存的周期,设置为0表示不缓存。

spring.web.resources.chain.cache

false

控制资源链处理是否启用缓存。设置为false表示禁用缓存,适用于开发环境。

      如果您不想应用devtools的属性默认值,您可以在application.properties配置文件中设置spring.devtools.add-properties=false。

自动重启

        使用 spring-boot-devtools 的应用程序会在类路径上的文件发生更改时自动重新启动

  • 触发重启的方式

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

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

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

      • 如果使用构建插件,运行mvn compileMaven 或gradle buildGradle 将触发重新启动。

  • 禁用重启:

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

    • 如果需要完全禁用重启支持(例如,因为它不适用于特定的库),则需要在调用之前将spring.devtools.restart.enabled 属性设置为false。请参考下面的代码示例:

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

自动重启机制原理

        Spring Boot Devtools 使用了两个类加载器,基础类加载器和重启类加载器

  • 基础类加载器(base classloader):它加载不会经常变化的类,如第三方库等;

  • 重启类加载器(restart classloader):它加载应用程序中自己编写的类。

  • 当代码发生变化时,重新启动应用程序时,将丢弃重启类加载器并创建一个新的类加载器。也就是只有重启类加载器会重新加载类,而基础类加载器保持不变,这就是为什么它能够实现快速重启的原因之一。

LiveReload 实时重载 

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

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

JRebel 重新加载技术

  • 如果您觉得Spring Boot devtools 的重新加载施行缓慢,不符合预期,Spring 官网推荐可以采用JRebel 技术代替 devtools 的重新加载技术。

  • JRebel 是一款 Java 开发工具,它的重新加载技术主要基于字节码增强。当 Java 应用程序运,JRebel 会监控类文件的变化。传统的 Java 应用在修改代码后需要重新启动才能使更改生效,而 JRebel 能够在不重启应用的情况下,将修改后的字节码动态地替换到正在运行的应用中。它通过自定义的类加载器来实现这一点,在检测到类文件发生变化后,JRebel 的类加载器会重新加载修改后的类,并且更新应用中的对象状态和引用,使得应用能够立即使用新的代码逻辑。

  • 优势

    • 节省时间:在开发过程中,尤其是对于大型的 Java 应用,重新启动应用可能需要花费大量的时间。例如,一个包含多个模块、复杂的依赖关系和大量初始化工作的企业级 Spring Boot 应用,重新启动可能需要几分钟。JRebel 可以让开发人员在修改代码后几乎立即看到效果,大大提高了开发效率。

    • 保持应用状态:在传统的重启过程中,应用的状态会丢失,例如用户的会话信息、缓存数据等。JRebel 能够在重新加载代码的同时,尽可能地保留应用的状态,这对于一些需要长时间运行并维护状态的应用非常重要,如 Web 应用中的用户登录状态、购物车信息等。

        自动重启与 LiveReload 配合使用效果很好。如果您使用 JRebel,则自动重启将被禁用,以支持动态类重新加载。其他 devtools 功能(例如 LiveReload 和属性覆盖)仍可使用。

使用触发文件

        如果您使用的 IDE 会持续编译已更改的文件,您可能希望仅在特定时间触发重启。为此,您可以使用“触发文件”,这是一个特殊文件,当您想要实际触发重启检查时必须对其进行修改。对文件的任何更新都会触发检查,但只有当 Devtools 检测到有事要做时才会真正发生重新启动。

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

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

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

自定义重启类加载器

  • 默认情况下,IDE 中打开的任何项目都使用“重启”类加载器加载,任何常规文件都使用“基础”类加载器加载。

  • 您可以通过创建文件META-INF/spring-devtools.properties来指示 Spring Boot 使用不同的类加载器加载项目的各个部分。spring-devtools.properties文件可以包含以restart.exclude和 为前缀的属性restart.include

    • include元素是应该拉入“重启”类加载器的项目,

    • exclude元素是应该推送到“基础”类加载器的项目。

    • 属性的值是一个正则表达式模式,它应用于启动时传递给 JVM 的类路径。以下是一些本地类文件被排除并在重启类加载器中包含一些额外库的示例:

restart:
  exclude:
    companycommonlibs: "/mycorp-common-[\\w\\d-\\.]/(build|bin|out|target)/"
  include:
    projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"

全局设置

        您可以通过将以下任意文件添加到$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文件: 

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

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

文件系统观察器

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

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

        现在每 2 秒轮询一次受监控的类路径目录以查看是否有任何变化,并维持 1 秒的静默期以确保没有其他类变化。

远程应用程序

  • 打包的项目默认不包含 devtools。如果要使用某个远程 devtools 功能,则需要将其包含。使用 Maven 插件时,请将excludeDevtools属性设置为false

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

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

IDEA 对自动重启功能的支持

Spring Boot | IntelliJ IDEA Documentation

参考文献

Developer Tools :: Spring Boot

;