前言
这是 SpringBoot 官方文档中文翻译版系列的第八篇文章:
前七篇文章如下:
SpringBoot 官方文档中文版 - 3. 构建你的代码
SpringBoot 官方文档中文版 - 4. 配置类与自动化配置
SpringBoot 官方文档中文版 - 5. Spring Beans 和 DI
SpringBoot 官方文档中文版 - 6. 使用 @SpringBootApplication 注解
SpringBoot 官方文档中文版 - 7. 运行您的应用
开发者工具
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")
}
当运行完全打包的应用程序时,Developer tools 将被自动禁用。如果您的应用程序是从 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 配置。
1. 默认属性
Spring Boot 支持的一些库使用缓存来提高性能。例如,模板引擎缓存已编译的模板,以避免重复解析模板文件。此外,Spring MVC 可以在提供静态资源时为响应添加 HTTP 缓存头。
虽然缓存在生产中非常有用,但在开发期间可能会产生相反的效果,使您无法看到刚刚在应用程序中所做的更改。因此,spring-boot-devtools 默认禁用缓存选项。
缓存选项通常由应用程序中的设置来配置。属性文件。例如,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。
2. 自动重启
只要类路径上的文件发生更改,使用 spring-boot-devtools 的应用程序就会自动重新启动。在 IDE 中工作时,这是一个非常有用的特性,因为它为代码更改提供了一个非常快速的反馈循环。默认情况下,将监视指向目录的类路径上的任何条目的更改。注意,某些资源,如静态资产和视图模板,不需要重新启动应用程序。
由于 DevTools 监控类路径资源,触发重启的唯一方法是更新类路径。更新类路径的方法取决于你使用的IDE:
-
在 Eclipse 中,保存修改后的文件会导致更新类路径并触发重新启动。
-
在 IntelliJ IDEA 中,构建项目(Build +→+ Build project)也有同样的效果。
-
如果使用构建插件,运行 mvn compile for Maven 或 gradle build for gradle 将触发重新启动。
如果你使用构建插件重新启动 Maven 或 Gradle,你必须让 forking 设置为 enabled。如果禁用 forking,则无法创建devtools使用的孤立应用程序类加载器,重启也无法正常运行。
当与 LiveReload 一起使用时,自动重启工作得非常好。有关详细信息,请参阅 LiveReload 部分。如果使用 JRebel,将禁用自动重新启动,以支持动态类重新加载。其他的 devtools 特性(比如LiveReload和属性覆盖)仍然可以使用。
在重启期间,DevTools 依赖于应用上下文的 shutdown钩子。如果你禁用了 shutdown钩子(SpringApplication.setRegisterShutdownHook(false)),DevTools 就不能正常工作。
重启和重载
Spring Boot 提供的重启技术通过使用两个类加载器来工作。不更改的类(例如,来自第三方jar的类)被加载到基类加载器中。您正在积极开发的类被加载到重新启动的类加载器中。当应用程序重新启动时,重新启动类加载器将被丢弃,并创建一个新的类加载器。这种方法意味着应用程序重新启动通常比“冷启动”快得多,因为基类加载器已经可用并填充了。
如果您发现重新启动应用程序不够快,或者遇到类加载问题,您可以考虑重新加载 ZeroTurnaround 的 JRebel 等技术。它们的工作原理是在装入类时重写类,使它们更易于重新装入。
2.1 条件评估中的日志变化
默认情况下,每次应用程序重新启动时,都会记录一个显示条件评估增量的报告。当您进行更改(如添加或删除bean和设置配置属性)时,该报告将显示对应用程序自动配置的更改。
若要禁用报表的日志记录,请设置以下属性:
spring.devtools.restart.log-condition-evaluation-delta=false
2.2 不包括的资源
某些资源在被更改时不一定需要触发重新启动。例如,可以就地编辑 Thymeleaf 模板。默认情况下,改变 /META-INF/maven、/META-INF/resources、/resources、/static、/public 或 /templates 中的资源不会触发重新启动,但会触发实时重新加载。如果您想定制这些排除,可以使用spring.devtools.restart.exclude 属性。例如,要只排除 /static 和 /public,你可以设置以下属性:
spring.devtools.restart.exclude=static/**,public/**
如果您想保留这些默认值并添加额外的排除项,请使用 spring.devtools.restart.additional-exclude 属性。
2.3 配置额外的路径
当对不在类路径上的文件进行更改时,您可能希望重新启动应用程序或重新加载应用程序。为此,请使用 spring.devtools.restart.additional-paths 属性来配置额外的路径,以监视更改。您可以使用前面描述的 spring.devtools.restart.exclude 属性来控制附加路径下的更改是触发完全重新启动还是实时重新加载。
2.4 禁用重启
如果您不想使用重启特性,可以使用 spring.devtools.restart.enabled 属性禁用它。在大多数情况下,您可以在应用程序中设置此属性。属性(这样做仍然初始化重新启动类加载器,但它不会监视文件更改)。
如果你需要完全禁用重启支持(例如,因为它不与特定的库一起工作),你需要在调用 SpringApplication.run(…) 之前将 spring.devtools.restart.enabled System 属性设置为 false,如下面的示例所示:
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);
}
}
2.5 使用触发器文件
如果您使用的IDE持续编译更改的文件,您可能更喜欢只在特定时间触发重新启动。为此,您可以使用“触发文件”,这是一个特殊的文件,当您希望实际触发重新启动检查时,必须修改该文件。
要使用触发器文件,请将 spring.devtools.restart.trigger-file 属性设置为您的触发器文件的名称(不包括任何路径)。触发器文件必须出现在类路径的某个位置。
例如,如果你有一个具有以下结构的项目:
src
+- main
+- resources
+- .reloadtrigger
那么你的 trigger-file 属性是:
spring.devtools.restart.trigger-file=.reloadtrigger
重启将只发生在 src/main/resources/.reloadtrigger 更新时。
有些 ide 的特性可以使您不必手动更新触发器文件。针对 Eclipse 的 Spring Tools 和 IntelliJ IDEA (Ultimate Edition) 都有这样的支持。使用 Spring Tools,您可以在控制台视图中使用 “reload” 按钮(只要您的触发器文件名为.reloadtrigger)。对于 IntelliJ IDEA,您可以按照其文档中的说明操作。
2.6 定制重启类加载器
如前面的 Restart vs Reload 一节所述,重启功能是通过使用两个类加载器实现的。对于大多数应用程序来说,这种方法工作得很好。然而,它有时会导致类加载问题。
默认情况下,IDE 中任何打开的项目都是用 “restart” 类加载器加载的,任何常规的 .jar 文件都是用 “base” 类加载器加载的。如果您在一个多模块项目中工作,并且不是每个模块都被导入到 IDE 中,那么您可能需要自定义内容。为此,您可以创建 META-INF/spring-devtools。属性文件。
spring-devtools.properties 文件可以包含以重启为前缀的属性 restart.exclude 和 restart.include。include 元素是应该上拉到 “restart” 类加载器中的项,而 exclude 元素是应该下推到 “base” 类加载器中的项。该属性的值是应用于类路径的正则表达式模式,如下面的示例所示:
restart.exclude.companycommonlibs=/mycorp-common-[\w\d-\.]+\.jar
restart.include.projectcommon=/mycorp-myproj-[\w\d-\.]+\.jar
所有属性键必须是唯一的。只要属性以 restart.include 启动。或 restart.exclude。它被认为是正确的。
2.7 已知的限制
对于使用标准 ObjectInputStream 反序列化的对象,重新启动功能不能很好地工作。如果需要反序列化数据,可能需要结合使用 Spring 的ConfigurableObjectInputStream 和 Thread.currentThread(). getcontextclassloader()。
不幸的是,一些第三方库在不考虑上下文类装入器的情况下进行了反序列化。如果您发现了这样的问题,您需要向原始作者请求修复。
3. LiveReload
spring-boot-devtools 模块包含一个嵌入式的 LiveReload 服务器,可用于在资源更改时触发浏览器刷新。LiveReload 浏览器扩展免费提供 Chrome, Firefox和 Safari 从 livereload.com。
如果您不想在应用程序运行时启动 LiveReloa d服务器,可以将 spring.devtools.livereload.enabled 属性设置为 false。
一次只能运行一个 LiveReload 服务器。在启动应用程序之前,确保没有其他 LiveReload 服务器在运行。如果从 IDE 启动多个应用程序,则只有第一个应用程序支持 LiveReload。
要在文件更改时触发 LiveReload,必须启用自动重启。
4. 全局设置
您可以通过将下列文件添加到 $HOME/.config/spring-boot 目录,来配置全局的 devtools 设置。
spring-boot-devtools.properties
spring-boot-devtools.yaml
spring-boot-devtools.yml
添加到这些文件中的任何属性都适用于您机器上使用 devtools 的所有 Spring Boot 应用程序。例如,要将重启配置为总是使用触发器文件,你需要在 spring-boot-devtools 文件中添加以下属性:
spring.devtools.restart.trigger-file=.reloadtrigger
4.1 配置文件系统监控
FileSystemWatcher 的工作方式是,按一定的时间间隔轮询类更改,然后等待预定义的安静时间,以确保没有更多更改。由于 Spring Boot 完全依赖于 IDE 来编译和复制文件到 Spring Boot 可以读取它们的位置,所以您可能会发现,当 devtools 重新启动应用程序时,某些更改可能没有反映出来。如果您经常观察到这样的问题,请尝试将 spring.devtools.restart.poll-interval 和 spring.devtools.restart.quiet-period 参数增加到适合您的开发环境的值:
spring.devtools.restart.poll-interval=2s
spring.devtools.restart.quiet-period=1s
监视的类路径目录现在每 2 秒轮询一次更改,并维持 1 秒的静默期,以确保没有额外的类更改。
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 属性时,服务器组件会自动启用。客户端组件必须手动启动。
5.1 运行远程客户端程序
远程客户端应用程序被设计为在 IDE 中运行。您需要使用与所连接的远程项目相同的类路径运行org.springframework.boot.devtools.RemoteSpringApplication。应用程序唯一必需的参数是它连接到的远程 URL。
例如,如果你正在使用 Eclipse或 Spring Tools,并且你有一个名为 my-app 的项目,你已经部署到 Cloud Foundry,你会做以下事情:
-
从Run菜单中选择Run Configurations…
-
创建新的Java应用程序“启动配置”。
-
浏览my-app项目。
-
使用org.springframework.boot.devtools.RemoteSpringApplication作为主类。
-
将https://myapp.cfapps.io添加到Program参数中(或者您的远程URL是什么)。
一个正在运行的远程客户端可能类似于下面的清单:
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _ ___ _
( ( )\___ | '_ | '_| | '_ / _` | | _ \___ _ __ ___| |_ ___
\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' / _ _/ -_) ) ) ) )
' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
=========|_|==============|___/===================================/_/_/_/
:: Spring Boot Remote :: 2.5.3
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://作为连接协议,以便加密通信和密码不能被拦截。
5.2 远程更新
远程客户机以与本地重启相同的方式监视应用程序类路径的更改。任何更新的资源都被推到远程应用程序,并(如果需要)触发重新启动。如果您迭代使用本地没有的云服务的特性,这将非常有用。通常,远程更新和重启比完整的重建和部署周期要快得多。
在较慢的开发环境中,可能会出现静默期不够用,类中的更改可能会被分批处理。在上传第一批类更改后,服务器将重新启动。下一批无法发送到应用程序,因为服务器正在重新启动。
这通常表现为在 RemoteSpringApplication 日志中出现关于未能上载某些类的警告,以及随后的重试。但它也可能导致应用程序代码不一致,并且在上传第一批更改后无法重新启动。如果您经常观察到这样的问题,请尝试将 spring.devtools.restart.poll-interval 和 spring.devtools.restart.quiet-period 参数增加到适合您的开发环境的值。有关配置这些属性,请参阅配置文件系统监视器一节。
每天学习一点点,每天进步一点点。