在SpringBoot開發偵錯中,如果我每行程式碼的修改都需要重啟啟動再偵錯,可能比較費時間;SpringBoot團隊針對此問題提供了spring-boot-devtools(簡稱devtools)外掛,它試圖提升開發偵錯的效率。@pdai
熱部署和熱載入是在應用正在執行的時候,自動更新(重新載入或者替換class等)應用的一種能力。(PS:spring-boot-devtools提供的方案也是要重啟的,只是無需手動重啟能實現自動載入而已。)
嚴格意義上,我們需要區分下熱部署和熱載入, 對於Java專案而言:
熱部署
熱載入
LiveLoad是提供瀏覽器使用者端自動載入更新的工具,分為LiveLoad伺服器和Liveload瀏覽器外掛兩部分; devtools中已經整合了LiveLoad伺服器,所以如果我們開發的是web應用,並且期望瀏覽器自動重新整理, 這時候可以考慮LiveLoad.
同一時間只能執行一個LiveReload伺服器。 開始應用程式之前,請確保沒有其他LiveReload伺服器正在執行。如果從IDE啟動多個應用程式,則只有第一個應用程式將支援LiveReload。
我們通過如下設定來實現自動重啟方式的熱部署。
新增spring-boot-devtools的依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 可以防止將devtools依賴傳遞到其他模組中 -->
</dependency>
</dependencies>
如果你使用IDEA開發工具,通常有如下兩種方式:
(也可以用mvn compile
編譯觸發重啟更新)
設定1:
File->Setting->Build,Execution,Deployment->Compile
勾選:Make project automatically
設定2:
快捷鍵:ctrl+alt+shift+/
選擇:Registry
勾選:compiler.automake.allow.when.app.running
新版本的IDEA可以在File->setting->Advanced Setttings裡面的第一個設定:
spring:
devtools:
restart:
enabled: true #設定開啟熱部署
additional-paths: src/main/java #重啟目錄
exclude: WEB-INF/**
thymeleaf:
cache: false #使用Thymeleaf模板引擎,關閉快取
spring-boot-devtools模組包含嵌入式LiveReload伺服器,可以在資源更改時用於觸發瀏覽器重新整理。 LiveReload瀏覽器擴充套件程式支援Chrome,Firefox和Safari,你可以從livereload.com免費下載。
或者從瀏覽器外掛中心下載,比如firefox:
安裝完之後,可以通過如下圖示管理
如果你不想在應用程式執行時啟動LiveReload伺服器,則可以將spring.devtools.livereload.enabled屬性設定為false 。
同一時間只能執行一個LiveReload伺服器。 開始應用程式之前,請確保沒有其他LiveReload伺服器正在執行。如果從IDE啟動多個應用程式,則只有第一個應用程式將支援LiveReload。
雖然一些開發者會使用devtool工具,但是很少有能夠深入理解的;讓我們理解如下幾個問題,幫助你進一步理解。@pdai
為什麼同樣是重啟應用,為什麼不手動重啟,而是建議使用spring-boot-devtools進行熱部署重啟?
spring-boot-devtools使用了兩個類載入器ClassLoader,一個ClassLoader載入不會發生更改的類(第三方jar包),另一個ClassLoader(restart ClassLoader)載入會更改的類(自定義的類)。
後臺啟動一個檔案監聽執行緒(File Watcher),監測的目錄中的檔案發生變動時, 原來的restart ClassLoader被丟棄,將會重新載入新的restart ClassLoader。
因為檔案變動後,第三方jar包不再重新載入,只載入自定義的類,載入的類比較少,所以重啟比較快。
這也是為什麼,同樣是重啟應用,為什麼不手動重啟,建議使用spring-boot-devtools進行熱部署重啟。
在自動重啟中有幾點需要注意:
(記錄在什麼情況下重啟的紀錄檔)
可以通過如下關閉
spring:
devtools:
restart:
log-condition-evaluation-delta: false
某些資源在更改時不一定需要觸發重新啟動。預設情況下,改變資源/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屬性。
重啟功能是通過使用兩個類載入器來實現的。對於大多數應用程式,這種方法效果很好。但是,它有時會導致類載入問題。
預設情況下,IDE 中的任何開啟專案都使用「重啟」類載入器載入,任何常規.jar檔案都使用「基本」類載入器載入。如果你處理一個多模組專案,並且不是每個模組都匯入到你的 IDE 中,你可能需要自定義一些東西。為此,你可以建立一個META-INF/spring-devtools.properties檔案。
該spring-devtools.properties檔案可以包含以restart.exclude和為字首的屬性restart.include。該include元素是應該被拉高到「重啟」的類載入器的專案,以及exclude要素是應該向下推入「Base」類載入器的專案。該屬性的值是應用於類路徑的正規表示式模式,如以下範例所示:
restart:
exclude:
companycommonlibs: "/mycorp-common-[\\w\\d-\\.]+\\.jar"
include:
projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"
更多相關的資訊可以在這裡檢視。
devtool原則上來說應該是隻在開發偵錯的時候使用,而在生產環境執行jar包時是不需要的,所以Spring打包會不會把它打進JAR嗎?
執行打包的應用程式時,開發人員工具會自動禁用。如果你通過 java -jar或者其他特殊的類載入器進行啟動時,都會被認為是「生產環境的應用」。
(生產環境勿用,只有在受信任的網路上執行或使用 SSL 進行保護時,才應啟用它)
在這種情況下,devtool也具備遠端偵錯的能力:遠端使用者端應用程式旨在從你的 IDE 中執行。你需要org.springframework.boot.devtools.RemoteSpringApplication使用與你連線的遠端專案相同的類路徑執行。應用程式的唯一必需引數是它連線到的遠端 URL。
例如,如果使用 Eclipse 或 Spring Tools,並且你有一個my-app已部署到 Cloud Foundry 的名為的專案,執行以下操作:
正在執行的遠端使用者端可能類似於以下列表:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \
\\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) )
' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
=========|_|==============|___/===================================/_/_/_/
:: Spring Boot Remote :: 2.5.4
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 Boot 支援的一些庫使用快取來提高效能。例如,模板引擎快取已編譯的模板以避免重複解析模板檔案。此外,Spring MVC 可以在提供靜態資源時向響應新增 HTTP 快取檔頭。
雖然快取在生產中非常有益,但在開發過程中可能會適得其反,使你無法看到剛剛在應用程式中所做的更改。出於這個原因, spring-boot-devtools 預設禁用快取選項。
比如Thymeleaf 提供了spring.thymeleaf.cache來設定模板引擎的快取,使用spring-boot-devtools模組時是不需要手動設定這些屬性的,因為spring-boot-devtools會自動進行設定。
那麼會自動設定哪些設定呢?你可以在DevToolsPropertyDefaultsPostProcessor類找到對應的預設設定。
public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostProcessor {
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.web.resources.cache.period", "0");
properties.put("spring.web.resources.chain.cache", "false");
properties.put("spring.template.provider.cache", "false");
properties.put("spring.mvc.log-resolved-exception", "true");
properties.put("server.error.include-binding-errors", "ALWAYS");
properties.put("server.error.include-message", "ALWAYS");
properties.put("server.error.include-stacktrace", "ALWAYS");
properties.put("server.servlet.jsp.init-parameters.development", "true");
properties.put("spring.reactor.debug", "true");
PROPERTIES = Collections.unmodifiableMap(properties);
}
當然如果你不想被應用屬性被spring-boot-devtools預設設定, 可以通過spring.devtools.add-properties到false你application.yml中。
可以通過將spring-boot-devtools.yml檔案新增到$HOME/.config/spring-boot目錄來設定全域性 devtools 設定。
新增到這些檔案的任何屬性都適用於你機器上使用 devtools 的所有Spring Boot 應用程式。例如,要將重新啟動設定為始終使用觸發器檔案,你需要將以下屬性新增到你的spring-boot-devtools檔案中:
spring:
devtools:
restart:
trigger-file: ".reloadtrigger"
如果我不用devtool,還有什麼選擇?
在實際的開發過程中,我也不會去使用devtool工具, 因為:
https://github.com/realpdai/tech-pdai-spring-demos
https://docs.spring.io/spring-boot/docs/current/reference/html/using.html