1. 程式人生 > >Spring Boot面試殺手鐗————自動配置原理

Spring Boot面試殺手鐗————自動配置原理

引言

不論在工作中,亦或是求職面試,Spring Boot已經成為我們必知必會的技能項。除了某些老舊的政府專案或金融專案持有觀望態度外,如今的各行各業都在飛速的擁抱這個已經不是很新的Spring啟動框架。

當然,作為Spring Boot的精髓,自動配置原理的工作過程往往只有在“面試”的時候才能用得上,但是如果在工作中你能夠深入的理解Spring Boot的自動配置原理,將無往不利。

Spring Boot的出現,得益於“習慣優於配置”的理念,沒有繁瑣的配置、難以整合的內容(大多數流行第三方技術都被整合),這是基於Spring 4.x提供的按條件配置Bean的能力。

Spring Boot的配置檔案

初識Spring Boot時我們就知道,Spring Boot有一個全域性配置檔案:application.properties或application.yml。

我們的各種屬性都可以在這個檔案中進行配置,最常配置的比如:server.port、logging.level.* 等等,然而我們實際用到的往往只是很少的一部分,那麼這些屬性是否有據可依呢?答案當然是肯定的,這些屬性都可以在官方文件中查詢到:

https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#common-application-properties

(所以,話又說回來,找資料還得是官方文件,百度出來一大堆,還是稍顯業餘了一些)

除了官方文件為我們提供了大量的屬性解釋,我們也可以使用IDE的相關提示功能,比如IDEA的自動提示,和Eclipse的YEdit外掛,都可以很好的對你需要配置的屬性進行提示,下圖是使用Eclipse的YEdit外掛的效果,Eclipse的版本是:STS 4。

 以上,是Spring Boot的配置檔案的大致使用方法,其實都是些題外話。

那麼問題來了:這些配置是如何在Spring Boot專案中生效的呢?那麼接下來,就需要聚焦本篇部落格的主題:自動配置工作原理或者叫實現方式。

工作原理剖析

Spring Boot關於自動配置的原始碼在spring-boot-autoconfigure-x.x.x.x.jar中:

當然,自動配置原理的相關描述,官方文件貌似是沒有提及。不過我們不難猜出,Spring Boot的啟動類上有一個@SpringBootApplication註解,這個註解是Spring Boot專案必不可少的註解。那麼自動配置原理一定和這個註解有著千絲萬縷的聯絡!

@EnableAutoConfiguration

 @SpringBootApplication是一個複合註解或派生註解,在@SpringBootApplication中有一個註解@EnableAutoConfiguration,翻譯成人話就是開啟自動配置,其定義如下:

 而這個註解也是一個派生註解,其中的關鍵功能由@Import提供,其匯入的AutoConfigurationImportSelector的selectImports()方法通過SpringFactoriesLoader.loadFactoryNames()掃描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar裡就有一個這樣的spring.factories檔案。

這個spring.factories檔案也是一組一組的key=value的形式,其中一個key是EnableAutoConfiguration類的全類名,而它的value是一個xxxxAutoConfiguration的類名的列表,這些類名以逗號分隔,如下圖所示:

這個@EnableAutoConfiguration註解通過@SpringBootApplication被間接的標記在了Spring Boot的啟動類上。在SpringApplication.run(...)的內部就會執行selectImports()方法,找到所有JavaConfig自動配置類的全限定名對應的class,然後將所有自動配置類載入到Spring容器中。

自動配置生效

每一個XxxxAutoConfiguration自動配置類都是在某些條件之下才會生效的,這些條件的限制在Spring Boot中以註解的形式體現,常見的條件註解有如下幾項:

@ConditionalOnBean:當容器裡有指定的bean的條件下。

@ConditionalOnMissingBean:當容器裡不存在指定bean的條件下。

@ConditionalOnClass:當類路徑下有指定類的條件下。

@ConditionalOnMissingClass:當類路徑下不存在指定類的條件下。

@ConditionalOnProperty:指定的屬性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表當xxx.xxx為enable時條件的布林值為true,如果沒有設定的情況下也為true。

以ServletWebServerFactoryAutoConfiguration配置類為例,解釋一下全域性配置檔案中的屬性如何生效,比如:server.port=8081,是如何生效的(當然不配置也會有預設值,這個預設值來自於org.apache.catalina.startup.Tomcat)。

在ServletWebServerFactoryAutoConfiguration類上,有一個@EnableConfigurationProperties註解:開啟配置屬性,而它後面的引數是一個ServerProperties類,這就是習慣優於配置的最終落地點。

在這個類上,我們看到了一個非常熟悉的註解:@ConfigurationProperties,它的作用就是從配置檔案中繫結屬性到對應的bean上,而@EnableConfigurationProperties負責匯入這個已經綁定了屬性的bean到spring容器中(見上面截圖)。那麼所有其他的和這個類相關的屬性都可以在全域性配置檔案中定義,也就是說,真正“限制”我們可以在全域性配置檔案中配置哪些屬性的類就是這些XxxxProperties類,它與配置檔案中定義的prefix關鍵字開頭的一組屬性是唯一對應的。

至此,我們大致可以瞭解。在全域性配置的屬性如:server.port等,通過@ConfigurationProperties註解,繫結到對應的XxxxProperties配置實體類上封裝為一個bean,然後再通過@EnableConfigurationProperties註解匯入到Spring容器中。

而諸多的XxxxAutoConfiguration自動配置類,就是Spring容器的JavaConfig形式,作用就是為Spring 容器匯入bean,而所有匯入的bean所需要的屬性都通過xxxxProperties的bean來獲得。

可能到目前為止還是有所疑惑,但面試的時候,其實遠遠不需要回答的這麼具體,你只需要這樣回答:

Spring Boot啟動的時候會通過@EnableAutoConfiguration註解找到META-INF/spring.factories配置檔案中的所有自動配置類,並對其進行載入,而這些自動配置類都是以AutoConfiguration結尾來命名的,它實際上就是一個JavaConfig形式的Spring容器配置類,它能通過以Properties結尾命名的類中取得在全域性配置檔案中配置的屬性如:server.port,而XxxxProperties類是通過@ConfigurationProperties註解與全域性配置檔案中對應的屬性進行繫結的。

通過一張圖示來理解一下這一繁複的流程:

 圖片來自於王福強老師的部落格:https://afoo.me/posts/2015-07-09-how-spring-boot-works.html 

總結

綜上是對自動配置原理的講解。當然,在瀏覽原始碼的時候一定要記得不要太過拘泥與程式碼的實現,而是應該抓住重點脈絡。

一定要記得XxxxProperties類的含義是:封裝配置檔案中相關屬性;XxxxAutoConfiguration類的含義是:自動配置類,目的是給容器中新增元件。

而其他的主方法啟動,則是為了載入這些五花八門的XxxxAutoConfiguration類。