Spring Boot2系列文章可以通过这里进行回顾:SpringBoot2(001):入门介绍、官网参考和博客汇总
对于 springboot 应用来说,JVM 的 Hot Swapping (热交换/热插拔/热替换?)也是开箱即用的。当然,JVM 的 Hot Swapping 相对来说会受限于可替换的字节码,完整的方案可参考业界的 JRebel 。
springboot 的 spring-boot-devtools 模块包含了可用于快速重启应用的功能,对于开发时进行快速的自动重启应用会有很大的帮助。接下来这篇文章将对此进行大致的介绍。具体参考官方文档:20. Developer Tools 。本文目录结构如下:
- 1、使用 spring-boot-devtools
- 2、spring-boot-devtools 的属性默认配置
- 3、自动重启 Automatic Restart
- 4、Live Reload
- 5、全局设置
- 6、远程应用
1、使用 spring-boot-devtools
springboot 的开发者工具 spring-boot-devtools ,用于提供额外的开发时特性,使得应用程序开发体验更方便顺畅。要使用 devtools 只需要在依赖中添加进来即可。
maven :
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> </dependencies>
Gradle :
configurations { developmentOnly runtimeClasspath { extendsFrom developmentOnly } } dependencies { developmentOnly("org.springframework.boot:spring-boot-devtools") }
注1:通过完整打包的方式运行 springboot 应用时,开发者工具 devtools 的功能默认是会自动关闭的,例如通过 java -jar 方式运行 springboot 应用或者通过特殊的 classloader 启动时,会被当成是生产应用,此时会自动禁止掉 devtools 的特性。如果发现没有关闭掉(例如通过容器启动),则需要考虑直接排除掉 devtools 引用或者在启动命令中增加变量 -Dspring.devtools.restart.enabled=false 的设置来进行关闭。
注2:像上面的案例一样,建议增加 optional(maven 中)或者使用 developmentOnly(Gradle 中),以防止 devtools 被传递到依赖你工程的项目中。
注3:默认情况下,Repackaged archives(springboot 自己的重新打包的配置)并不会包含 devtools。如果需要使用远程开发特性,可以关闭 excludeDevtools 构建属性来进行开启 。
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludeDevtools>false</excludeDevtools> </configuration> </plugin> </plugins> </build>
2、spring-boot-devtools 的属性默认配置
springboot 支持的一些 jar 包会使用缓存来提升性能。例如,模板引擎 template engines 会缓存已编译的模板以避免重复解析模板文件。另外,在提供静态资源文件时,Spring MVC 可以添加 HTTP 缓存头(headers)。
虽然缓存在生产环境中非常有用(生产环境的包一般不会随意做改动),但在开发过程中可能会适得其反,缓存会使开发者无法看到在应用程序中所做的更改。出于这个原因,spring-boot-devtools 默认禁用缓存选项。
缓存选项通常是在 application.properties 文件中进行配置。例如,Thymeleaf 提供了 spring.thymeleaf.cache。spring-boot-devtools 对这些配置选项默认提供了一些合理的开发时配置,而不是需要手工去一一设置。
由于开发者在开发 spring mvc 或者 spring WebFlux 应用时可能需要更多关于 web 请求的信息,因此开发者工具 developer tools 默认对 web logging group 开启了 debug 级别的日志记录,接收的请求、哪个处理器进行处理、输出的响应等等,都会进行详细记录。如果希望记录所有请求详情(包括潜在的敏感信息),可以开启 spring.http.log-request-details 配置。
注1:如果不需要默认属性配置,可以在 application.properties 中设置 spring.devtools.addproperties=false 来进行关闭。
注2:devtools 中的完整属性配置详情参考: DevToolsPropertyDefaultsPostProcessor 。
static { Map<String, Object> properties = new HashMap<>(); properties.put("spring.thymeleaf.cache", "false"); properties.put("spring.freemarker.cache", "false"); properties.put("spring.groovy.template.cache", "false"); properties.put("spring.mustache.cache", "false"); properties.put("server.servlet.session.persistent", "true"); properties.put("spring.h2.console.enabled", "true"); properties.put("spring.resources.cache.period", "0"); properties.put("spring.resources.chain.cache", "false"); properties.put("spring.template.provider.cache", "false"); properties.put("spring.mvc.log-resolved-exception", "true"); properties.put("server.error.include-stacktrace", "ALWAYS"); properties.put("server.servlet.jsp.init-parameters.development", "true"); properties.put("spring.reactor.stacktrace-mode.enabled", "true"); PROPERTIES = Collections.unmodifiableMap(properties); }
3、自动重启 Automatic Restart
使用 spring-boot-devtools 的应用, classpath 下的文件变更可以触发应用进行自动重启。这个特性和使用IDE(开启了自动编译/构建)进行开发相得益彰,因为这样对于代码改动会很快进行反馈,而不是手动停止应用然后再重启。当然,对于一些特定的资源文件,比如 静态资源文件和视图模板等,是不需要重启应用的。
如何触发重启:由于 devtools 监控着 classpath 下的文件,触发重启唯一的方式就是更新了 classpath 下的文件。
Eclipse 的设置:Eclipse 中开启自动编译构建时(菜单:Project ==》 Build Automatically 勾选上,如下图),保存已修改文件就会引起 classpath 的更新从而触发自动重启,或者通过 Project ==》 Clean 进行手动清理和构建(如下图):
IDEA 的设置:IntelliJ IDEA 则需要通过构建项目(Build==》 Build Project)来达到同样的效果(测试过,不需要其他设置了,只是这里需要手动触发),或者开启自动构建功能: File ==》 Settings ==》 Build, Execution, Deployment ==》 Compiler ==》 Build project automatically (ctrl+alt+s),这个配置还特地说明了 only works while not running/debugging,因此还需要设置 compiler.automake.allow.when.app.running 开启运行时的自动编译:快捷键 ctrl + shift + alt + /,选择Registry,勾上 compiler.automake.allow.when.app.running,如果 idea 快捷键做过变更的话,可以通过“File” -> “Settings” ->“KeyMap” 搜索 Maintenance 找到对应的快捷键。
注1:开发者也可以通过使用 spring-boot-maven-plugin 插件来启动应用,而不是通过 IDE(使用 main 函数),只要开启 fork 配置即可,因为 devtools 需要一个独立的类加载器来进行操作处理。默认情况下, Gradle 和 maven 只要检测到类路径下有 devtools 就会启动这样的配置。
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> </configuration> </plugin> </plugins> </build>
这里就是通过 mvn spring-boot:run 启动了引用,然后 classpath 路径下修改了文件(可以是 IDE 的自动构建或者手动构建,也可以是 手动替换等),从而触发自动重启。经过测试,这里没配置 fork 也是可以自动重启的(默认),如果不行就先加上。
注2:和 LiveReload 一起使用时,自动重启的效果也非常好,后续会对 LiveReload 进行详细介绍。如果使用 JRebel ,动态的类重新加载会替换自动重启,而其他的开发者工具特性(例如 LiveReload 和 属性覆盖) 还可以继续使用
注3:devtools 依赖应用上下文中的停机钩子(shutdown hook)在重启中来进行关闭。如果禁用了 shutdown hook ,可能会无法正常工作(SpringApplication.setRegisterShutdownHook(false))。
注4:devtools 会自动忽略 classpath 下 spring-boot, spring-boot-devtools, springboot-autoconfigure, spring-boot-actuator 和 spring-boot-starter的变化。
注5:devtools 需要定制自己的 ResourceLoader 供 ApplicationContext 使用。如果开发者的应用中已经提供了一个,会被直接覆盖掉,另外还不支持重写 ApplicationContext 的 getResource 方法。
Restart vs Reload:重启 vs 重新加载
restart 自动重启原理:springboot 使用 2个 类加载器 来处理自动重启的问题,对于不会变化的类,例如 spring 本身的引用包和第三方引用的 jar 包,使用一个 base classloader 来加载,对于正在开发中的工程项目代码,则使用 restart classloader 来进行加载。当应用自动重启时,旧的 restart classloader 会被丢弃,并产生一个新的来进行加载,这意味这自动重启会比冷启动快一些,因为 base classloader 已经准备好无需重启。
如果觉得自动重启还不够快(毕竟还要加载项目中其他没改动过的代码)或者遇到了类加载器的问题,可以考虑 ZeroTurnaround 开发的 JRebel 提供的重新加载 reload 技术。JRebel 通过在载入时重写 classes 使得更容易重新加载。
从启动日志的差别可以看到,这里变成了 restartMain,表示可以自动重启,在不加上 devtools 之前时 main,不会自动重启。
注:这里说明一下,经过测试,开启之后如果把 pom.xml 中的 devtools 引用再注释掉的话,其实还是会自动重启的,因为这个加载器已经定好没有改动,后续再修改还是会触发自动重启。反过来如果开启应用时没有 devtools ,在运行过程中再加上 devtools 依赖,是不会重启的,原因也一样。
. ____ _ __ _ _ /\ / ___'_ __ _ _(_)_ __ __ _ ( ( )\___ | '_ | '_| | '_ / _` | \/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.5.RELEASE) 2020-05-02 16:53:33.910 INFO 7036 --- [ restartedMain] c.w.l.devtools.DevtoolsApplication : Starting DevtoolsApplication on XXX with PID 7036 (C:code-workspaceeclipse-workspacespringboot2-leanringspringboot2-leanring-devtools argetclasses started by wpb in C:code-workspaceeclipse-workspacespringboot2-leanringspringboot2-leanring-devtools) 2020-05-02 16:53:33.913 INFO 7036 --- [ restartedMain] c.w.l.devtools.DevtoolsApplication : No active profile set, falling back to default profiles: default 2020-05-02 16:53:33.970 INFO 7036 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable 2020-05-02 16:53:33.971 INFO 7036 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG' 2020-05-02 16:53:36.565 INFO 7036 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2020-05-02 16:53:36.595 INFO 7036 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-05-02 16:53:36.595 INFO 7036 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.19] 2020-05-02 16:53:36.731 INFO 7036 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-05-02 16:53:36.731 INFO 7036 --- [ restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2760 ms 2020-05-02 16:53:37.005 INFO 7036 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-05-02 16:53:37.239 INFO 7036 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729 2020-05-02 16:53:37.286 INFO 7036 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-05-02 16:53:37.290 INFO 7036 --- [ restartedMain] c.w.l.devtools.DevtoolsApplication : Started DevtoolsApplication in 3.747 seconds (JVM running for 4.339) 2020-05-02 16:53:52.827 INFO 7036 --- [ Thread-6] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' . ____ _ __ _ _ /\ / ___'_ __ _ _(_)_ __ __ _ ( ( )\___ | '_ | '_| | '_ / _` | \/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.5.RELEASE) 2020-05-02 16:53:53.950 INFO 7036 --- [ restartedMain] c.w.l.devtools.DevtoolsApplication : Starting DevtoolsApplication on XXX with PID 7036 (C:code-workspaceeclipse-workspacespringboot2-leanringspringboot2-leanring-devtools argetclasses started by wpb in C:code-workspaceeclipse-workspacespringboot2-leanringspringboot2-leanring-devtools) 2020-05-02 16:53:53.951 INFO 7036 --- [ restartedMain] c.w.l.devtools.DevtoolsApplication : No active profile set, falling back to default profiles: default 2020-05-02 16:53:54.338 INFO 7036 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2020-05-02 16:53:54.339 INFO 7036 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-05-02 16:53:54.339 INFO 7036 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.19] 2020-05-02 16:53:54.366 INFO 7036 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-05-02 16:53:54.366 INFO 7036 --- [ restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 413 ms 2020-05-02 16:53:54.423 INFO 7036 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-05-02 16:53:54.489 INFO 7036 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729 2020-05-02 16:53:54.506 INFO 7036 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-05-02 16:53:54.507 INFO 7036 --- [ restartedMain] c.w.l.devtools.DevtoolsApplication : Started DevtoolsApplication in 0.596 seconds (JVM running for 21.555) 2020-05-02 16:53:54.509 INFO 7036 --- [ restartedMain] .ConditionEvaluationDeltaLoggingListener : Condition evaluation unchanged
3.1 在状态评估报告中进行变更的日志记录(Logging changes in condition evaluation)
默认情况下,每次应用程序自动重启时,都会通过日志记录显示增量的应用状态评估报告。报告会显示应用中做过的自动配置变更,例如 增加或者移除 beans ,设置或者变更 配置属性(上面日志中看到的 ConditionEvaluationDeltaLoggingListener )。
如果要关闭这个报告记录,增加如下设置:
spring.devtools.restart.log-condition-evaluation-delta=false
3.2 排除资源文件
一些特定的资源文件被修改时是不需要重新启动的,例如 Thymeleaf 模板就可以随意编辑。默认情况下,/META-INF/maven,/META-INF/resources, /resources, /static, /public, 或者 /templates 下的资源变更都不会触发自动重启,但是会进行 Live Reload(浏览器客户端自动刷新)。如果需要定制排除策略,可以使用 spring.devtools.restart.exclude 属性配置,例如只排除掉 /static 和 public ,可以进行如下配置,这样会把原来的默认配置覆盖掉。
spring.devtools.restart.exclude=static/**,public/**
如果要保留默认的排除策略,然后新增排除策略,则使用 spring.devtools.restart.additional-exclude
spring.devtools.restart.additional-exclude=otherstatic/**,otherpublic/**
3.3 监控其他文件
开发者如果其他的没有包含在 classpath 上的变更但是又想让应用自动重启或者重新加载的话(例如多模块开发的场景),可以通过 spring.devtools.restart.additional-paths 来进行指定。上面提到的配置 spring.devtools.restart.exclude 也同样适用于指定是触发自动重启还是 Live Reload。
3.4 禁止自动重启
通过在 application.properties 增加 spring.devtools.restart.enabled=false 配置来禁止自动重启(这样做会触发一次重启,但是之后不会再监控文件变更了)。
如果要完全禁止自动重启支持(例如,对于一些特定的 jar 包可能不生效),开发者需要在调用 SpringApplication.run(…) 前设置系统属性 spring.devtools.restart.enabled=false:
public static void main(String[] args) { System.setProperty("spring.devtools.restart.enabled", "false"); SpringApplication.run(MyApp.class, args); }
3.5 使用触发文件
如果使用 IDE 进行开发和持续编译构建的话,应用会经常重启,特别是改动比较多的时候,这时候可以通过指定触发文件来达到特定时间触发自动重启的功能,此时只要编辑并保存触发文件即可触发自动重启。配置 spring.devtools.restart.trigger-file 就可以指定了。
注:也可以将 spring.devtools.restart.trigger-file 设置为全局配置(后面会介绍),所有的工程都进行监测和重启。
3.6 定制重启的类加载器
前面提到过,自动重启功能是通过2个类加载器进行实现的,大部分场景下是正常的。但有些时候可能就不起作用了。
默认情况下,IDE 中打开的任何项目都会被 restart classloader 进行加载,而任何普通的 xxx.jar 则会被 base classloader 进行加载。但是当开发者进行多模块项目开发时(这种场景也比较常见,比如分层和内部多组件的情况下),并非所有模块都会被打开导入 IDE,这个时候可能就需要定制加载策略了。这种场景下,可以创建一个 META-INF/spring-devtools.properties 文件来进行定制。
spring-devtools.properties 文件包含 restart.exclude 和 restart.include 开头的属性前缀配置。include 表示需要上升到 restart classloader 的项目,而 exclude 表示需要下推到 base classloader 的项目。
这些配置都可以使用正则表达式:
restart.exclude.companycommonlibs=/mycorp-common-[\w-]+.jar
restart.include.projectcommon=/mycorp-myproj-[\w-]+.jar
注:所有的 key 都必须唯一,只要以 restart.exclude 和 restart.include 开头即可。
注:类路径下所有的 META-INF/spring-devtools.properties 文件都会进行加载,因此这文件可以放置在项目工程中,也可以是在引用的 jar 中。
3.7 一些限制
重启对于标准的 ObjectInputStream 的反序列化可能支持不太好。如果需要使用反序列化数据,开发者可以使用 spring 的 ConfigurableObjectInputStream 搭配 Thread.currentThread().getContextClassLoader() 进行处理。
可惜的是,一些第三方包在发序列化的时候并没有考虑 context classloader。如果开发者遇到了这种问题,可能需要向原作者提出 fix request。
4、Live Reload
spring-boot-devtools 模块内置了一个 LiveReload 服务器,用于在资源变更时触发浏览器的自动更新。LiveReload 浏览器扩展插件支持 Chrome、Firefox 和 Safari,具体参考:livereload.com。
如果需要关闭这个功能,增加如下设置:
spring.devtools.livereload.enabled=false
注:只支持启动一个 LiveReload 服务器,在 IDE 中开多个的话,只会认第一个。因此需要确保正在用的是唯一一个。
谷歌浏览器:F12或者“Ctrl+Shift+I”,打开开发者工具,“Network” 选项卡下 选中打勾 “Disable Cache(while DevTools is open)”。
livereload 通过引入的脚本livereload.js在 livereload 服务和浏览器之间建立了一个 WebSocket 连接。每当监测到文件的变动,livereload 服务就会向浏览器发送一个信号,浏览器收到信号后就刷新页面,实现了实时刷新的效果。有需要的可以自行测试。
5、全局设置
可以通过在 $HOME 目录(windows环境下可以设置HOME的用户环境变量)下增加文件 .spring-bootdevtools.properties 来进行全局的 devtools 配置,这个配置会应用于所有有使用 devtools 的 springboot 应用。
例如 3.5 使用触发文件 中提到的,如果是在全局配置里面进行设置的话,可以在 .spring-bootdevtools.properties 文件中这样写:
spring.devtools.reload.trigger-file=.reloadtrigger
注:.spring-bootdevtools.properties 中的配置不会影响到 24.4 Profile-specific Properties (application-{profile}.properties 文件)的加载。
6、远程应用
spring-boot-devtools 提供了可选的远程支持。如果需要开启的话,首先增加如下配置,将 spring-boot-devtools 的依赖包添加到最终的 jar 包中 :
<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=mysecret
警告:这种操作有风险,仅限于开发测试环境,生产环境切记不能添加 spring-boot-devtools 。
远程开发工具支持包含了两部分:接收请求的服务端和在 IDE 中开启的客户端。服务端的 springboot 应用在启动时检测到 spring.devtools.remote.secret 配置后会自动开启远程支持,而客户端则需要手工在 IDE 中启动。
6.1 运行客户端连接
客户端需要使用 org.springframework.boot.devtools.RemoteSpringApplication 进行启动,参数是远程连接的 URL。Eclipse 中的操作步骤:
- Run ==> Run Configurations…
- 在 Java Application 下新建一个 “launch configuration”
- 选择需要的工程
- 使用 org.springframework.boot.devtools.RemoteSpringApplication 作为主类
- 增加主函数参数,也即是需要连接的 URL ,例如 http://localhost:8080 ,截图如下
运行之后可能输出如下:
. ____ _ __ _ _ /\ / ___'_ __ _ _(_)_ __ __ _ ___ _ ( ( )\___ | '_ | '_| | '_ / _` | | _ \___ _ __ ___| |_ ___ \/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' / _ _/ -_) ) ) ) ) ' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / / =========|_|==============|___/===================================/_/_/_/ :: Spring Boot Remote :: 2.1.5.RELEASE 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-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code/springboot-samples/spring-boot-sample-devtools) 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)
笔者拿打出的 jar 包在 cmd 窗口通过 java -jar 进行启动,然后在 Eclipse 中进行改动,可以看到远程服务端重启了,从 main 变成了 restartMain:
C:code-workspaceeclipse-workspace>java -jar springboot2-leanring-devtools-0.0.1-SNAPSHOT.jar . ____ _ __ _ _ /\ / ___'_ __ _ _(_)_ __ __ _ ( ( )\___ | '_ | '_| | '_ / _` | \/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.5.RELEASE) 2020-05-03 08:43:57.111 INFO 20180 --- [ main] c.w.l.devtools.DevtoolsApplication : Starting DevtoolsApplication v0.0.1-SNAPSHOT on XXX with PID 20180 (C:code-workspaceeclipse-workspacespringboot2-leanring-devtools-0.0.1-SNAPSHOT.jar started by wpb in C:code-workspaceeclipse-workspace) 2020-05-03 08:43:57.115 INFO 20180 --- [ main] c.w.l.devtools.DevtoolsApplication : No active profile set, falling back to default profiles: default 2020-05-03 08:43:57.171 INFO 20180 --- [ main] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable 2020-05-03 08:43:57.171 INFO 20180 --- [ main] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG' 2020-05-03 08:43:59.433 INFO 20180 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2020-05-03 08:43:59.472 INFO 20180 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-05-03 08:43:59.472 INFO 20180 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.19] 2020-05-03 08:43:59.587 INFO 20180 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-05-03 08:43:59.588 INFO 20180 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2415 ms 2020-05-03 08:43:59.630 WARN 20180 --- [ main] .s.b.d.a.RemoteDevToolsAutoConfiguration : Listening for remote restart updates on /.~~spring-boot!~/restart 2020-05-03 08:43:59.813 INFO 20180 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-05-03 08:44:00.034 INFO 20180 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-05-03 08:44:00.038 INFO 20180 --- [ main] c.w.l.devtools.DevtoolsApplication : Started DevtoolsApplication in 3.348 seconds (JVM running for 3.786) 2020-05-03 08:44:13.899 INFO 20180 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2020-05-03 08:44:13.899 INFO 20180 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2020-05-03 08:44:13.904 INFO 20180 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms 2020-05-03 08:44:13.928 INFO 20180 --- [ Thread-0] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' . ____ _ __ _ _ /\ / ___'_ __ _ _(_)_ __ __ _ ( ( )\___ | '_ | '_| | '_ / _` | \/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.5.RELEASE) 2020-05-03 08:44:15.007 INFO 20180 --- [ restartedMain] c.w.l.devtools.DevtoolsApplication : Starting DevtoolsApplication v0.0.1-SNAPSHOT on XXX with PID 20180 (C:code-workspaceeclipse-workspacespringboot2-leanring-devtools-0.0.1-SNAPSHOT.jar started by wpb in C:code-workspaceeclipse-workspace) 2020-05-03 08:44:15.007 INFO 20180 --- [ restartedMain] c.w.l.devtools.DevtoolsApplication : No active profile set, falling back to default profiles: default 2020-05-03 08:44:15.188 INFO 20180 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2020-05-03 08:44:15.189 INFO 20180 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-05-03 08:44:15.190 INFO 20180 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.19] 2020-05-03 08:44:15.211 INFO 20180 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-05-03 08:44:15.212 INFO 20180 --- [ restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 202 ms 2020-05-03 08:44:15.229 WARN 20180 --- [ restartedMain] .s.b.d.a.RemoteDevToolsAutoConfiguration : Listening for remote restart updates on /.~~spring-boot!~/restart 2020-05-03 08:44:15.291 INFO 20180 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-05-03 08:44:15.342 INFO 20180 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-05-03 08:44:15.343 INFO 20180 --- [ restartedMain] c.w.l.devtools.DevtoolsApplication : Started DevtoolsApplication in 0.361 seconds (JVM running for 19.091) 2020-05-03 08:44:15.432 INFO 20180 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2020-05-03 08:44:15.433 INFO 20180 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2020-05-03 08:44:15.441 INFO 20180 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 6 ms
注1:客户端和服务端用的是同一套代码,因此配置的密码是可以读取并进行验证的。
注2:建议使用 https:// ,这样通信就会加密,并且密码不会被获取。
注3:也可以通过如下方式进行远程代码的代理连接:
spring.devtools.remote.proxy.host=192.168.0.1
spring.devtools.remote.proxy.port=80
6.2 远程更新
和本地应用自动重启一样,远程客户端同样会监控类路径下的变更,任何变更都会被推送到远程的服务端中并且触发重启(如果需要)。这种特性对于使用云服务而在本地进行调试会比较方便。总的来说,远程更新和重启会比一般的重新构建和发布要快很多。
注:客户端开启前的文件变更并不会被监控到,所以需要注意下。