開發者工具

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 配置

診斷類載入問題

重啟與過載部分所述,重啟功能透過使用兩個類載入器實現。對於大多數應用來說,這種方法工作良好。然而,它有時可能會導致類載入問題,尤其是在多模組專案中。

要診斷類載入問題是否確實由 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 請求的資訊,開發者工具建議你為 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 時不支援自動重啟。
重啟與過載

Spring Boot 提供的重啟技術透過使用兩個類載入器來實現。不發生變化的類(例如,來自第三方 jar 的類)載入到 base 類載入器中。你正在積極開發的類載入到 restart 類載入器中。當應用重啟時,restart 類載入器會被丟棄並建立一個新的。這種方法意味著應用重啟通常比“冷啟動”快得多,因為 base 類載入器已經可用並已填充。

如果你發現重啟對你的應用來說不夠快或者遇到了類載入問題,你可以考慮使用 ZeroTurnaround 的 JRebel 等過載技術。這些技術透過在類載入時重寫類,使其更適合過載。

記錄條件評估的變化

預設情況下,每次應用重啟時,都會記錄一份顯示條件評估增量的報告。該報告會顯示隨著你進行諸如新增或移除 Bean 和設定配置屬性等更改時,你的應用自動配置的變化。

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

  • Properties

  • 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,你可以設定以下屬性

  • Properties

  • 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 屬性將是

  • Properties

  • 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,你可以遵循其文件中的說明

自定義重啟類載入器

重啟與過載部分前面所述,重啟功能透過使用兩個類載入器實現。如果這導致了問題,你可以使用 spring.devtools.restart.enabled 系統屬性來診斷問題,如果應用在關閉重啟後能夠正常工作,你可能需要自定義哪些內容由哪個類載入器載入。

預設情況下,你的 IDE 中的任何開放專案都透過“重啟”類載入器載入,而任何常規的 .jar 檔案都透過“基礎”類載入器載入。如果你使用 mvn spring-boot:rungradle bootRun,情況也是如此:包含你的 @SpringBootApplication 的專案透過“重啟”類載入器載入,其餘所有內容透過“基礎”類載入器載入。應用啟動時會在控制檯上列印類路徑,這有助於識別任何有問題的條目。反射使用的類,尤其是註解,可能在應用類使用它們之前被載入到父級(固定)類載入器中,這可能導致 Spring 在應用中無法檢測到它們。

你可以透過建立一個 META-INF/spring-devtools.properties 檔案來指示 Spring Boot 使用不同的類載入器載入專案的某些部分。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 檔案中

  • Properties

  • 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 檔案中不支援 Profile。

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

配置檔案系統監視器

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

  • Properties

  • 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 內部執行。你需要使用與你連線的遠端專案相同的 classpath 來執行 RemoteSpringApplication。該應用程式唯一必需的引數是它連線的遠端 URL。

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

  • Run 選單中選擇 Run Configurations…​

  • 建立一個新的 Java Application “啟動配置”。

  • 瀏覽找到 my-app 專案。

  • 使用 RemoteSpringApplication 作為主類。

  • https://myapp.cfapps.io 新增到 Program arguments 中(或者你的遠端 URL 是什麼就填什麼)。

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

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

2025-04-24T13:04:45.447Z  INFO 128087 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Starting RemoteSpringApplication v3.4.5 using Java 17.0.15 with PID 128087 (/Users/myuser/.m2/repository/org/springframework/boot/spring-boot-devtools/3.4.5/spring-boot-devtools-3.4.5.jar started by myuser in /opt/apps/)
2025-04-24T13:04:45.472Z  INFO 128087 --- [           main] o.s.b.devtools.RemoteSpringApplication   : No active profile set, falling back to 1 default profile: "default"
2025-04-24T13:04:46.769Z  INFO 128087 --- [           main] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2025-04-24T13:04:46.873Z  INFO 128087 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Started RemoteSpringApplication in 3.848 seconds (process running for 5.081)
因為遠端客戶端使用與實際應用程式相同的 classpath,所以它可以直接讀取應用程式屬性。spring.devtools.remote.secret 屬性就是這樣被讀取並傳遞給伺服器進行認證的。
始終建議使用 https:// 作為連線協議,以便對流量進行加密,防止密碼被截獲。
如果你需要使用代理來訪問遠端應用程式,請配置 spring.devtools.remote.proxy.hostspring.devtools.remote.proxy.port 屬性。

遠端更新

遠端客戶端監視你的應用程式 classpath 中的更改,方式與本地重啟相同。任何更新的資源都會被推送到遠端應用程式並(如果需要)觸發重啟。如果你正在迭代開發某個功能,而該功能使用了一個你本地沒有的雲服務,這將非常有用。一般來說,遠端更新和重啟比完整的重建和部署週期要快得多。

在較慢的開發環境中,可能會出現安靜期不夠,導致類的更改被分成多個批次。第一批類更改上傳後,伺服器會重啟。由於伺服器正在重啟,下一批次無法傳送到應用程式。

這通常表現為在RemoteSpringApplication日誌中出現關於未能上傳部分類的警告,並隨之進行重試。但它也可能導致應用程式程式碼不一致,並在第一批更改上傳後重啟失敗。如果你經常遇到此類問題,請嘗試增加 spring.devtools.restart.poll-intervalspring.devtools.restart.quiet-period 引數的值,使其適合你的開發環境。有關配置這些屬性的資訊,請參閱配置檔案系統監視器部分。

只有當遠端客戶端執行時,檔案才會被監視。如果你在啟動遠端客戶端之前更改了檔案,則不會將其推送到遠端伺服器。