6. 使用 Spring Boot進行開發(Developing with Spring Boot)
本節詳細介紹了如何使用Spring Boot。它涵蓋考慮構建系統、自動配置以及如何運行應用程序等主題。我們還介紹一些 Spring Boot 最新做法。雖然 Spring Boot 沒有什么特別之處(它只是你使用的一個庫),它會有一些建議,當您遵循這些建議,可以使您的開發過程更容易一些。
如果您從 Spring Boot 開始,在進入本章節之前,你應該閱讀 入門指南 。
6.1 構建系統(Build Systems)
強烈建議您選擇一個 依賴管理 來構建項目,而且可以使用發布到 “Maven Central” 庫的組件。我們建議您選擇 Maven 或 Gradle。你也可以讓 Spring Boot 和其它構建系統(例如Ant)配合使用,但是它們的支持并不完善。
6.1.1 依賴管理(Dependency Management)
Spring Boot 的每個版本都會提供其支持的依賴項列表。實際上,你不需要提供構建配置中依賴項的版本,因為Spring Boot 會為您管理這些依賴項。當您升級 Spring Boot 本身時,這些依賴項也會統一升級。
::: tip 提示
如果需要,您仍然可以指定依賴版本并覆蓋 Spring Boot 的設置版本。
:::
列表中包含了所有的 Spring 模塊,以及第三方庫的詳細列表。該列表以標準清單spring-boot-dependencies
的形式提供,可以與 Maven 和 Gradle 一起使用。
::: warning 警告
Spring Boot 的每個版本都與 Spring Framework 的集成版本息息相關。我們強烈建議你不要指定它的版本。
:::
6.1.2 Maven
要了解如何將 Spring Boot 與 Maven 結合使用,請參閱 Spring Boot 的 Maven 插件文檔:
- 參考資料 (HTML 和 PDF)
- API
6.1.3 Gradle
要了解如何將 Spring Boot 與 Gradle 結合使用,請參閱 Spring Boot 的 Gradle 插件文檔:
- 參考資料(HTML 和 PDF)
- API
6.1.4 Ant
使用 Apache Ant+Ivy 可以構建 Spring Boot 項目。此外,“AntLib” 模塊 spring-boot-antlib
可以幫助 Ant 創建可執行jar。
如果要聲明依賴關系, ivy.xml
文件應與下方示例類似:
<ivy-module version="2.0"><info organisation="org.springframework.boot" module="spring-boot-sample-ant"/><configurations><conf name="compile" description="everything needed to compile this module"/><conf name="runtime" extends="compile" description="everything needed to run this module"/></configurations><dependencies><dependency org="org.springframework.boot" name="spring-boot-starter"rev="${spring-boot.version}" conf="compile"/></dependencies>
</ivy-module>
build.xml
文件應與下方示例類似:
<projectxmlns:ivy="antlib:org.apache.ivy.ant"xmlns:spring-boot="antlib:org.springframework.boot.ant"name="myapp" default="build"><property name="spring-boot.version" value="2.7.18-SNAPSHOT"/><target name="resolve" description="--> retrieve dependencies with ivy"><ivy:retrieve pattern="lib/[conf]/[artifact]-[type]-[revision].[ext]"/></target><target name="classpaths" depends="resolve"><path id="compile.classpath"><fileset dir="lib/compile" includes="*.jar"/></path></target><target name="init" depends="classpaths"><mkdir dir="build/classes"/></target><target name="compile" depends="init" description="compile"><javac srcdir="src/main/java" destdir="build/classes" classpathref="compile.classpath"/></target><target name="build" depends="compile"><spring-boot:exejar destfile="build/myapp.jar" classes="build/classes"><spring-boot:lib><fileset dir="lib/runtime"/></spring-boot:lib></spring-boot:exejar></target>
</project>
::: tip 提示
如果不想使用 spring-boot-antlib
模塊,請參閱 Build an Executable Archive From Ant without Using spring-boot-antlib 。
:::
6.1.5 Starters
場景啟動器是一組依賴關系的描述,您可以將其包含在應用程序中。你可以獲得所需的全部 Spring 以及相關技術的一站式服務,而無需搜索示例代碼和復制粘貼依賴描述符。例如,如果您開始使用 Spring 和 JPA 進行數據庫訪問,請在項目中包含 spring-boot-starter-data-jpa
依賴。
場景啟動器包含大量的依賴項,這些依賴項可以讓項目快速啟動和運行,并提供一套一致的、受支持的依賴項傳遞。
::: tip What is in a name
所有官方場景啟動器都遵循類型的命名模式; spring-boot-starter-*
,其中 *
為特定類型的應用程序。這種命名結構的目的是需要查找場景啟動器時提供幫助。許多集成開發環境中的 Maven 都可以讓您按名稱搜索依賴項。例如,如果安裝了相應的 Eclipse 或 Spring 插件,就可以在 POM 編輯器中鍵入 ctrl-space
鍵,然后鍵入“spring-boot-starter”,查看完整列表。
在 “創建自己的場景啟動器” 部分所述,第三方啟動器不應該以spring-boot
開頭,因為spring-boot
是 Spring Boot 官方庫的專屬開通。相反,第三方啟動器通常以項目名稱開通,例如,名為 thirdpartyproject
的第三方啟動器通常會命名為thirdpartyproject-spring-boot-starter
。
:::
以下場景啟動器是 Spring Boot 官方提供的,都屬于 org.springframework.boot
組:
表 1. Spring Boot 應用程序啟動器
Name | Description |
---|---|
spring-boot-starter | 核心啟動器,包括自動配置、日志記錄和 YAML |
spring-boot-starter-activemq | 集成 Apache ActiveMQ 的 JMS messaging 啟動器 |
spring-boot-starter-amqp | 集成 Spring AMQP 和 Rabbit MQ 的啟動器 |
spring-boot-starter-aop | 集成 Spring AOP 和 AspectJ 進行面向切面編程的啟動器 |
spring-boot-starter-artemis | 集成 Apache Artemis 的 JMS messaging 啟動器 |
spring-boot-starter-batch | 集成 Spring Batch 的啟動器 |
spring-boot-starter-cache | 集成 Spring Framework 緩存支持的啟動器 |
spring-boot-starter-data-cassandra | 集成 Cassandra 分布式數據庫和 Spring Data Cassandra 的啟動器 |
spring-boot-starter-data-cassandra-reactive | 集成 Cassandra 分布式數據庫和 Spring Data Cassandra Reactive 的啟動器 |
spring-boot-starter-data-couchbase | 集成面向文檔的 Couchbase 數據庫和 Spring Data Couchbase 的啟動器 |
spring-boot-starter-data-couchbase-reactive | 集成面向文檔的 Couchbase 數據庫和 Spring Data Couchbase Reactive 的啟動器 |
spring-boot-starter-data-elasticsearch | 集成 Elasticsearch 搜索、分析引擎和 Spring Data Elasticsearch 的啟動器 |
spring-boot-starter-data-jdbc | 集成 Spring Data JDBC 的啟動器 |
spring-boot-starter-data-jpa | 集成 Spring Data JPA 和 Hibernate 的啟動器 |
spring-boot-starter-data-ldap | 集成 Spring Data LDAP 的啟動器 |
spring-boot-starter-data-mongodb | 集成面向文檔的 MongoDB 數據庫和 Spring Data MongoDB 的啟動器 |
spring-boot-starter-data-mongodb-reactive | 集成面向文檔的 MongoDB 數據庫和 Spring Data MongoDB Reactive 的啟動器 |
spring-boot-starter-data-neo4j | 集成 Neo4j 圖形數據庫和 Spring Data Neo4j 的啟動器 |
spring-boot-starter-data-r2dbc | 集成 Spring Data R2DBC 的啟動器 |
spring-boot-starter-data-redis | 集成 Redis 存儲、Spring Data Redis 和 Lettuce 客戶端的啟動器 |
spring-boot-starter-data-redis-reactive | 集成 Redis 存儲、Spring Data Redis reactive 和 Lettuce 客戶端的啟動器 |
spring-boot-starter-data-rest | 使用 Spring Data REST 和 Spring MVC 通過 REST 訪問 Spring Data存儲庫的啟動器 |
spring-boot-starter-freemarker | 使用 FreeMarker 視圖構建 MVC 網絡應用程序的啟動器 |
spring-boot-starter-graphql | 使用 Spring GraphQL 構建 GraphQL 應用程序的啟動器 |
spring-boot-starter-groovy-templates | 使用 Groovy 模板視圖構建 MVC 網絡應用程序的啟動器 |
spring-boot-starter-hateoas | 使用 Spring MVC 和 Spring HATEOAS 構建基于超媒體的 RESTful 網絡應用程序的啟動器 |
spring-boot-starter-integration | 集成 Spring Integration 的啟動器 |
spring-boot-starter-jdbc | 集成 HikariCP 連接池的JDBC啟動器 |
spring-boot-starter-jersey | 使用 JAX-RS 和 Jersey 構建 RESTful 網絡應用程序的啟動器。可以代替 spring-boot-starter-web |
spring-boot-starter-jooq | 使用 jOOQ 通過JDBC 訪問 SQL 數據庫的啟動器。可以代替 spring-boot-starter-data-jpa 或 spring-boot-starter-jdbc |
spring-boot-starter-json | 用于讀寫 json 的啟動器 |
spring-boot-starter-jta-atomikos | 使用 Atomikos 進行 JTA 事務的啟動器 |
spring-boot-starter-mail | 使用 Java Mail 和 Spring Framework 電子郵件支持發送的啟動器 |
spring-boot-starter-mustache | 使用 Mustache 視圖構建網絡應用程序的啟動器 |
spring-boot-starter-oauth2-client | 使用 Spring Security 的 OAuth2/OpenID 連接客戶端功能的啟動器 |
spring-boot-starter-oauth2-resource-server | 使用 Spring Security 的 OAuth2 資源服務功能的啟動器 |
spring-boot-starter-quartz | 集成 Quartz scheduler 的啟動器 |
spring-boot-starter-rsocket | 用于構建 RSocket 客戶端和服務器的啟動器 |
spring-boot-starter-security | 集成 Spring Security 的啟動器 |
spring-boot-starter-test | 使用 JUnit Jupiter、Hamcrest 和 Mockito 等庫測試 Spring Boot 應用程序的啟動器 |
spring-boot-starter-thymeleaf | 使用 Thymeleaf 視圖構建 MVC 應用程序的啟動器 |
spring-boot-starter-validation | 使用 Hibernate 驗證器進行 Java Bean 驗證的啟動器 |
spring-boot-starter-web | 使用 Spring MVC 構建Web(包括 RESTful)應用程序的啟動器。使用 Tomcat 作為默認嵌入式容器 |
spring-boot-starter-web-services | 集成 Spring Web Services 的啟動器 |
spring-boot-starter-webflux | 使用 Spring Framework 的 Reactive Web 支持構建 WebFlux 應用程序的啟動器 |
spring-boot-starter-websocket | 使用 Spring Framework 的 WebSocket 支持構建WebSocket啟動器 |
除應用程序啟動器外,還可使用以下啟動器添加 production ready 功能:
表 2. Spring Boot 生產環境啟動器
Name | Description |
---|---|
spring-boot-starter-actuator | 使用 Spring Boot 的 Actuator 的啟動器,它提供production ready功能,幫助您監控和管理應用程序 |
最后,Spring Boot 還包括一些用于排除或交換特定技術方向的啟動器:
表 3. Spring Boot 技術啟動器
Name | Description |
---|---|
spring-boot-starter-jetty | 使用 Jetty 作為嵌入式 servlet 容器的啟動器。可以替代 spring-boot-starter-tomcat |
spring-boot-starter-log4j2 | 使用 Log4j2 進行日志記錄的啟動器。可以替代 spring-boot-starter-logging |
spring-boot-starter-logging | 使用 Logback 進行日志記錄的啟動器。默認的日志啟動器 |
spring-boot-starter-reactor-netty | 使用 Reactor Netty 作為嵌入式響應式 HTTP 服務器的啟動器 |
spring-boot-starter-tomcat | 使用 Tomcat 作為嵌入式 servlet 容器的啟動器。使用默認 servlet 容器啟動器 spring-boot-starter-web |
spring-boot-starter-undertow | 使用 Undertow 作為嵌入式 servlet 容器的啟動器。可以替代 spring-boot-starter-tomcat |
要深入了解技術交互方向的知識,請參閱r swapping web server 和 logging system。
::: tip 提示
有關其他社區貢獻的啟動器列表,請參閱 GitHub 上的spring-boot-starters
模塊的 README 文件 。
:::
6.2 構建你的代碼(Structuring Your Code)
Spring Boot 不需要任何特定的代碼結構。然而,也有一些最佳實現是很有幫助的。
6.2.1 使用默認包(Using the “default” Package)
當一個類不包含 package
聲明。它通常被認為在一個“默認包”中。一般不建議使用 “默認包” ,應該避免使用。它會給使用 @ComponentScan
, @ConfigurationPropertiesScan
, @EntityScan
或 @SpringBootApplication
注解的 Spring Boot 應用程序帶來很多問題,因為每個 jar 中的每個類都會被讀取。
::: tip 提示
我們建議您遵循 Java 推薦的軟件包命名約定,并使用相反的域名(例如,com.example.project
)。
:::
6.2.2 定位主程序類(Locating the Main Application Class)
我們通常建議將主程序類放到根包中。 @SpringBootApplication
注解 會放在主類上,它隱式地為某些項目定義了一個基礎的 “search package” 。例如,如果你正在編寫一個 JPA 應用程序,那么使用 @SpringBootApplication
注解的類所在的包將會搜索 @Entity
。使用根包還可以讓組件只應用到你的項目。
::: tip 提示
如果你不使用 @SpringBootApplication
,你應該使用 @EnableAutoConfiguration
和 @ComponentScan
注解來代替它。
:::
下面列出了一個典型項目的布局:
com+- example+- myapplication+- MyApplication.java|+- customer| +- Customer.java| +- CustomerController.java| +- CustomerService.java| +- CustomerRepository.java|+- order+- Order.java+- OrderController.java+- OrderService.java+- OrderRepository.java
MyApplication.java
文件定義了 main
方法,以及 @SpringBootApplication
,如下所示:
@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}}
6.3 配置類(Configuration Classes)
Spring Boot 偏好基于 Java 的配置。雖然可以將. SpringApplication
和 XML 結合使用,但是我們通常建議您將一個 @Configuration
類作為主要來源。通常,定義的 main
方法的類適合作為主要的 @Configuration
。
::: tip 提示
在互聯網上發布了很多使用XML配置的Spring配置示例,如果可能,請盡量使用基于Java的等效配置。搜索 Enable*
注解是一個很多方法。
:::
6.3.1 導入其它配置類(Importing Additional Configuration Classes)
你不需要把全部的 @Configuration
放在一個類中。 @Import
注解可以用于導入其它配置類。或者,您可以使用 @ComponentScan
主動掃描注入全部的Spring組件,包括 @Configuration
。
6.3.2 導入XML配置(Importing XML Configuration)
如果您一定要使用基于XML的配置,我們建議您從 @Configuration
類開始。然后,您可以使用 @ImportResource
注解來加載XML配置文件。
6.4 自動配置(Auto-configuration)
Spring Boot 自動配置會嘗試根據您添加的jar依賴關系自動配置您的 Spring 應用程序。例如,如果 HSQLDB
在類路徑上,而您沒有手動配置任何數據庫連接nean,則 Spring Boot 會自動配置內存數據庫。
你需要在其中一個 @Configuration
類中添加@EnableAutoConfiguration
或 @SpringBootApplication
注解,從而添加自動配置功能
::: tip 提示
你只能添加一個 @SpringBootApplication
或 @EnableAutoConfiguration
注解。我們通常建議你只在主要的 @Configuration
添加其中一個組件。
:::
6.4.1 逐步取代自動配置(Gradually Replacing Auto-configuration)
自動配置是非侵入性的。在任何時候,你都可以開始定義自己的配置,用來取代自動配置的特定部分。例如,如果您添加了自己的 DataSource
bean,默認嵌入式數據庫不在進行支持。
個你需要了解當前應用的自動配置及其原因,請使用 --debug
開關啟動應用程序。這樣做可以為選定的核心日志記錄器啟用debug日志,并將報告記錄到控制臺。
6.4.2 禁用特定的自動配置類(Disabling Specific Auto-configuration Classes)
如果你發現當前應用中您不需要的特定自動配置類,你可以使用 @SpringBootApplication
的exclude屬性來禁用它們,如下所示:
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MyApplication {}
如果類不在classpath上,可以使用注解的 excludeName
屬性來指定全限定類名。如果你更傾向于使用 @EnableAutoConfiguration
而不是 @SpringBootApplication
,也可以使用exclude
和 excludeName
,最后,你可以使用 spring.autoconfigure.exclude
屬性來控制需要排除的自動配置類列表。
::: tip 提示
您可以在注解級別的和使用屬性來定義排除項。
:::
::: tip 提示
盡管自動配置類是 public
,但是該類唯一被認為公共API的部分是類名,該名稱可用于禁用自動配置。這些類的實際內容(比如嵌套配置類或bean方法)僅供內部使用,我們不建議直接使用這些。
:::
6.4.3 自動配置包路徑(Auto-configuration Packages)
自動配置包路徑是各種自動配置功能掃描實體和Spring Data repositories默認查找的包路徑。 @EnableAutoConfiguration
注解(或者直接通過@SpringBootApplication
)來決定默認的自動配置包路徑。可以使用@AutoConfigurationPackage
注解配置其它軟件包路徑。
6.5 Spring Beans 和依賴注入(Spring Beans and Dependency Injection)
你可以自由使用任何標準的 Spring Framework 技術來定義您的 bean 及其注入的依賴項。我們通常建議使用構造器注入的方式來進行依賴注入,并使用 @ComponentScan
來查找Bean。
如果你按照上面的建議(將主程序類放到頂級包中)修改代碼架構,你就可以添加 @ComponentScan
(無需任何參數)或者使用 @SpringBootApplication
(包含前者)。所有的應用程序組件(@Component
, @Service
, @Repository
, @Controller
等)都會自動注入成 Spring Bean。
下面的示例顯示了一個使用構造器注入獲取所需 RiskAssessor
Bean 的 @Service
Bean:
@Service
public class MyAccountService implements AccountService {private final RiskAssessor riskAssessor;public MyAccountService(RiskAssessor riskAssessor) {this.riskAssessor = riskAssessor;}// ...}
如果一個Bean有多個構造函數,則需要用 @Autowired
來標記您希望Spring使用的構造函數:
@Service
public class MyAccountService implements AccountService {private final RiskAssessor riskAssessor;private final PrintStream out;@Autowiredpublic MyAccountService(RiskAssessor riskAssessor) {this.riskAssessor = riskAssessor;this.out = System.out;}public MyAccountService(RiskAssessor riskAssessor, PrintStream out) {this.riskAssessor = riskAssessor;this.out = out;}// ...}
::: tip 提示
請注意,使用構造器注入可以將 riskAssessor
字段標記為 final
字段,表示以后不能更改。
:::
6.6 使用@SpringBootApplication注解(Using the @SpringBootApplication Annotation)
許多 Spring Boot 開發人員都希望自己的應用程序能夠使用自動配置、組件掃描,并能在 "application class"定義額外的配置。只需要使用 @SpringBootApplication
注解就可以啟用這三個功能,即:
@EnableAutoConfiguration
:啟用 Spring Boot 的自動配置機制@ComponentScan
:在應用程序所在包路徑上啟動@Component
掃描 (參閱 the best practices)@SpringBootConfiguration
:啟用在上下文中注冊額外的 Bean 或導入額外的配置類。她是Spring標準@Configuration
的替代品,有助于集成測試紅的 configuration detection 。
// Same as @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}}
::: tip 提示
@SpringBootApplication
提供了別名來自定義 @EnableAutoConfiguration
和 @ComponentScan
的屬性。
:::
::: tip 提示
這些功能都不是強制性的,你可以選擇用它所啟用的任何功能來替代這個單一注解。例如,您可能不想在應用程序中使用組件掃描或配置屬性掃描:
@SpringBootConfiguration(proxyBeanMethods = false)
@EnableAutoConfiguration
@Import({ SomeConfiguration.class, AnotherConfiguration.class })
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}}
在上述示例中, MyApplication
和其它 Spring Boot 應用程序一樣,只是 @Component
-annotated 類和 @ConfigurationProperties
-annotated 類不會被自動掃描到,而用戶定義Bean的會被顯式導入 (參閱 @Import
)。
:::
6.7 運行應用程序(Running Your Application)
將應用程序打包成jar并使用嵌入式HTTP服務器是最大優勢之一,您可以像運行其它服務器一樣運行應用程序。調試Spring Boot應用程序也很容易。您不需要任何特殊的IDE插件或擴展。
::: tip 備注
本章節僅涉及打包成jar文件。如果您選擇將應用程序打包成war文件嗎,請參閱服務器和IDE文檔。
:::
6.7.1 使用IDE運行(Running From an IDE)
您可以將 Spring Boot 應用程序作為一個 Java 應用程序在IDE中運行。然而,您首先需要導入您的項目。導入步驟因IDE和構建系統而異。大多數 IDE 可以直接導入 Maven 項目。例如,Eclipse 用戶可以 File
菜單中選擇 Import…
→ Existing Maven Projects
。
如果無法直接將項目導入 IDE,則可以使用build插件生成IDE基礎開發架構。Maven 包含很多用于 Eclipse 和 IDEA 的插件。 Gradle 為 various IDEs 也提供了插件。
::: tip 提示
如果無意中運行了Web應用程序兩次,就會看到 “Port already in use” 錯誤。Spring 工具用戶可以使用 重新啟動(Relaunch
)按鈕而不是運行(Run
)按鈕以確保關閉任何現有實例。
:::
6.7.2 作為打包程序運行(Running as a Packaged Application)
如果您使用 Spring Boot Maven 或 Gradle 插件創建可執行jar,你可以使用 java -jar
運行應用程序,如下例所示:
$ java -jar target/myapplication-0.0.1-SNAPSHOT.jar
也可以在啟用遠程調試支持的情況下運行打包應用程序。這樣做可以將調試器附加到打包的應用程序上,如下例所示:
$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \-jar target/myapplication-0.0.1-SNAPSHOT.jar
6.7.3 使用Maven插件(Using the Maven Plugin)
Spring Boot Maven 插件包含 run
命令,可以用于快速編譯和運行您的應用程序。應用程序以 exploded 形式運行,就像在 IDE 中一樣。下面示例展示了運行SpringBoot應用程序的命令:
$ mvn spring-boot:run
您可以需要使用 MAVEN_OPTS
操作系統環境變量,如下所示:
$ export MAVEN_OPTS=-Xmx1024m
6.7.4 使用Gradle插件(Using the Gradle Plugin)
Spring Boot Gradle 插件包括 bootRun
任務,可以以1 exploded 的形式運行您的應用程序。每當您應用 org.springframework.boot
和 java
插件時,都會添加 bootRun
任務,如下所示:
$ gradle bootRun
您可以需要使用 JAVA_OPTS
操作系統環境變量,如下所示:
$ export JAVA_OPTS=-Xmx1024m
6.7.5 熱插拔(Hot Swapping)
由于 Spring Boot 應用程序只是普通的 Java 應用程序,因此,JVM 熱插拔可以開箱即用。 JVM 熱插拔在某種程度上受限于它可以替換的字節碼。要獲得更完整的解決方案,可以使用 JRebel 。
spring-boot-devtools
模塊也支持快速重啟應用程序。詳情參閱 Hot swapping “How-to” 。
6.8 Developer Tools
Spring Boot 包含一套額外的工具,可以讓應用程序開發體驗更加愉快。spring-boot-devtools
模塊可以包含在任何項目中,以便提供額外的開發功能。如果要包含 devtools 支持,請將模塊依賴添加到您的構建中,如下所示:
Maven
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency>
</dependencies>
Gradle
configurations {developmentOnlyruntimeClasspath {extendsFrom developmentOnly}
}
dependencies {developmentOnly("org.springframework.boot:spring-boot-devtools")
}
::: tip 注意事項
Devtools 可能會導致類加載問題,尤其是在多模塊項目中。 Diagnosing Classloading Issues 解釋了如何診斷和解決這些問題。
:::
::: tip 提示
運行打包之后的應用程序是,會自動禁用devtools。
如果您的應用程序是使用 java -jar
啟動,或者使用一個特定的類加載器啟動,那么它將被視為“production application”。您可以使用 spring.devtools.restart.enabled
屬性來控制是否啟用 devtools。
如果要啟用,而不考慮類加載器,請設置 -Dspring.devtools.restart.enabled=true
。在生產環境運行devtools 會帶來安全風險.
如果要禁用 devtools,請排除依賴關系或設置 -Dspring.devtools.restart.enabled=false
。
:::
::: tip 提示
在 Maven 中將依賴關系標記為可選,或在Gradle 中使用 developmentOnly
配置(如上圖所示),可以防止devtools 被應用到項目的其它模塊中。
:::
::: tip 提示
重新打包的歸檔文件默認不包括 devtools 。如果需要使用 某些遠程 devtools 功能,則需要包含它。當使用 Maven 插件時,將 excludeDevtools
屬性設置為 false
。當使用 Gradle 插件時,配置依賴的類路徑包含 developmentOnly
配置.
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><!--確保項目打包是將Devtools包含進去--><excludeDevtools>false</excludeDevtools></configuration></plugin></plugins>
</build>
:::
6.8.1 診斷類加載問題(Diagnosing Classloading Issues)
正如 重啟 vs 重載 部分所述,重啟功能是通過使用兩個類加載器實現的,對于大多數應用程序,這種方法效果良好。然而,又是會導致類加載問題,特別是在多模塊項目中。
判斷類加載問題是否由devtools 和兩個類加載器,可以嘗試禁用重啟. 如果問題得到解決,請 customize the restart classloader 使其包含整個項目。
6.8.2 Propert默認值(Property Defaults)
Spring Boot 支持一些庫使用緩存來提高性能。例如,模板引擎 緩存已編譯的模板,以避免重復解析模板文件。此外,Spring MVC 還可以在提供靜態資源時為響應添加HTTP緩存響應頭。
雖然緩存在生產中非常有益,但在開發過程中卻可能適得其反,讓你無法看到剛剛在應用程序中做出的更改。因此,spring-boot-devtools 默認禁用緩存選項。
緩存選項通常由 application.properties
文件來進行配置的。例如,Thymeleaf 提供了 spring.thymeleaf.cache
屬性。無需手動配置這些屬性, spring-boot-devtools
模塊會提供開發時合理的配置
下表列出了應用的所有屬性:
Name | Default Value |
---|---|
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.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 |
::: tip 備注
如果您不希望應用默認配置,則可以在application.properties
中將 spring.devtools.add-properties
設置為 false
。
:::
在開發 Spring MVC 和 Spring WebFlux 應用程序時,您需要更多有關 Web 請求的信息,因此開發工具建議您為 web
logging group啟用 DEBUG
日志。這將為您提供有關傳入請求、處理程序、響應結果和其他詳細信息。如果希望記錄所有請求的詳細信息(包括潛在的敏感信息),您可以打開 spring.mvc.log-request-details
或 spring.codec.log-request-details
配置屬性.
6.8.3 自動重啟(Automatic Restart)
只要類路徑上的文件發生改變,使用 spring-boot-devtools
的應用程序就會自動重啟。在IDE中這是一個非常有用的功能,因為它為代碼修改提供了非常快速的反饋體驗。默認情況下,類路徑指向的目錄中所有文件都會受到控制,以防發生變化。請注意,對于某些資源(如靜態資源和視圖模板),不需要重新啟動應用程序。
::: tip 觸發重啟
由于 DevTools 監控類路徑上的資源,因此觸發重啟的唯一方式就是更新類路徑上的資源。無論你使用的是 IDE還是構build插件,修改后的文件都必須重新編譯才能觸發重啟,更新類路徑的方式取決于所使用的工具:
- 在Eclipse中,保存修改后的文件會更新類路徑資源并觸發重啟。
- 在IntelliJ IDEA中,構建項目(
Build +→+ Build Project
) 具體相同效果。 - 如果使用build插件,運行Maven插件的
mvn compile
命令或Gradle插件的gradle build
命令會觸發重啟。
:::
::: tip 備注
如果使用build插件Maven 或 Gradle進行重啟,則必須將 forking
設置為 enabled
。如果禁用 forking,因為devtools 需要一個獨立的應用程序類加載器可以使用,所以重啟功能將無法使用。
:::
::: tip 提示
自動重啟和LiveReload一起使用時效果非常好,詳情參閱 LiveReload 部分 。如果使用 JRebel,自動重啟功能將會被禁用,以支持動態類重新加載功能。其它devtools 功能(例如LiveReload 和屬性覆蓋)仍然可以使用。
:::
::: tip 備注
DevTools 依賴于應用程序上下文的shutdown hook 在重啟的時候關閉它。如果禁用了shutdown hook (SpringApplication.setRegisterShutdownHook(false)
),它將無法正常使用。
:::
::: tip 備注
DevTools 需要自定義ApplicationContext
所使用的的 ResourceLoader
。如果您的應用程序已經提供了一個,他將會被包裝。不支持直接覆蓋 ApplicationContext
上的 getResource
方法。
:::
::: tip 注意事項
使用 AspectJ weaving時不支持自動重啟。
:::
::: tip 重啟 vs 重載
Spring Boot 提供的重啟技術是通過使用兩個類加載器來實現的。不會更改的類(例如,來自第三方jar的類)會被加載到 base classloader。您正在開發的類將會被加載到 restart classloader 中,當應用程序重啟時,restart classloader 將會被丟棄,然后創建一個新的。這種方法意味著應用程序重啟的速度比 “cold starts” 要快的多,因為 base classloader 在重啟之前已經是可用且已加載。
如果你發現重啟對于你的應用程序來說不夠快,或者你遇到類加載問題,你可以考慮重載技術,比如 JRebel 。這些技術的原理是在加載類時對其進行重寫,使其更易于重載。
:::
記錄狀態評估中的變化(Logging Changes in Condition Evaluation)
默認情況下,每次重新啟動應用程序時,都會記錄一份狀態評估的報告。該報告會顯示應用程序自動配置的更改情況,如添加或刪除bean,和配置屬性
要禁用狀態評估記錄,請設置以下屬性:
spring:devtools:restart:log-condition-evaluation-delta: false
排除資源(Excluding Resources)
某些資源在更改時不一定需要觸發重啟。例如,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/**"
::: tip 提示
如果要保留這些默認值并添加其它排除項,請使用 spring.devtools.restart.additional-exclude
屬性代替。
:::
監控其它路徑(Watching Additional Paths)
當修改不在類路徑上的文件時,您可能希望應用程序重啟或重載。為此,可以使用 spring.devtools.restart.additional-paths
屬性配置其它路徑,以便監視修改。您可以使用 the spring.devtools.restart.exclude
屬性(如上所訴) 來控制其它路徑上的修改是否會觸發重啟和live reload.
禁用重啟(Disabling Restart)
如果不想使用重啟功能,您可以使用 spring.devtools.restart.enabled
屬性來禁用它。多數情況下,可以在 application.properties
文件配置該屬性(這樣做仍會初始化restart classloader,但不會監控文件的更改)。
如果您需要完全禁用重啟功能(例如,因為它無法和某些特定庫一起使用),則需要在調用 SpringApplication.run(…)
之前將 系統
屬性 spring.devtools.restart.enabled
設置為 false
,如下所示:
@SpringBootApplication
public class MyApplication {public static void main(String[] args) {System.setProperty("spring.devtools.restart.enabled", "false");SpringApplication.run(MyApplication.class, args);}}
使用觸發器文件(Using a Trigger File)
如果您使用的IDE會持續編譯已修改的文件,但是您更希望只在特定時間觸發重啟。為此,你可以使用“觸發器文件”,這是一個特殊文件,當需要實際觸發重啟時,必須對其進行修改。
::: tip 備注
修改文件只會觸發檢查,只有在Devtools 檢測到必須執行某些操作時,才會重啟。
:::
要使用觸發器文件,請將 spring.devtools.restart.trigger-file
屬性設置為觸發器文件的路徑。觸發器文件必須在類路徑上。
例如,如果您有一個結構如下的項目:
src
+- main+- resources+- .reloadtrigger
那么您的 trigger-file
屬性如下所示:
spring:devtools:restart:trigger-file: ".reloadtrigger"
現在,只有更新 src/main/resources/.reloadtrigger
時,才會重啟。
::: tip 提示
您可能希望將 spring.devtools.restart.trigger-file
設置成 全局設置,這樣所有項目的行為方式都是一樣的。
:::
有些 IDE 具有不需要手動修改觸發器文件的功能。 Spring Tools for Eclipse 和 IntelliJ IDEA (Ultimate Edition) 都支持這種功能,你可以在控制臺使用 “reload” 按鈕(只要您的 trigger-file
命名為 .reloadtrigger
)。對于 IntelliJ IDEA,您可以按照 文檔中的說明進行使用。
自定義重啟類加載器(Customizing the Restart Classloader)
正如 重啟 vs 重載 部分所訴,重啟功能是通過兩個類加載器來實現的。如果它導致了問題,你可以需要自定義類加載器需要加載哪些內容。
默認情況下,IDE中任何打開的項目都會使用 “restart” classloader,而 .jar
文件會使用“base” classloader。使用 mvn spring-boot:run
或 gradle bootRun
時也是如此:包含 @SpringBootApplication
的項目使用 “restart” classloader加載,而其它項目則使用 “base” classloader 加載。
你可以通過創建 META-INF/spring-devtools.properties
文件,來指定Spring Boot使用不同的類加載器加載項目的部分內容。spring-devtools.properties
文件可以包含以 restart.exclude
和 restart.include
為前綴的屬性。include
屬性配置的文件應該放到 “restart” classloader 中,而 exclude
屬性配置的文件應該放到 “base” classloader。該屬性值是一個 regex 格式,應用在類路徑上,如下所示:
restart:exclude:companycommonlibs: "/mycorp-common-[\\w\\d-\\.]+\\.jar"include:projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"
::: tip 備注
所有屬性key都必須是唯一的。只要是 restart.include.
或 restart.exclude.
為前綴的屬性都要被加載。
:::
::: tip 提示
所有類路徑中的 META-INF/spring-devtools.properties
都會被加載。你可以在項目中打包文件,也可以在項目使用的庫中打包文件。
:::
已知限制(Known Limitations)
對于使用標準 ObjectInputStream
進行反序列化的對象,重啟功能不起作用。如果您需要反序列化數據,可能需要將 Spring 的 ConfigurableObjectInputStream
和 Thread.currentThread().getContextClassLoader()
結合使用。
遺憾的是,一些第三方庫在進行反序列化時沒有考慮上下文類加載器。如果發現此類問題,需要向原作者申請修復。
6.8.4 LiveReload
spring-boot-devtools
模塊包含一個嵌入式 LiveReload 服務器,可以用于在資源發生變化是觸發瀏覽器刷新。LiveReload 瀏覽器擴展可以免費用于 Chrome, Firefox 和 Safari。您可以在所用瀏覽器的市場或商店中搜索 ‘LiveReload’ ,找到這些擴展。
如果不想在應用程序運行時啟動 LiveReload 服務器,可以將 spring.devtools.livereload.enabled
屬性設置為 false
。
::: tip 備注
一次只能運行一個 LiveReload 服務器。啟動應用程序前,請確保沒有其他 LiveReload 服務器在運行。如果從集成開發環境啟動多個應用程序,只有第一個支持 LiveReload。
:::
::: warning 警告
需要在更改文件時觸發 LiveReload,必須啟用 自動重啟 。
:::
6.8.5 全局配置(Global Settings)
在$HOME/.config/spring-boot
目錄中添加以下任何文件,即可配置全局devtools設置:
spring-boot-devtools.properties
spring-boot-devtools.yaml
spring-boot-devtools.yml
添加到這些文件中的任何屬性都適用于機器上使用 devtools 的所有 Spring Boot 應用程序。例如,要將重啟配置為使用 觸發器文件,你可以在 spring-boot-devtools
文件中添加以下屬性:
spring:devtools:restart:trigger-file: ".reloadtrigger"
默認情況下,$HOME
是用戶的主目錄。要自定義該位置,請設置環境變量 SPRING_DEVTOOLS_HOME
或系統屬性 spring.devtools.home
。
::: tip 備注
如果在 $HOME/.config/spring-boot
中找不到 devtools 配置文件,則會搜索 $HOME
目錄中是否存在 .spring-boot-devtools.properties
文件。這樣您就可以使用不支持$HOME/.config/spring-boot
位置的舊版 Spring Boot 應用程序共享 devtools 全局配置。
:::
::: tip 備注
devtools properties/yaml 文件不支持Profiles。.spring-boot-devtools.properties
中激活的任何profiles 都不會影響 特定 profile 的配置文件 的加載。YAML 和 Properties 類型文件的特定 Profile 文件名(例如 spring-boot-devtools-<profile>.properties
)和 spring.config.activate.on-profile
文件均不支持。
:::
配置文件系統監視器(Configuring File System Watcher)
FileSystemWatcher 的工作原理是以一定時間間隔輪詢觀察類的修改,然后等待預定義的靜默期,以確保不再有修改。由于 Spring Boot 完全依賴 IDE 來編譯文件并將其復制到 Spring Boot 可以讀取到的位置,因此您可能會發現當 devtools 重啟應用程序是,有時某些修改不會被反映出來。如果您經常遇見此類問題,請嘗試將 spring.devtools.restart.poll-interval
和 spring.devtools.restart.quiet-period
屬性參數設置為您需要的值:
spring:devtools:restart:poll-interval: "2s"quiet-period: "1s"
現在,每2秒鐘就會輪詢一次,觀察受監控的類路徑目錄是否有變化,并保持1秒鐘的靜默期,以確保沒有其他類變化。
6.8.6 遠程應用程序(Remote Applications)
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
屬性后自動啟用。客戶端組件必須手動啟動。
::: tip 備注
Spring WebFlux 應用程序不支持遠程 devtools。
:::
運行遠程客戶端程序(Running the Remote Client Application)
遠程客戶端程序可以在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 :: (v2.7.18-SNAPSHOT)2023-11-22 15:38:10.397 INFO 916 --- [ main] o.s.b.devtools.RemoteSpringApplication : Starting RemoteSpringApplication v2.7.18-SNAPSHOT using Java 1.8.0_392 on myhost with PID 916 (/Users/myuser/.m2/repository/org/springframework/boot/spring-boot-devtools/2.7.18-SNAPSHOT/spring-boot-devtools-2.7.18-SNAPSHOT.jar started by myuser in /opt/apps/)
2023-11-22 15:38:10.401 INFO 916 --- [ main] o.s.b.devtools.RemoteSpringApplication : No active profile set, falling back to 1 default profile: "default"
2023-11-22 15:38:10.702 INFO 916 --- [ main] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2023-11-22 15:38:10.724 INFO 916 --- [ main] o.s.b.devtools.RemoteSpringApplication : Started RemoteSpringApplication in 0.736 seconds (JVM running for 1.14)
::: tip 備注
因為遠程客戶端與真正的應用程序使用相同的類路徑,所有它可以直接讀取應用程序屬性。這就是讀取 spring.devtools.remote.secret
屬性并將其傳遞給服務器進行身份驗證的方式。
:::
::: tip 提示
始終建議使用 https://
作為連接協議,以便加密通信信息并且密碼無法被截獲。
:::
::: tip 提示
如果需要使用代理訪問遠程應用程序,請配置 spring.devtools.remote.proxy.host
和 spring.devtools.remote.proxy.port
屬性。
:::
遠程升級(Remote Update)
遠程客戶端會以與本地重啟相同的方式監控應用程序類路徑的變化。任何更新的資源都會被推送到遠程應用程序,并且(如果需要)會觸發重啟。如果您迭代的功能使用的是本地沒有的與服務,這將會非常有用。通常,遠程更新和重啟比完全重新構建和部署要快得多。
在速度較慢的開發環境中,可能會出現靜默期不夠的情況,這時類中的更改可能會被分批進行。第一批更改上傳后,服務器將重新啟動。由于服務器正在重啟,下一批更改無法發送到應用程序。
這種情況通常會在 "RemoteSpringApplication "日志中出現警告,提示無法上傳某些類,并隨之重試。但它也可能導致應用程序代碼不一致,以及在上傳第一批更改后無法重啟。如果經常出現此類問題,請嘗試將 spring.devtools.restart.poll-interval
和 spring.devtools.restart.quiet-period
屬性參數設置為您需要的值。請參閱 配置文件系統監視器 來配置這些屬性。
::: tip 備注
只有在遠程客戶端運行時,文件才會受到監控。如果在啟動遠程客戶端之前更改文件,則不會將其推送到遠程服務器。
:::
6.9 打包應用程序(Packaging Your Application for Production)
可執行 jar 可用于生產部署。由于它們是獨立的,因此也非常適合基于云的部署。
對于其它的 “production ready” 功能,例如運行狀況,審計和度量標準REST或JMX端點,請考慮添加 spring-boot-actuator
。 詳情參閱 Production-ready Features。
6.10 接下來要閱讀的內容(What to Read Next)
您現在應該了解如何使用Spring Boot和一些您應該遵循的最佳實踐。現在,您可以繼續深入了解特定的 Spring Boot 功能 ,也可以跳到前面閱讀Spring Boot的 “production ready” 部分。