https://blog.csdn.net/renpeng301/article/details/124596782

参考:https://blog.csdn.net/renpeng301/article/details/124596782

Spring Boot DevTools 2.x(IDEA 热部署&远程调试&LiveReload)

前言

Spring Boot包括一组额外的工具,它们可以使应用程序开发体验更加方便。spring-boot-devtools模块可以包含在任何项目中,以提供额外的开发时特性。要包含devtools支持,请将模块依赖添加到你的项目中,如下面的Maven和Gradle清单所示:

Maven

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

Gradle

1
2
3
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系统属性。


诊断类加载问题

Restart vs Reload一节所述,重启功能是通过使用两个类加载器来实现的。对于大多数应用程序,这种方法工作得很好。然而,它有时会导致类加载问题,特别是在多模块项目中。

要诊断类加载问题是否确实是由devtools及其两个类加载器引起的,请尝试禁用restart。如果这解决了你的问题,那么定制重新启动类加载器以包括整个项目。

属性默认值

Spring Boot支持一些库使用缓存来提高性能。例如,模板引擎缓存已编译的模板,以避免重复解析模板文件。此外,Spring MVC可以在提供静态资源时向响应添加HTTP缓存头。虽然缓存在生产中非常有益,但在开发过程中可能会产生相反的效果,使你无法看到刚刚在应用程序中所做的更改。出于这个原因,spring-boot-devtools默认禁用缓存选项。

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

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

属性名称默认值
server.error.include-binding-errorsalways
server.error.include-messagealways
server.error.include-stacktracealways
server.servlet.jsp.init-parameters.developmenttrue
server.servlet.session.persistenttrue
spring.freemarker.cachefalse
spring.groovy.template.cachefalse
spring.h2.console.enabledtrue
spring.mustache.cachefalse
spring.mvc.log-resolved-exceptiontrue
spring.reactor.debugtrue
spring.template.provider.cachefalse
spring.thymeleaf.cachefalse
spring.web.resources.cache.period0
spring.web.resources.chain.cachefalse

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

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

自动重启

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

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

1.在Eclipse中,保存修改后的文件会导致更新classpath并触发重新启动。
2.在IntelliJ IDEA中,构建项目(Build +→+ Build Project)具有相同的效果。
3.如果使用构建插件,Maven运行mvn compileGradle运行gradle build 将触发重启。

下面已IDEA为例:

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

DevTools需要定制ApplicationContext使用的ResourceLoader。如果你的应用程序已经提供了一个,那么它将被包装。不支持在ApplicationContext上直接覆盖getResource方法。

重启 vs 重新加载

Spring Boot提供的重启技术通过使用两个类加载器来工作。不变的类(例如,那些来自第三方jar的类)被加载到基类加载器中。
正在开发的类被加载到一个重新启动的类加载器中。 当应用程序重新启动时,将丢弃重新启动类加载器,并创建一个新的类加载器。
这种方法意味着应用程序重启通常比“冷启动”快得多,因为基类加载器已经可用并填充了。 如果您发现应用程序重新启动不够快或遇到类加载问题,
你可以考虑重新加载技术,比如ZeroTurnaroundJRebel。它们的工作方式是在 装入类时重写类,使它们更易于重新装入。

增量变化日志报表

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

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

1
2
3
4
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,你可以设置以下属性:

1
2
3
4
spring:
devtools:
restart:
exclude: "static/**,public/**"

如果你想保留这些默认值并添加额外的排除,请使用spring.devtools.restart.additional-exclude属性。

监听更多路径

当你对不在类路径上的文件进行更改时,可能希望重新启动或重新加载应用程序。为此,使用spring.devtools.restart.additional-paths属性配置额外的路径来监视更改。 你可以使用前面描述的spring.devtools.restart.exclude属性来控制附加路径下的更改是否会触发完全重启或实时重新加载。

禁止重启

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

如果您需要完全禁用重启支持(例如,因为它不能与特定的库一起工作), 在调用SpringApplication.run(…)之前,你需要设置spring.devtools.restart.enabled系统属性为false,如下所示:

1
2
3
4
5
6
7
8
@SpringBootApplication
public class MyApplication {

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

使用trigger file

如果你使用的IDE不断编译更改的文件,那么你可能更喜欢只在特定时间触发重新启动。 为此,你可以使用“trigger file”,这是一个特殊的文件,当你希望真正触发重新启动检查时,必须修改它。

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

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

1
2
3
4
src
+- main
+- resources
+- .reloadtrigger

那么你的触发器文件属性就是:

1
2
3
4
spring:
devtools:
restart:
trigger-file: ".reloadtrigger"

重启将只发生在src/main/resources/.reloadtrigger更新。

有些ide具有一些特性,使你无需手动更新触发器文件。Spring Tools Eclipse和IntelliJ IDEA (Ultimate Edition)都有这样的支持。使用Spring Tools,你可以在控制台视图中使用“reload”按钮(只要你的触发器文件名为.reloadtrigger)。

对于IntelliJ IDEA,若要更新正在运行的应用程序,请在主菜单中选择“Run | Debugging Actions | update application⌘F10”,或在“Services”工具窗口中选择你的应用程序,单击“update application”。根据你的需要,你可以配置执行此操作时IDE将执行的操作。

定制重启类加载器

如前所述,重启功能是通过使用两个类加载器来实现的。如果这会导致问题,你可能需要定制由哪个类加载器加载的内容。

默认情况下,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”类加载器中的项。
属性的值是一个应用于类路径的regex模式,如下所示:

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

限制

对于通过使用标准ObjectInputStream反序列化的对象,重新启动功能不能很好地工作。如果你需要反序列化数据,你可能需要结合使用SpringConfigurableObjectInputStreamThread.currentThread(). getcontextclassloader()

IDEA热部署

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<!--参数非常关键-->
<optional>true</optional>
</dependency>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!--这个参数也非常关键(springboot3.x中已经不再支持fork元素:https://youtrack.jetbrains.com/issue/IDEA-306949)-->
<fork>true</fork>
</configuration>
</plugin>

代码修改自动编译方式

idea 设置

修改java文件,自动重新自动。

trigger file方式

idea配置

1.从主菜单 选择Run | Edit Configurations

2.选择自己项目,然后选择Modify options->On ‘Upate’ action

3.新建文件.reloadtirgger

4.代码更改完成后,选择 Run | Debugging Actions | Update Application

LiveReload(实时重新加载)

spring-boot-devtools模块包括一个嵌入式LiveReload服务器,当资源发生变化时,可以使用它触发浏览器刷新。livereload.com为Chrome, Firefox和Safari提供免费的livereload.com浏览器扩展。

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

要在文件更改时触发LiveReload,必须启用“自动重启”。

配置文件系统监视器

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

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

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

远程应用

Spring Boot开发工具并不局限于本地开发。在远程运行应用程序时,还可以使用几个特性。远程支持是可选择的,因为启用它可能会带来安全风险。它应该只在可信任的网络上运行或使用SSL保护时启用。如果这两个选项对你来说都不可用,你就不应该使用DevTools的远程支持。永远不应该在生产部署中启用支持。

要启用它,你需要确保devtools包含在重新打包的归档文件中,如下所示:

1
2
3
4
5
6
7
8
9
10
11
<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。

运行远程客户端应用程序

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

例如,如果你正在使用Eclipse或Spring Tools,并且你有一个名为my-app的项目已经部署到云服务器,你将做以下操作:
1.运行菜单选择 Run Configurations…​
2.创建一个“launch configuration”的JAVA应用
3.选择my-app项目
\4. 使用org.springframework.boot.devtools.RemoteSpringApplication作为主类。
\5. 将远程URL添加到Program参数

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

建议使用“https://”作为连接协议,这样流量就会被加密,密码就不会被拦截。
如果你需要使用代理来访问远程应用程序,请配置spring.devtools.remote.proxy.hostspring.devtools.remote.proxy.port属性。

IDEA远程调试

1.SpringBoot默认打包不会包含devtoolspom.xml需要修改如下。

1
2
3
4
5
6
7
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!--打包时不排除Devtools-->
<excludeDevtools>false</excludeDevtools>
</configuration>

2.application.yml文件,添加devtools的远程访问密钥

1
2
3
4
spring:
devtools:
remote:
secret: laopeng123

3.添加测试接口

1
2
3
4
@RequestMapping("/hello")
public ResponseEntity hello() {
return ResponseEntity.ok("laopeng");
}

4.将项目部署打包部署

访问接口http://localhost:9090/hello

5.添加一个启动配置,启动类为org.springframework.boot.devtools.RemoteSpringApplication,配置如下:

6.启动远程客户端

7.修改接口内容

1
2
3
4
@RequestMapping("/hello")
public ResponseEntity hello() {
return ResponseEntity.ok("laopeng我被修改了");
}

8.Rebuild 本地项目

9.访问远程接口

远程热部署成功!