本章內容
- 自定義屬性快速入門
- 外化配置
- 自動配置
- 自定義建立 Starter 元件
摘錄:讀書是讀完這些文字還要好好用心去想想,寫書也一樣,做任何事也一樣
圖 2 第二章目錄結構圖
第 2 章 Spring Boot 配置
Spring Boot 配置,包括自動配置和外化配置。本章先實現自定義屬性工程,將屬性外化配置在 application.properties 應用配置檔案,然後在工程中獲取該屬性值。接著會詳細介紹屬性的獲取方式、外化配置和自動配置。最後會介紹利用自動配置自定義 Start 元件。
2.1 快速入門工程
第一章的 HelloBookController
控制層中,在程式碼中以硬編碼的方式使用字串表示書資訊。下面把書的資訊作為屬性,外化配置在 application.properties 。好處是將應用引數、業務引數或第三方引數等統一配置在應用配置檔案中,避免配置侵入業務程式碼,達到可配置的方式,方便及時調整修改。
2.1.1 配置屬性
新建工程命名為 chapter-2-spring-boot-config ,在 application.properties 中配置書名和作者,配置如下:
## 書資訊
demo.book.name=[Spring Boot 2.x Core Action]
demo.book.writer=BYSocket
.properties 檔案的每行引數被儲存為一對字串,即一個儲存引數名稱,被稱為鍵;另一個為值。一般稱為鍵值對配置。井號(#)或者英文狀態下的歎號(!)作為第一行中第一個非空字元來表示該行的文字為註釋。另外,反斜槓(\)用於轉義字元。
Spring Boot 支援並推薦使用 YAML 格式的配置檔案,將 application.properties 檔案替換成 application.yml 檔案,並配置相同的屬性,配置如下:
## 書資訊
demo:
book:
name: 《Spring Boot 2.x 核心技術實戰 - 上 基礎篇》
writer: 泥瓦匠BYSocket
YAML 是一個可讀性高,用來表達資料序列的格式。表示鍵值對格式時,注意鍵和值由冒號及空白字元分開。強調下,空白字元是必須的,IDE 一般也會提示。兩種配置方式都非常便捷,在開發中選擇 .properties 或 .yml 檔案配置。但如果兩種配置檔案同時存在的時候,預設優先使用 .properties 配置檔案。YAML 與 .properties 配置檔案對比如圖 2-1 所示:
圖 2-1 YAML 與 .properties 配置檔案對比
注意:
在 application.properties 配置中文值,讀取時會出現中文亂碼問題。因為 Java .properties 檔案預設編碼方式是 iso-8859 ,Spring Boot 應用以 UTF-8 的編碼方式讀取,就導致出現亂碼問題。
官方 Issue 中的解決方法是,將 .properties 檔案中配置的中文值轉義成 Unicode 編碼形式。例如 demo.book.writer=泥瓦匠
應該配置成 demo.book.writer=\u6ce5\u74e6\u5320
。利用 IDEA properties 外掛 或利用 Java 檔案轉碼工具 native2ascii 來快速地進行轉義。該工具有線上版實現,地址如下:
https://javawind.net/tools/native2ascii.jsp
2.1.2 建立屬性類
在工程中新建包目錄 demo.springboot.config
,並在目錄中建立名為 BookProperties 的屬性類,程式碼如下:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* 書屬性
*/
@Component
public class BookProperties {
/**
* 書名
*/
@Value("${demo.book.name}")
private String name;
/**
* 作者
*/
@Value("${demo.book.writer}")
private String writer;
// ... 省略 getter / setter 方法
}
利用 @Component
註解定義了書的屬性 Bean,並通過 @Value
註解為該 Bean 的成員變數(或者方法引數)自動注入 application.properties 檔案的屬性值。@Value
註解是通過 “${propName}” 的形式引用屬性,propName 表示屬性名稱。
核心註解的知識點:
-
@Component 註解:
@Component
對類進行標註,職責是泛指元件 Bean ,應用啟動時會被容器載入並加入容器管理。常見的@Controller
、@Service
、@Repository
是@Component
的分類細化元件,分別對應控制層、服務層、持久層的 Bean。 -
@Value 註解:
@Value
對 Bean 的欄位或者方法引數進行標註,職責是基於表示式給欄位或方法引數設定預設屬性值。通常格式是註解 + SpEL 表示式,如@Value("SpEL 表示式")
。
使用 @Vlaue
註解來引用屬性值時,確保所引用的屬性值在 application.properties 檔案存在並且相對應匹配,否則會造成 Bean 的建立錯誤,引發 java.lang.IllegalArgumentException
非法引數異常。
2.1.3 獲取屬性
修改原有的 HelloBookController
類,通過注入的方式獲取書屬性 Bean 並返回。程式碼如下:
import demo.springboot.config.BookProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloBookController {
@Autowired
BookProperties bookProperties;
@GetMapping("/book/hello")
public String sayHello() {
return "Hello, " + bookProperties.getWriter() + " is writing "
+ bookProperties.getName() + " !";
}
}
通過 @Autowired
註解標記在 BookProperties
欄位,控制層自動裝配屬性 Bean 並使用。預設情況下要求被註解的 Bean 必須存在,需要允許 NULL 值,可以設定其 required 屬性為 false: @Autowired(required = false)
。
2.1.4 執行工程
執行 ConfigApplication
類啟動,在控制檯看到成功執行的輸出後,開啟瀏覽器訪問 /book/hello 地址,可以看到如圖 2-2 所示的返回結果:
圖 2-2 Hello Book 頁面
也可以通過單元測試的方式驗證屬性獲取是否成功,單元測試具體相關的會在第 9 章節介紹。單元測試程式碼如下:
import demo.springboot.config.BookProperties;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ConfigApplicationTests {
@Autowired
BookProperties bookProperties;
@Test
public void testBookProperties() {
Assert.assertEquals(bookProperties.getName(),"'Spring Boot 2.x Core Action'");
Assert.assertEquals(bookProperties.getWriter(),"BYSocket");
}
}
2.2 配置屬性的獲取方式
配置屬性的常用獲取方式有基於 @Value
和 @ConfigurationProperties
註解兩種方式。兩種方式適合的場景不同,下面具體介紹其使用方法和場景。
2.2.1 @Value 註解
@Value
註解對 Bean 的變數或者方法引數進行標註,職責是基於表示式給欄位或方法引數設定預設屬性值。通常格式是註解 + SpEL 表示式,如 @Value("SpEL 表示式")
,並標註在對應的欄位或者方法上方,且必須對變數一一標註。這種方式適用於小而不復雜的屬性結構。屬性結構複雜,欄位很多的情況下,這種方式會比較繁瑣,應該考慮使用 @ConfigurationProperties
註解。
另外通過 @PropertySource
註解引入對應路徑的其他 .properties 檔案。將書資訊重新配置在 classpath 下新的 book.properties 配置檔案後,讀取新配置檔案的程式碼如下:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* 書屬性
*/
@Component
@PropertySource("classpath:book.properties")
public class BookProperties {
/**
* 書名
*/
@Value("${demo.book.name}")
private String name;
/**
* 作者
*/
@Value("${demo.book.writer}")
private String writer;
// ... 省略 getters / setters 方法
}
2.2.2 @ConfigurationProperties 註解
在包目錄 demo.springboot.config
中建立名為 BookComponent 的屬性類,並使用 @ConfigurationProperties
註解獲取屬性,程式碼如下:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 書屬性
*
*/
@Component
@ConfigurationProperties(prefix = "demo.book")
public class BookComponent {
/**
* 書名
*/
private String name;
/**
* 作者
*/
private String writer;
// ... 省略 getters / setters 方法
}
類似 @Value
註解方式,使用 @ConfigurationProperties(prefix = "demo.book")
註解標註在類上方可以達到相同的效果。 @ConfigurationProperties
註解的 prefix 是指定屬性的引數名稱。會匹配到配置檔案中 “ demo.book.* ” 結構的屬性,星號 “ * ” 是指會一一對應匹配 BookComponent
類的欄位名。例如,欄位 name 表示書名,會匹配到 demo.book.name
屬性值。
@Value
註解方式強制欄位必須對應在配置檔案, @ConfigurationProperties
註解方式則不是必須的。一般情況下,所有欄位應該保證一一對應在配置檔案。如果沒有屬性值對應的話,該欄位預設為空, @ConfigurationProperties
註解方式也不會引發任何異常,Spring Boot 推薦使用 @ConfigurationProperties
註解方式獲取屬性。
同樣使用單元測試驗證獲取屬性是否成功。單元測試程式碼如下:
@Autowired
BookComponent bookComponent;
@Test
public void testBookComponent() {
Assert.assertEquals(bookComponent.getName(),"'Spring Boot 2.x Core Action'");
Assert.assertEquals(bookComponent.getWriter(),"BYSocket");
}
API org.springframework.boot.context.properties.ConfigurationProperties 註解引數
- prefix
字串值,繫結該名稱字首的屬性物件。 - value
字串值,功能同 prefix 引數。 - ignoreInvalidFields
布林值,預設 false。繫結物件時,忽略無效欄位。 - ignoreUnknownFields
布林值,預設 true。繫結物件時,忽略未知欄位。
2.2.3 @ConfigurationProperties 資料驗證
@ConfigurationProperties
註解方式支援驗證功能,即當屬性類被 @Validated
註解標註時,Spring Boot 初始化時會驗證類的欄位。在類的欄位上新增 JSR-303 約束註解,進行資料驗證。下面為書屬性欄位新增非 NULL 和字串非空約束,程式碼如下:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 書屬性
*
*/
@Component
@ConfigurationProperties(prefix = "demo.book")
@Validated
public class BookComponent {
/**
* 書名
*/
@NotEmpty
private String name;
/**
* 作者
*/
@NotNull
private String writer;
// ... 省略 getters / setters 方法
}
通過 @Validated
註解開啟對 BookComponent
類欄位的資料驗證,如果 name 欄位為 NULL 或者為空字串時,會引發 BindValidationException
繫結資料驗證異常。資料驗證常用在郵箱格式或者有長度限制的屬性欄位。另外,驗證巢狀屬性的值,必須在巢狀物件欄位上方標註 @Valid
註解,用來觸發其驗證。例如,在書屬性中新增巢狀物件出版社 Publishing
,就需要在該物件上方標註 @Valid
註解,來開啟對 Publishing
物件的資料驗證。綜上,兩種屬性獲取方式各有優缺點,對比如圖 2-3 所示:
圖 2-3 @ConfigurationPropertiesd vs @Value
2.3 外化配置
Spring Boot 可以將配置外部化,即分離儲存在 classpath 之外,這種模式叫做 “外化配置”。常用在不同環境中,將配置從程式碼中分離外接,只要簡單地修改下外化配置,可以依舊執行相同的應用程式碼。外化配置表現形式不單單是 .properties 和 .yml 屬性檔案,還可以使用環境變數和命令列引數等來實現。那麼,多處配置了相同屬性時,Spring Boot 是通過什麼方式來控制外化配置的衝突呢?答案是外化配置優先順序。
2.3.1 外化配置優先順序
用命令列配置去覆蓋 .properties 檔案配置方法很簡單。正常情況下利用 Java 命令執行工程,程式碼如下:
// chapter-2-spring-boot-config 目錄下執行
java -jar target/chapter-2-spring-boot-config-1.0.jar
下面將書的作者資訊 BYSocket 改成 Jeff , 通過命令列配置覆蓋屬性,程式碼如下:
java -jar target/chapter-2-spring-boot-config-1.0.jar --demo.book.writer=Jeff
在命令列配置中,設定屬性值的格式是用兩個連續的減號 “--”標誌屬性。在控制檯看到成功執行的輸出後,開啟瀏覽器,訪問 /book/hello 地址,可以看到如圖 2-4 所示的返回結果:
圖 2-4 書資訊被覆蓋頁面
通過命令列配置覆蓋屬性提供了非常大的作用與便利性,常見於使用 shell 指令碼執行工程時,可以方便地修改工程執行的配置。
但是這就引發了一個問題,豈不讓工程很有侵入性,如果開放這個功能,導致未知的安全問題。所以 Spring Boot 提供了遮蔽命令列屬性值設定,在應用啟動類中設定 setAddCommandLineProperties
方法為 false
,用於關閉命令列配置功能,程式碼如下:
SpringApplication.setAddCommandLineProperties(false);
命令列配置屬性的優先順序是第四。外化配置獲取屬性時,會按優先順序從高到低獲取。如果高優先順序存在屬性,則返回屬性,並忽略優先順序低的屬性。優先順序如下:
- 本地 Devtools 全域性配置
- 測試時
@TestPropertySource
註解配置 - 測試時
@SpringBootTest
註解的 properties 配置 - 命令列配置
- SPRING_APPLICATION_JSON 配置
ServletConfig
初始化引數配置ServletContext
初始化引數配置- Java 環境的 JNDI 引數配置
- Java 系統的屬性配置
- OS 環境變數配置
- 只能隨機屬性的
RandomValuePropertySource
配置 - 工程 jar 之外的多環境配置檔案(application- {profile}.properties 或 YAML)
- 工程 jar 之內的多環境配置檔案(application- {profile}.properties 或 YAML)
- 工程 jar 之外的應用配置檔案(application.properties 或 YAML)
- 工程 jar 之內的應用配置檔案(application.properties 或 YAML)
@Configuration
類中的 @PropertySource 註解配置- 預設屬性配置(
SpringApplication.setDefaultProperties
指定)
2.3.2 屬性引用
在 application.properties 中配置屬性時,屬性之間可以直接通過 “${propName}” 的形式引用其他屬性。比如新增書的描述 description 屬性,程式碼如下:
## 書資訊
demo.book.name=[Spring Boot 2.x Core Action]
demo.book.writer=BYSocket
demo.book.description=${demo.book.writer}'s${demo.book.name}
demo.book.description 屬性引用了前面定義的 demo.book.name 和 demo.book.writer 屬性,其值為 BYSocket's[Spring Boot 2.x Core Action] 。一方面可以使相同配置可以複用,另一方面增強了配置的閱讀性。
2.3.3 使用隨機數
在 application.properties 中配置屬性時,可以使用隨機數配置,例如注入某些金鑰、UUID 或者測試用例,需要每次不是一個固定的值。RandomValuePropertySource
類隨機提供整形、長整形數、UUID 或者字串。使用程式碼如下:
my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}
2.3.4 多環境配置
多環境是指不同配置的生產伺服器使用同一工程程式碼部署,比如:開發環境、測試環境、預發環境、生產環境等。各個環境的工程埠、資料庫配置、Redis 配置、日誌配置等都會不同,傳統模式下需要修改配置,工程重新編譯打包,並部署到指定環境伺服器。結果是容易發生配置錯誤,導致開發部署效率低下。Spring Boot 使用多環境配置去解決這個問題。
多環境配置,類似 Maven 構建配置檔案的思路,即配置多個不同環境的配置檔案,再通過 spring.profiles.active
命令去指定讀取特定配置檔案的屬性。多環境配置檔案是不同於 application.properties 應用配置檔案。多環境配置檔案的約定命名格式為 application-{profile}.properties。多環境配置功能預設為啟用狀態,如果其他配置未被啟用,則 {profile} 預設為 default,會載入 application-default.properties 預設配置檔案,沒有該檔案就會載入 application.properties 應用配置檔案。
多環境配置檔案的屬性讀取方式和從 application.properties 應用配置檔案讀取方式一致。不管多環境配置檔案在工程 jar 包內還是包外,按照配置優先順序覆蓋其他配置檔案。在微服務實踐開發中,經常會使用一個類似 deploy 工程去管理配置檔案和打包其他業務工程。
在 application.properties 同級目錄中,新建 application-dev.properties 作為開發環境配置檔案,配置如下:
## 書資訊
demo.book.name=[Spring Boot 2.x Core Action] From Dev
demo.book.writer=BYSocket
新建 application-prod.properties 作為生產環境配置檔案,程式碼如下:
## 書資訊
demo.book.name=<Spring Boot 2.x Core Action Dev> From Prod
demo.book.writer=BYSocket
通過命令列指定讀取 dev 環境配置檔案並執行工程,程式碼如下:
java -jar target/chapter-2-spring-boot-config-1.0.jar --spring.profiles.active=dev
在多個環境配置中,通過命令 --spring.profiles.active=dev
指定讀取某個配置檔案,將 dev 更改成 prod ,輕鬆切換讀取生產環境配置。也可以在控制檯的日誌中確定配置讀取來自 dev :
2017-11-09 12:10:52.978 INFO 72450 --- [ main] demo.springboot.ConfigApplication : The following profiles are active: dev
最後開啟瀏覽器,訪問 /book/hello 地址,可以看到如圖 2-5 所示的返回結果:
圖 2-5 dev 環境書資訊頁面
2.4 自動配置
Spring Boot spring-boot-autoconfigure
依賴實現了預設的配置項,即應用預設值。這種模式叫做 “自動配置”。Spring Boot 自動配置會根據新增的依賴,自動載入依賴相關的配置屬性並啟動依賴。例如預設用的內嵌式容器是 Tomcat ,埠預設設定為 8080。
為什麼需要自動配置?顧名思義,自動配置的意義是利用這種模式代替了配置 XML 繁瑣模式。以前使用 Spring MVC ,需要進行配置元件掃描、排程器、檢視解析器等,使用 Spring Boot 自動配置後,只需要新增 MVC 元件即可自動配置所需要的 Bean。所有自動配置的實現都在 spring-boot-autoconfigure
依賴中,包括 Spring MVC 、Data 和其它框架的自動配置。
2.4.1 spring-boot-autoconfigure 依賴
spring-boot-autoconfigure
依賴,是 Spring Boot 實現自動配置的核心 Starter 元件。其實現原始碼包結構如圖 2-6 所示:
圖 2-6 spring-boot-autoconfigure 依賴包目錄
從圖中可以看出,其中常見核心的包如下:
org.springframework.boot.autoconfigure
org.springframework.boot.autoconfigure.data.jpa
org.springframework.boot.autoconfigure.thymeleaf
org.springframework.boot.autoconfigure.web.servlet
org.springframework.boot.autoconfigure.web.reactive
... 省略
在各自包目錄下有對應的自動配置類,程式碼如下:
JpaRepositoriesAutoConfiguration
ThymeleafAutoConfiguration
WebMvcAutoConfiguration
WebFluxAutoConfiguration
... 省略
上面自動配置類依次是 Jpa 自動配置類、Thymeleaf 自動配置類、Web MVC 自動配置類和 WebFlux 自動配置類。WebFlux 響應式框架會在第 3 章 詳細介紹使用。
spring-boot-autoconfigure
職責是通過 @EnableAutoConfiguration
核心註解,掃描 ClassPath 目錄中自動配置類對應依賴,並按一定規則獲取預設配置並自動初始化所需要的 Bean。在 application.properties 配置檔案也可以修改預設配置項,常用配置清單地址如下:
https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
2.4.2 @EnableAutoConfiguration 註解
自動配置工作機制是通過 @EnableAutoConfiguration
註解中 @Import
的 AutoConfigurationImportSelector
自動配置匯入選擇器類實現的。查閱原始碼可得具體流程如下:
AutoConfigurationImportSelector
通過SpringFactoriesLoader.loadFactoryNames()
核心方法讀取 ClassPath 目錄下面的 META-INF/spring.factories 檔案。- spring.factories 檔案中配置的 Spring Boot 自動配置類,例如常見的
WebMvcAutoConfiguration
Web MVC 自動配置類和ServletWebServerFactoryAutoConfiguration
容器自動配置類 。 - spring.factories 檔案和 application.properties 檔案都屬於配置檔案,配置的格式均為鍵值對。裡面配置的每個自動配置類都會定義相關 Bean 的例項配置,也會定義什麼條件下自動配置和哪些 Bean 被例項化。
- 當 pom.xml 新增某 Starter 依賴元件的時候,就會自動觸發該依賴的預設配置。
例如新增 spring-boot-starter-web
依賴後,啟動應用會觸發容器自動配置類。容器自動配置類 ServletWebServerFactoryAutoConfiguration
的部分程式碼如下:
package org.springframework.boot.autoconfigure.web.servlet;
@Configuration
@ConditionalOnClass({ServletRequest.class})
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@EnableConfigurationProperties({ServerProperties.class})
@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class})
public class ServletWebServerFactoryAutoConfiguration {
... 省略
}
上面程式碼中,@ConditionalOnClass
註解表示對應的 ServletRequest
類在 ClassPath 目錄下面存在,並且 @ConditionalOnWebApplication
註解表示該應用是 Servlet Web 應用時,才會去啟動容器自動配置,並通過 ServerProperties 類預設設定了埠為 8080。Type.SERVLET 列舉代表 Servlet Web 應用,Type.REACTIVE 列舉代表響應式 WebFlux 應用。
自動配置,是一把雙刃劍。用好了就像天下武功唯快不破一樣。但要注意一些自動化配置造成的問題。常見的問題有:
- Spring Boot 工程新增某些 Starter 元件依賴,又不需要觸發元件自動配置
- Spring Boot 配置多個不同資料來源配置時,使用 XML 配置多資料來源,但其預設資料來源配置會觸發自動配置出現問題。
類似場景下,解決方式是通過 exclude 屬性指定並排除自動配置類,程式碼如下:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
也等價於配置 @EnableAutoConfiguration
註解,程式碼如下:
@SpringBootApplication
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
自動配置會最大的智慧化,只有配置了 exclude 屬性時,Spring Boot 優先初始化使用者定義的 Bean ,然後再進行自動配置。
2.4.3 利用自動配置自定義 Starter 元件
當公司需要共享或者開源 Spring Boot Starter 元件依賴包,就可以利用自動配置自定義 Starter 元件。一個完整的 Starter 元件包括以下兩點:
- 提供自動配置功能的自動配置模組。
- 提供依賴關係管理功能的元件模組,即封裝了元件所有功能,開箱即用。
實現自定義 Starter 元件,並不會將這兩點嚴格區分,可以將自動配置功能和依賴管理結合在一起實現。下面利用自動配置實現自定義 Starter 元件:spring-boot-starter-swagger 元件是用來快速生成 API 文件,簡化原生使用 Swagger2 。
spring-boot-starter-swagger 元件為 Spring For All 社群(spring4all.com)開源專案,原始碼地址是 https://github.com/SpringForAll/spring-boot-starter-swagger。
什麼是 Swagger2
Swagger2 是 API 最大的開發框架,基於 OpenAPI 規範(OAS),管理了 API 整個生命週期,即從 API 設計到文件,從測試到部署。具體更多瞭解見其官網,https://swagger.io。
spring-boot-starter-swagger 元件依賴
建立一個新的 Spring Boot 工程,命名為 spring-boot-starter-swagger。在 pom.xml 配置相關
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${version.swagger}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${version.swagger}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-bean-validators</artifactId>
<version>${version.swagger}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
配置中新增了 spring-boot-starter
元件依賴用於自動配置特性,springfox-swagger2
依賴是 Swagger2 框架。
Swagger2 屬性配置類 SwaggerProperties
新建名為 SwaggerProperties
Swagger2 屬性配置類,包含了所有預設屬性值。使用該元件時,可以在 application.properties 配置檔案配置對應屬性項,進行覆蓋預設配置。程式碼如下:
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import springfox.documentation.schema.ModelRef;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Data
@ConfigurationProperties("swagger")
public class SwaggerProperties {
/**是否開啟swagger**/
private Boolean enabled;
/**標題**/
private String title = "";
/**描述**/
private String description = "";
/**版本**/
private String version = "";
/**許可證**/
private String license = "";
/**許可證URL**/
private String licenseUrl = "";
/**服務條款URL**/
private String termsOfServiceUrl = "";
private Contact contact = new Contact();
/**swagger會解析的包路徑**/
private String basePackage = "";
/**swagger會解析的url規則**/
private List<String> basePath = new ArrayList<>();
/**在basePath基礎上需要排除的url規則**/
private List<String> excludePath = new ArrayList<>();
/**分組文件**/
private Map<String, DocketInfo> docket = new LinkedHashMap<>();
/**host資訊**/
private String host = "";
/**全域性引數配置**/
private List<GlobalOperationParameter> globalOperationParameters;
... 省略,具體程式碼見 GitHub
}
用 @ConfigurationProperties(prefix = "swagger")
標註在類上方是指定屬性的引數名稱為 swagger。會對應匹配到配置檔案中 “ swagger.* ” 結構的屬性,例如,欄位標題 title 表示標題,會匹配到 swagger.title
屬性值。
Swagger2 自動配置類 SwaggerAutoConfiguration
新建名為 SwaggerAutoConfiguration
Swagger2 自動配置類,提供 Swagger2 依賴關係管理功能和自動配置功能。程式碼如下:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@Configuration
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
@Import({
Swagger2DocumentationConfiguration.class,
BeanValidatorPluginsConfiguration.class
})
public class SwaggerAutoConfiguration implements BeanFactoryAware {
private BeanFactory beanFactory;
@Bean
@ConditionalOnMissingBean
public SwaggerProperties swaggerProperties() {
return new SwaggerProperties();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
... 省略,具體程式碼見 GitHub
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
上面程式碼實現流程如下:
@Configuration
註解標註在類上方,表明該類為配置類。@Import
註解引入 Swagger2 提供的配置類Swagger2DocumentationConfiguration
和 Bean 資料驗證外掛配置類BeanValidatorPluginsConfiguration
。@ConditionalOnMissingBean
註解標註了兩處方法,當 Bean 沒有被建立時會執行被標註的初始化方法。第一處被標記方法是swaggerProperties()
,用來例項化屬性配置類SwaggerProperties
;第二處被標記方法是createRestApi()
, 用來例項化 Swagger2 API 對映的 Docket 列表物件。@ConditionalOnProperty
註解標註在createRestApi()
方法,name 屬性會去檢查環境配置項swagger.enabled
。預設情況下,屬性存在且不是false
的情況下,會觸發該初始化方法。matchIfMissing 屬性預設值為false
,這裡設定為true
,表示如果環境配置項沒被設定,也會觸發。
Swagger2 啟動註解類 EnableSwagger2Doc
新建名為 EnableSwagger2Doc
Swagger2 啟動註解類,用於開關 spring-boot-starter-swagger 元件依賴。程式碼如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({SwaggerAutoConfiguration.class})
public @interface EnableSwagger2Doc {
}
上面程式碼 @Import
註解引入 Swagger2 自動配置類 SwaggerAutoConfiguration
。當將該註解配置在應用啟動類上方,即可開啟 Swagger2 自動配置及其功能。
使用 spring-boot-starter-swagger 元件依賴
上面簡單介紹了spring-boot-starter-swagger 元件的核心程式碼實現,同樣使用方式也很簡單。在 chapter-2-spring-boot-config 工程的 Maven 配置中新增對應的依賴配置,目前支援 1.5.0.RELEASE 以上版本,配置如下:
<!-- 自定義 swagger2 Starter 元件依賴 -->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>spring-boot-starter-swagger</artifactId>
<version>2.0</version>
</dependency>
另外,需要在 ConfigApplication 應用啟動類上方配置啟動註解類 EnableSwagger2Doc
,程式碼如下:
import com.spring4all.swagger.EnableSwagger2Doc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableSwagger2Doc // 開啟 Swagger
@SpringBootApplication
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
}
執行 ConfigApplication
類啟動,在控制檯看到成功執行的輸出後,開啟瀏覽器訪問 localhost:8080/swagger-ui.html 地址,可以看到自動生成的 Swagger API 文件,如圖 2-7 所示:
圖 2-7 Swagger API 文件
API org.springframework.boot.autoconfigure.EnableAutoConfiguration 註解引數
- exclude:
Class 陣列,排除特定的自動配置類。 - excludeName:
字串陣列,排除特定名稱的自動配置類。
API org.springframework.boot.autoconfigure.ConditionalOnProperty 註解引數
- havingValue:
字串,屬性期望值是否匹配。 - matchIfMissing:
布林值,如果該屬性值未設定,則匹配。 - name:
字串陣列,要測試的屬性名。 - prefix:
字串,屬性字首名。 - value:
字串,功能同 name。
API org.springframework.boot.autoconfigure.ConditionalOnClass 註解引數
- name:
字串陣列,類名必須存在。 - value:
Class 陣列,類必須存在。
API org.springframework.boot.autoconfigure.ConditionalOnMissingBean 註解引數
- annotation:
註解 Class 陣列,匹配註解裝飾的 Bean。 - ignored:
Class 陣列,匹配時,忽略該型別的 Bean。 - ignoredType:
字串陣列,匹配時,忽略該型別名稱的 Bean。 - name:
字串陣列,匹配要檢查的 Bean 名稱。 - search:
SearchStrategy 物件,通過 SearchStrategy 來決定程式的上下文策略。 - type:
字串史胡族,匹配要檢查的 Bean 型別名稱。 - value:
Class 陣列,匹配要檢查的 Bean 型別。
API org.springframework.boot.autoconfigure.ConditionalOnWebApplication 註解引數
- type:
ConditionalOnWebApplication.Type 物件,匹配對應的 Web 應用程式型別。
2.5 本章小結
本章從自定義屬性快速入門工程出發,介紹了兩種配置檔案以及屬性的獲取方式,然後講解了外化配置的優先順序、屬性引用、隨機式使用和多環境配置,最後講解了自動配置的原理、核心註解以及利用自動配置實現了自定義 Starter 元件。下一章介紹 Spring Boot Web 開發相關。
本文由部落格群發一文多發等運營工具平臺 OpenWrite 釋出