您好,登錄后才能下訂單哦!
Spring Boot 自動配置的原理、核心注解以及如何利用自動配置實現自定義Starter組件,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
摘錄:讀書是讀完這些文字還要好好用心去想想,寫書也一樣,做任何事也一樣
圖 2 第二章目錄結構圖
Spring Boot 配置,包括自動配置和外化配置。本章先實現自定義屬性工程,將屬性外化配置在 application.properties 應用配置文件,然后在工程中獲取該屬性值。接著會詳細介紹屬性的獲取方式、外化配置和自動配置。最后會介紹利用自動配置自定義 Start 組件。
第一章的 HelloBookController
控制層中,在代碼中以硬編碼的方式使用字符串表示書信息。下面把書的信息作為屬性,外化配置在 application.properties 。好處是將應用參數、業務參數或第三方參數等統一配置在應用配置文件中,避免配置侵入業務代碼,達到可配置的方式,方便及時調整修改。
新建工程命名為 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
在工程中新建包目錄 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
非法參數異常。
修改原有的 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)
。
執行 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"); } }
配置屬性的常用獲取方式有基于 @Value
和 @ConfigurationProperties
注解兩種方式。兩種方式適合的場景不同,下面具體介紹其使用方法和場景。
@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 方法 }
在包目錄 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"); }
prefix 字符串值,綁定該名稱前綴的屬性對象。
value 字符串值,功能同 prefix 參數。
ignoreInvalidFields 布爾值,默認 false。綁定對象時,忽略無效字段。
ignoreUnknownFields 布爾值,默認 true。綁定對象時,忽略未知字段。
@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
Spring Boot 可以將配置外部化,即分離存儲在 classpath 之外,這種模式叫做 “外化配置”。常用在不同環境中,將配置從代碼中分離外置,只要簡單地修改下外化配置,可以依舊運行相同的應用代碼。外化配置表現形式不單單是 .properties 和 .yml 屬性文件,還可以使用環境變量和命令行參數等來實現。那么,多處配置了相同屬性時,Spring Boot 是通過什么方式來控制外化配置的沖突呢?答案是外化配置優先級。
用命令行配置去覆蓋 .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
指定)
在 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] 。一方面可以使相同配置可以復用,另一方面增強了配置的閱讀性。
在 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]}
多環境是指不同配置的生產服務器使用同一工程代碼部署,比如:開發環境、測試環境、預發環境、生產環境等。各個環境的工程端口、數據庫配置、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 環境書信息頁面
Spring Boot spring-boot-autoconfigure
依賴實現了默認的配置項,即應用默認值。這種模式叫做 “自動配置”。Spring Boot 自動配置會根據添加的依賴,自動加載依賴相關的配置屬性并啟動依賴。例如默認用的內嵌式容器是 Tomcat ,端口默認設置為 8080。
為什么需要自動配置?顧名思義,自動配置的意義是利用這種模式代替了配置 XML 繁瑣模式。以前使用 Spring MVC ,需要進行配置組件掃描、調度器、視圖解析器等,使用 Spring Boot 自動配置后,只需要添加 MVC 組件即可自動配置所需要的 Bean。所有自動配置的實現都在 spring-boot-autoconfigure
依賴中,包括 Spring MVC 、Data 和其它框架的自動配置。
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
自動配置工作機制是通過 @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 ,然后再進行自動配置。
當公司需要共享或者開源 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 是 API 最大的開發框架,基于 OpenAPI 規范(OAS),管理了 API 整個生命周期,即從 API 設計到文檔,從測試到部署。具體更多了解見其官網,https://swagger.io。
創建一個新的 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 框架。
新建名為 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
屬性值。
新建名為 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
,表示如果環境配置項沒被設置,也會觸發。
新建名為 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 組件的核心代碼實現,同樣使用方式也很簡單。在 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 文檔
exclude: Class 數組,排除特定的自動配置類。
excludeName: 字符串數組,排除特定名稱的自動配置類。
havingValue: 字符串,屬性期望值是否匹配。
matchIfMissing: 布爾值,如果該屬性值未設置,則匹配。
name: 字符串數組,要測試的屬性名。
prefix: 字符串,屬性前綴名。
value: 字符串,功能同 name。
name: 字符串數組,類名必須存在。
value: Class 數組,類必須存在。
annotation: 注解 Class 數組,匹配注解裝飾的 Bean。
ignored: Class 數組,匹配時,忽略該類型的 Bean。
ignoredType: 字符串數組,匹配時,忽略該類型名稱的 Bean。
name: 字符串數組,匹配要檢查的 Bean 名稱。
search: SearchStrategy 對象,通過 SearchStrategy 來決定程序的上下文策略。
type: 字符串史胡族,匹配要檢查的 Bean 類型名稱。
value: Class 數組,匹配要檢查的 Bean 類型。
type: ConditionalOnWebApplication.Type 對象,匹配對應的 Web 應用程序類型。
關于Spring Boot 自動配置的原理、核心注解以及如何利用自動配置實現自定義Starter組件問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。