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-workspace\eclipse-workspace\springboot2-leanring\springboot2-leanring-devtools\target\classes started by wpb in C:\code-workspace\eclipse-workspace\springboot2-leanring\springboot2-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-workspace\eclipse-workspace\springboot2-leanring\springboot2-leanring-devtools\target\classes started by wpb in C:\code-workspace\eclipse-workspace\springboot2-leanring\springboot2-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-workspace\eclipse-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-workspace\eclipse-workspace\springboot2-leanring-devtools-0.0.1-SNAPSHOT.jar started by wpb in C:\code-workspace\eclipse-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-workspace\eclipse-workspace\springboot2-leanring-devtools-0.0.1-SNAPSHOT.jar started by wpb in C:\code-workspace\eclipse-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 遠程更新
和本地應用自動重啟一樣,遠程客戶端同樣會監控類路徑下的變更,任何變更都會被推送到遠程的服務端中並且觸發重啟(如果需要)。這種特性對於使用雲服務而在本地進行調試會比較方便。總的來說,遠程更新和重啟會比一般的重新構建和發布要快很多。
注:客戶端開啟前的文件變更並不會被監控到,所以需要注意下。
