Spring-Boot-Starter 1. 準備配置類和 Bean 對象 Spring Boot 提供了兩個註解: @Configuration:Spring 提供的配置類註解,作用在類上,代表整個類是個 Spring 配置類,對照傳統的 Spring XML 配置文件。 @Bean:作用於方法上 ...
Spring-Boot-Starter
1. 準備配置類和 Bean 對象
Spring Boot 提供了兩個註解:
@Configuration
:Spring 提供的配置類註解,作用在類上,代表整個類是個 Spring 配置類,對照傳統的 Spring XML 配置文件。@Bean
:作用於方法上,代表此方法的返回值(對象)將會被 Spring 容器所管理,從而完成 Bean 的自動註冊。
這兩個組合起來搭配可以完美的代替傳統的 Spring XML 配置文件,並給 Spring Boot 的自動配置提供基本數據體。
2. 自動配置條件依賴
有些情況下自動配置類並不是在任何條件下都能生效的,此時我們需要制定自動配置生效的條件,可以使用 Spring Boot 提供的註解來指定生效條件。
這些註解是 spring boot 特有的,常見的條件依賴註解有:
註解 | 功能說明 |
---|---|
@ConditionalOnBean | 僅在當前上下文中存在某個 bean 時,才會實例化這個 Bean |
@ConditionalOnClass | 某個 class 位於類路徑上,才會實例化這個 Bean |
@ConditionalOnExpression | 當表達式為 true 的時候,才會實例化這個 Bean |
@ConditionalOnMissingBean | 僅在當前上下文中不存在某個 bean 時,才會實例化這個 Bean |
@ConditionalOnMissingClass | 某個 class 在類路徑上不存在的時候,才會實例化這個 Bean |
@ConditionalOnNotWebApplication | 不是 web 應用時才會實例化這個 Bean |
@AutoConfigureAfter | 在某個 Bean 完成自動配置後實例化這個 Bean |
@AutoConfigureBefore | 在某個 Bean 完成自動配置前實例化這個 Bean |
3. Bean 的參數獲取
舉個例子,例如在 Spring Boot Web 項目中,我們經常會導入 MyBatis 相關的依賴,幫助我們與資料庫打交道,那麼在傳統的 Spring 項目中,我們一般會在 Spring 容器配置 XML 文件中去使用 <bean>
標簽生成相關數據源(DataSource),那麼這個 DataSource 需要我們提供資料庫連接參數:driver、url、username、password
這四個最基本的參數,這些數據可能放在一個叫做 db.properties
文件中,這種文件我們稱為外部數據源文件,在 Spring 配置文件中聲明:<context:property-placeholder location="classpath:db.properties"/>
這樣就可以引入文件中的配置參數了,從而賦值給 DataSource
這個 Bean 所需要的屬性參數。最後完成對象初始化。
這個過程在傳統 Spring 開發,無疑是略顯繁瑣,如果在某些我們需要自定義類和大量參數屬性從外部文件引入,這個時候 properties 文件格式也比較複雜,文件可能較多,在初始化 Bean 時,需要手寫大量的屬性賦值。
那麼 Spring Boot 提供了註解幫助我們減小開發量,更加規範 Bean 參數的獲取方式。
預設情況下我們 Bean 的參數配置在 application.yml
文件中,使用 YAML
文件格式定義,比 properties
文件更有層級感,更簡約。
搭配 @EnableConfigurationProperties、@ConfigurationProperties
這兩個註解可以直接實現自動配置類的 Bean 參數獲取。
3.1 @EnableConfigurationProperties 註解
這個註解使用情況:自動配置類中需要從外部文件獲取參數,來進行初始化。
在註解中指定一個類,這個時候可以配置類可以在這個類中獲取到外部文件的參數,交給配置類中的 Bean 進行初始化。
3.2 @ConfigurationProperties 註解
註解使用情況:從外部文件獲取參數信息,載入到自身類屬性中,給 Spring 配置類提供外部數據來源,外部數據文件通常指的是 application.yml
。
在註解中指定從 application.yml
文件獲取的首碼,例如 @ConfigurationProperties(prefix="spring.datasource")
,會獲取以這個字元串為首碼的所有參數進行自動匹配賦值。
所以可以看出兩個註解的關係是:
@EnableConfigurationProperties
註解作用在配置類中,並且使得該註解指定的數據文件類中的 @ConfigurationProperties
註解生效。
4. Bean 的發現
4.1 自己項目的 Bean 掃描
在寫 Spring Boot 項目時,一般在項目的代碼的根目錄會有一個 Spring Boot 啟動類:xxxApplication.java
,這個類被 @SpringBootApplication
註解修飾標記成 Spring Boot 項目的啟動類。
@SpringBootApplication
public class SpringbootStarterApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootStarterApplication.class, args);
}
}
此時再來看看如何完成 Bean 掃描,我們需要查看 @SpringBootApplication
註解源碼:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
//...
}
我們重點查看 @SpringBootConfiguration
註解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
可以看到這個註解被熟悉的 @Configuration
註解修飾。@SpringBootConfiguration
應用標註在某個類上說明這個類是SpringBoot 的主配置類,SpringBoot 需要運行這個類的 main 方法來啟動 SpringBoot 應用。
底層 Spring Boot 會幫我們將啟動類的當前路徑包以及子包的所有 Spring 組件(可能需要 @ComponentScan註解去做組件掃描
)以及 Bean 掃描初始化。暫時只說淺層的流程,後續會深入 Spring 源碼學習。
4.2 jar 包的 Bean 掃描
那麼前面聊了自己項目的 Bean 掃描,且 Spring Boot 預設掃描啟動類所在包下的主類與子類的所有組件,其中並沒有包括項目依賴包中的類,那麼這些類是如何被 Spring Boot 發現的呢?
這就是第二個主要註解:@EnableAutoConfiguration
,開啟自動配置:
這裡引入其他博客的理解,覺得這幾句話簡單易懂:
一、
@EnableAutoConfiguration
的作用
簡單點說就是 Spring Boot 根據依賴中的 jar 包,自動選擇實例化某些配置,配置類必須有@Configuration
註解。說白了,還是實例化對象,只是實例化的是依賴包中的類。
另外,我們也可以按照自動裝配的規範自己定義裝配的類。
接下來查看一下註解源碼:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
//...
}
主要看 @Import({AutoConfigurationImportSelector.class})
,這個註解導入了 AutoConfigurationImportSelector.class
這個類(如果是其他版本,可能會是 @EnableAutoConfigurationImportSelector
這個是子類)。
我們找到 getCandidateConfigurations()
方法,這個方法就是用來載入依賴所需要的自動配置相關。
看到 SpringFactoriesLoader.loadFactoryNames()
的源碼:
其他版本可能是只有 loadFactoryNames()
方法,但是我們主要關註 classLoader.getResources()
方法中的常量:
很明顯這個方法是用來載入資源文件,而這個 Spring 工廠資源的路徑就是依賴中自動配置的相關路徑,根據這個路徑找到需要自動配置的類,最後完成依賴的自動配置。我們導入 mybatis-spring-boot-starter
依賴看看這個 META-INF/spring.factories
裡邊是怎麼樣的:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
簡單概括的流程:Spring Boot 會根據 jar 包的 META-INF/spring.factories
文件的配置進行自動裝配,裝配的流程是 SpringFactoriesLoader.loadFactoryNames()
方法頂層實現的(底層實現需深入源碼),而開始外部自動裝配的註解是:@SpringBootApplication
註解中的 @Import({AutoConfigurationImportSelector.class})
主導整個過程。
5. Bean 的載入
在 Spring Boot 中將一個普通類交給 Spring 容器管理,通常有以下幾個方法:
- 使用
@Configuration
配合@Bean
註解使用(配置類)。 - 使用
@Controller、@Service、@Repository、@Component
註解標註類並且使用@ComponentScan
自動掃描(組件掃描)。 - 使用
@Import
方法(載入外部依賴的類)。
在上面可以看到 Spring Boot 實現自動配置使用的是 @Import
註解這種方式。AutoConfigurationImportSelector
類的 selectImports()
方法(其中調用了 getAutoConfigurationEntry()
方法主要過程)返回一組從 META-INF/spring.factories
文件中讀取的 Bean 的全限定名,這樣 Spring Boot 就可以載入到這些 Bean 並完成實例的初始化工作。
自動配置總結
經過前面的分析,將自動配置的關鍵步驟以及對應註解抽取出來:
- 定義需要自動裝配的類信息:
@Configuration、@Bean
,Spring Boot 配置類。 - 設置自動配置條件依賴:
@Conditional
。 - 將外部配置文件讀取並封裝成 Bean,讓配置類讀取參數:
@EnableConfigurationProperties、@ConfigurationProperties
。 - 實現 Bean 的發現與載入:
@EnableAutoConfiguration、@Import
。
以上的內容是基於其他相關博客內容的基礎,進行自己的學習記錄,接下來需要自定義一個 Spring Boot Starter 來進一步加深理解,後續可能還需要對 Spring 、Spring Boot 的源碼進行學習。