開發人員工具

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")
}
Devtools 可能會導致類別載入問題,尤其是在多模組專案中。診斷類別載入問題說明如何診斷和解決這些問題。
當執行完整封裝的應用程式時,開發人員工具會自動停用。如果您的應用程式是從 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 組態

診斷類別載入問題

重新啟動 vs 重新載入章節中所述,重新啟動功能是透過使用兩個類別載入器來實作的。對於大多數應用程式,這種方法運作良好。但是,有時可能會導致類別載入問題,尤其是在多模組專案中。

若要診斷類別載入問題是否確實是由 devtools 及其兩個類別載入器所引起,請嘗試停用重新啟動。如果這解決了您的問題,請自訂重新啟動類別載入器以包含您的整個專案。

屬性預設值

Spring Boot 支援的多個程式庫都使用快取來提高效能。例如,範本引擎會快取編譯後的範本,以避免重複剖析範本檔案。此外,當提供靜態資源時,Spring MVC 可以將 HTTP 快取標頭新增至回應。

雖然快取在生產環境中非常有利,但在開發期間可能會產生反效果,阻止您看到您剛在應用程式中所做的變更。因此,spring-boot-devtools 預設會停用快取選項。

快取選項通常透過 application.properties 檔案中的設定進行組態。例如,Thymeleaf 提供 spring.thymeleaf.cache 屬性。spring-boot-devtools 模組會自動套用合理的開發時期組態,而無需手動設定這些屬性。

下表列出所有套用的屬性

名稱 預設值

server.error.include-binding-errors

always

server.error.include-message

always

server.error.include-stacktrace

always

server.servlet.jsp.init-parameters.development

true

server.servlet.session.persistent

true

spring.docker.compose.readiness.wait

only-if-started

spring.freemarker.cache

false

spring.graphql.graphiql.enabled

true

spring.groovy.template.cache

false

spring.h2.console.enabled

true

spring.mustache.servlet.cache

false

spring.mvc.log-resolved-exception

true

spring.reactor.netty.shutdown-quiet-period

0s

spring.template.provider.cache

false

spring.thymeleaf.cache

false

spring.web.resources.cache.period

0

spring.web.resources.chain.cache

false

如果您不想要套用屬性預設值,可以在您的 application.properties 中將 spring.devtools.add-properties 設定為 false

由於在開發 Spring MVC 和 Spring WebFlux 應用程式時,您需要更多關於網路請求的資訊,因此開發人員工具建議您為 web 日誌記錄群組啟用 DEBUG 日誌記錄。這將為您提供關於傳入請求、哪個處理常式正在處理它、回應結果和其他詳細資訊的資訊。如果您希望記錄所有請求詳細資訊(包括潛在的敏感資訊),您可以開啟 spring.mvc.log-request-detailsspring.codec.log-request-details 組態屬性。

自動重新啟動

使用 spring-boot-devtools 的應用程式會在類別路徑上的檔案變更時自動重新啟動。當在 IDE 中工作時,這可能是一個有用的功能,因為它可以為程式碼變更提供非常快速的回饋迴圈。預設情況下,會監控類別路徑上指向目錄的任何項目是否有變更。請注意,某些資源,例如靜態資產和檢視範本,不需要重新啟動應用程式

觸發重新啟動

由於 DevTools 監控類別路徑資源,因此觸發重新啟動的唯一方法是更新類別路徑。無論您是使用 IDE 還是建置外掛程式之一,都必須重新編譯修改過的檔案才能觸發重新啟動。您導致類別路徑更新的方式取決於您正在使用的工具

  • 在 Eclipse 中,儲存修改過的檔案會導致類別路徑更新並觸發重新啟動。

  • 在 IntelliJ IDEA 中,建置專案 (Build -> Build Project) 具有相同的效果。

  • 如果使用建置外掛程式,則執行 Maven 的 mvn compile 或 Gradle 的 gradle build 將會觸發重新啟動。

如果您正在使用 Maven 或 Gradle 和建置外掛程式重新啟動,則必須將 forking 設定為 enabled。如果您停用 forking,則不會建立 devtools 使用的隔離應用程式類別載入器,且重新啟動將無法正常運作。
當與 LiveReload 一起使用時,自動重新啟動效果非常好。請參閱LiveReload章節以取得詳細資訊。如果您使用 JRebel,則會停用自動重新啟動,而改用動態類別重新載入。其他 devtools 功能(例如 LiveReload 和屬性覆寫)仍然可以使用。
DevTools 依賴應用程式內容的關閉鉤子,以在重新啟動期間關閉它。如果您已停用關閉鉤子 (SpringApplication.setRegisterShutdownHook(false)),則它無法正常運作。
DevTools 需要自訂 ApplicationContext 使用的 ResourceLoader。如果您的應用程式已提供一個,則將會包裝它。不支援直接覆寫 ApplicationContext 上的 getResource 方法。
當使用 AspectJ weaving 時,不支援自動重新啟動。
重新啟動 vs 重新載入

Spring Boot 提供的重新啟動技術透過使用兩個類別載入器來運作。不變更的類別(例如,來自第三方 jar 的類別)會載入到基礎類別載入器中。您正在積極開發的類別會載入到重新啟動類別載入器中。當應用程式重新啟動時,重新啟動類別載入器會被丟棄並建立一個新的類別載入器。這種方法表示應用程式重新啟動通常比「冷啟動」快得多,因為基礎類別載入器已可用且已填入。

如果您發現重新啟動對於您的應用程式來說不夠快,或者您遇到類別載入問題,您可以考慮重新載入技術,例如 ZeroTurnaround 的 JRebel。這些技術透過在載入類別時重寫類別,使其更易於重新載入。

記錄條件評估中的變更

預設情況下,每次您的應用程式重新啟動時,都會記錄一份報告,顯示條件評估差異。該報告顯示當您進行變更(例如新增或移除 Bean 和設定組態屬性)時,應用程式自動組態的變更。

若要停用報告的日誌記錄,請設定下列屬性

  • 屬性

  • YAML

spring.devtools.restart.log-condition-evaluation-delta=false
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,您將設定下列屬性

  • 屬性

  • YAML

spring.devtools.restart.exclude=static/**,public/**
spring:
  devtools:
    restart:
      exclude: "static/**,public/**"
如果您想要保留這些預設值並新增其他排除項目,請改用 spring.devtools.restart.additional-exclude 屬性。

監看其他路徑

當您變更不在類別路徑上的檔案時,您可能希望重新啟動或重新載入您的應用程式。若要執行此操作,請使用 spring.devtools.restart.additional-paths 屬性來組態要監看變更的其他路徑。您可以使用先前描述的 spring.devtools.restart.exclude 屬性來控制其他路徑下方的變更是否觸發完整重新啟動或即時重新載入

停用重新啟動

如果您不想要使用重新啟動功能,可以使用 spring.devtools.restart.enabled 屬性來停用它。在大多數情況下,您可以在您的 application.properties 中設定此屬性(這樣做仍然會初始化重新啟動類別載入器,但不會監看檔案變更)。

如果您需要完全停用重新啟動支援(例如,因為它不適用於特定的程式庫),您需要在呼叫 SpringApplication.run(…​) 之前將 spring.devtools.restart.enabled System 屬性設定為 false,如下列範例所示

  • Java

  • Kotlin

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);
	}

}
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication

@SpringBootApplication
object MyApplication {

	@JvmStatic
	fun main(args: Array<String>) {
		System.setProperty("spring.devtools.restart.enabled", "false")
		SpringApplication.run(MyApplication::class.java, *args)
	}

}

使用觸發檔案

如果您使用的 IDE 會持續編譯變更的檔案,您可能偏好僅在特定時間觸發重新啟動。若要執行此操作,您可以使用「觸發檔案」,這是一個特殊檔案,必須在您想要實際觸發重新啟動檢查時進行修改。

對檔案的任何更新都會觸發檢查,但僅當 Devtools 偵測到它有事要做時,才會實際發生重新啟動。

若要使用觸發檔案,請將 spring.devtools.restart.trigger-file 屬性設定為您的觸發檔案的名稱(不包含任何路徑)。觸發檔案必須出現在您的類別路徑上的某個位置。

例如,如果您有一個具有以下結構的專案

src
+- main
   +- resources
      +- .reloadtrigger

那麼您的 trigger-file 屬性將會是

  • 屬性

  • YAML

spring.devtools.restart.trigger-file=.reloadtrigger
spring:
  devtools:
    restart:
      trigger-file: ".reloadtrigger"

現在,只有在更新 src/main/resources/.reloadtrigger 時才會發生重新啟動。

您可能想要將 spring.devtools.restart.trigger-file 設定為全域設定,以便您的所有專案都以相同的方式運作。

某些 IDE 具有可讓您免於手動更新觸發檔案的功能。Spring Tools for EclipseIntelliJ IDEA (Ultimate Edition) 都具有此類支援。使用 Spring Tools,您可以從主控台檢視中使用「重新載入」按鈕(只要您的 trigger-file 名稱為 .reloadtrigger)。對於 IntelliJ IDEA,您可以依照其文件中的指示進行操作。

自訂重新啟動類別載入器

重新啟動 vs 重新載入章節前面所述,重新啟動功能是透過使用兩個類別載入器來實作的。如果這導致問題,您可以使用 spring.devtools.restart.enabled 系統屬性來診斷問題,如果應用程式在關閉重新啟動的情況下運作,您可能需要自訂哪個類別載入器載入哪些內容。

預設情況下,IDE 中的任何開啟專案都會使用「重新啟動」類別載入器載入,而任何常規的 .jar 檔案都會使用「基礎」類別載入器載入。如果您使用 mvn spring-boot:rungradle bootRun,情況也是如此:包含您的 @SpringBootApplication 的專案會使用「重新啟動」類別載入器載入,而所有其他專案都使用「基礎」類別載入器載入。當您啟動應用程式時,類別路徑會列印在主控台上,這有助於識別任何有問題的項目。反射性使用的類別,尤其是註解,可能會在啟動時在父級(固定)類別載入器中載入,然後再載入使用它們的應用程式類別,這可能會導致 Spring 在應用程式中無法偵測到它們。

您可以指示 Spring Boot 透過建立 META-INF/spring-devtools.properties 檔案,使用不同的類別載入器載入專案的某些部分。spring-devtools.properties 檔案可以包含以 restart.excluderestart.include 為字首的屬性。include 元素是應拉入「重新啟動」類別載入器的項目,而 exclude 元素是應推入「基礎」類別載入器的項目。屬性的值是一個正則表達式模式,該模式應用於啟動時傳遞給 JVM 的類別路徑。以下範例說明如何在重新啟動類別載入器中排除某些本機類別檔案並包含一些額外的程式庫

restart:
  exclude:
    companycommonlibs: "/mycorp-common-[\\w\\d-\\.]/(build|bin|out|target)/"
  include:
    projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"
所有屬性金鑰都必須是唯一的。只要屬性以 restart.include.restart.exclude. 開頭,就會被視為有效。
會載入來自類別路徑的所有 META-INF/spring-devtools.properties。您可以將檔案封裝在您的專案中,或封裝在專案使用的程式庫中。無法使用系統屬性,只能使用屬性檔案。

已知限制

重新啟動功能無法與使用標準 ObjectInputStream 反序列化的物件良好地運作。如果您需要反序列化資料,您可能需要將 Spring 的 ConfigurableObjectInputStreamThread.currentThread().getContextClassLoader() 結合使用。

不幸的是,多個第三方程式庫在反序列化時沒有考慮內容類別載入器。如果您發現此類問題,則需要向原始作者請求修復。

LiveReload

spring-boot-devtools 模組包含一個嵌入式 LiveReload 伺服器,可用於在資源變更時觸發瀏覽器重新整理。LiveReload 瀏覽器擴充功能可免費用於 Chrome、Firefox 和 Safari。您可以在您選擇的瀏覽器的市場或商店中搜尋「LiveReload」來找到這些擴充功能。

如果您不希望在應用程式執行時啟動 LiveReload 伺服器,您可以將 spring.devtools.livereload.enabled 屬性設定為 false

您一次只能執行一個 LiveReload 伺服器。在啟動您的應用程式之前,請確保沒有其他 LiveReload 伺服器正在執行。如果您從 IDE 啟動多個應用程式,則只有第一個應用程式具有 LiveReload 支援。
若要在檔案變更時觸發 LiveReload,必須啟用自動重新啟動

全域設定

您可以透過將下列任何檔案新增至 $HOME/.config/spring-boot 目錄來組態全域 devtools 設定

  1. spring-boot-devtools.properties

  2. spring-boot-devtools.yaml

  3. spring-boot-devtools.yml

新增至這些檔案的任何屬性都適用於您機器上使用 devtools 的所有 Spring Boot 應用程式。例如,若要組態重新啟動以始終使用觸發檔案,您需要將下列屬性新增至您的 spring-boot-devtools 檔案

  • 屬性

  • YAML

spring.devtools.restart.trigger-file=.reloadtrigger
spring:
  devtools:
    restart:
      trigger-file: ".reloadtrigger"

預設情況下,$HOME 是使用者的主目錄。若要自訂此位置,請設定 SPRING_DEVTOOLS_HOME 環境變數或 spring.devtools.home 系統屬性。

如果在 $HOME/.config/spring-boot 中找不到 devtools 組態檔案,則會在 $HOME 目錄的根目錄中搜尋 .spring-boot-devtools.properties 檔案是否存在。這可讓您與使用不支援 $HOME/.config/spring-boot 位置的舊版 Spring Boot 的應用程式共用 devtools 全域組態。

devtools 屬性/yaml 檔案中不支援設定檔。

.spring-boot-devtools.properties 中啟用的任何設定檔都不會影響設定檔特定的組態檔案的載入。設定檔特定的檔案名稱(格式為 spring-boot-devtools-<profile>.properties)以及 YAML 和 Properties 檔案中的 spring.config.activate.on-profile 文件均不受支援。

設定檔案系統監看器

FileSystemWatcher 透過以一定的時間間隔輪詢類別變更來運作,然後等待預定義的靜默期,以確保不再有變更。由於 Spring Boot 完全依賴 IDE 來編譯檔案並將檔案複製到 Spring Boot 可以讀取它們的位置,因此您可能會發現有時在 devtools 重新啟動應用程式時,某些變更未反映出來。如果您經常觀察到此類問題,請嘗試將 spring.devtools.restart.poll-intervalspring.devtools.restart.quiet-period 參數增加到適合您開發環境的值

  • 屬性

  • YAML

spring.devtools.restart.poll-interval=2s
spring.devtools.restart.quiet-period=1s
spring:
  devtools:
    restart:
      poll-interval: "2s"
      quiet-period: "1s"

現在每 2 秒輪詢受監控的類別路徑目錄是否有變更,並維持 1 秒的靜默期,以確保不再有其他類別變更。

遠端應用程式

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 屬性時,伺服器元件會自動啟用。用戶端元件必須手動啟動。

Spring WebFlux 應用程式不支援遠端 devtools。

執行遠端用戶端應用程式

遠端用戶端應用程式設計為從您的 IDE 內部執行。您需要使用與您連線的遠端專案相同的類別路徑來執行 org.springframework.boot.devtools.RemoteSpringApplication。此應用程式唯一需要的引數是其連線的遠端 URL。

例如,如果您使用 Eclipse 或 Spring Tools,且您有一個名為 my-app 的專案已部署到 Cloud Foundry,您可以執行以下操作

  • Run 選單中選取 Run Configurations…​

  • 建立新的 Java Application「啟動組態」。

  • 瀏覽尋找 my-app 專案。

  • 使用 org.springframework.boot.devtools.RemoteSpringApplication 作為主要類別。

  • https://myapp.cfapps.io 新增至 Program arguments (或您的遠端 URL)。

一個正在執行的遠端用戶端可能類似於以下列表

  .   ____          _                                              __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _          ___               _      \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` |        | _ \___ _ __  ___| |_ ___ \ \ \ \
 \\/  ___)| |_)| | | | | || (_| []::::::[]   / -_) '  \/ _ \  _/ -_) ) ) ) )
  '  |____| .__|_| |_|_| |_\__, |        |_|_\___|_|_|_\___/\__\___|/ / / /
 =========|_|==============|___/===================================/_/_/_/
 :: Spring Boot Remote ::  (v3.3.5)

2024-10-24T12:03:02.454Z  INFO 112504 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Starting RemoteSpringApplication v3.3.5 using Java 17.0.13 with PID 112504 (/Users/myuser/.m2/repository/org/springframework/boot/spring-boot-devtools/3.3.5/spring-boot-devtools-3.3.5.jar started by myuser in /opt/apps/)
2024-10-24T12:03:02.487Z  INFO 112504 --- [           main] o.s.b.devtools.RemoteSpringApplication   : No active profile set, falling back to 1 default profile: "default"
2024-10-24T12:03:03.165Z  INFO 112504 --- [           main] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2024-10-24T12:03:03.204Z  INFO 112504 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Started RemoteSpringApplication in 2.032 seconds (process running for 2.824)
由於遠端用戶端使用與真實應用程式相同的類別路徑,因此它可以直接讀取應用程式屬性。這就是 spring.devtools.remote.secret 屬性被讀取並傳遞到伺服器以進行驗證的方式。
始終建議使用 https:// 作為連線協定,以便流量加密且密碼不會被攔截。
如果您需要使用 Proxy 來存取遠端應用程式,請設定 spring.devtools.remote.proxy.hostspring.devtools.remote.proxy.port 屬性。

遠端更新

遠端用戶端會以與 本機重新啟動 相同的方式監控您的應用程式類別路徑中的變更。任何更新的資源都會推送至遠端應用程式,並且(如果需要)觸發重新啟動。如果您迭代使用您在本機沒有的雲端服務的功能,這會很有幫助。通常,遠端更新和重新啟動比完整的重建和部署週期快得多。

在較慢的開發環境中,可能會發生靜默期不足的情況,並且類別中的變更可能會分成批次。伺服器會在第一批類別變更上傳後重新啟動。下一批次無法傳送到應用程式,因為伺服器正在重新啟動。

這通常會透過 RemoteSpringApplication 日誌中關於上傳某些類別失敗以及後續重試的警告來體現。但這也可能導致應用程式程式碼不一致,以及在第一批變更上傳後無法重新啟動。如果您經常觀察到此類問題,請嘗試增加 spring.devtools.restart.poll-intervalspring.devtools.restart.quiet-period 參數的值,以符合您的開發環境。請參閱 設定檔案系統監看器 章節,以了解如何設定這些屬性。

檔案僅在遠端用戶端執行時才會受到監控。如果您在啟動遠端用戶端之前變更檔案,則不會將其推送至遠端伺服器。