程式設計實戰篇——Spring Boot 自動配置實現

慕容千語發表於2018-10-12

基於Spring Boot自動配置的思想封裝起來,使其他Spring Boot專案引入後能夠進行快速配置。AutoConfiguration

Spring Boot的一個重要特性就是提供了各種各樣的AutoConfiguration。例如DataSourceAutoConfiguration。這樣我們只需要在配置檔案中進行如下配置:

spring:
  datasource:
    url: jdbc:mysql://xxxxxxxxxxx/realname
    username: xxxxx
    password: xxxxx
    driverClassName: com.mysql.jdbc.Driver複製程式碼

Spring Boot就會在容器中按照我們的配置的資訊注入一個DataSource。那麼Spring boot是怎麼知道 DataSourceAutoConfiguration是自動配置類?其實很簡單:

  1. Spring Boot在啟動時候會讀取檔案Classpath:\META-INF\spring.factories的所有檔案,spring.factories其實是一個properties的檔案,即是 key = value的形式。

  2. 獲取spring.factories中

    key=org.springframework.boot.autoconfigure.EnableAutoConfiguration配置項的值(類的全路徑)作為Spring啟動配置類

Spring Boot 這種用“約定優於配置”思想可以大大的簡化配置程式碼的編寫。那麼,我們就可以按照上面的套路來編寫一個Spring Boot的自動配置類吧

實戰

現在有一個配置Bean——PrintAfterInitBean,需要Spring容器啟動以後,列印一次訊息,並且該訊息的內容是在配置檔案中定義

第一步,編寫配置Bean——PrintAfterInitBean

程式碼如下,因為只是一個簡單例子,這裡的配置Bean其實可以是其他任何複雜配置Bean,例如DataSource。往往一個公共包需要多個這樣配置Bean才能完成其配置。

public class PrintAfterInitBean implements InitializingBean {
    private String message;

    public void afterPropertiesSet() throws Exception {
        System.out.println(message);
    }
    //setter getter
}複製程式碼

第二步,建立一個AutoConfiguration。

如果搜尋Spring Boot下面的類,你會發現其實有很多名字形如xxxAutoConfiguration的類,這些類都是Spirng Boot為我們做的一些快捷配置類。程式設計實戰篇——Spring Boot 自動配置實現 建立一個TestAutoConfig,作為一個自動配置類。

@Configuration
public class TestAutoConfig {

    @Bean
    @ConfigurationProperties(prefix = "init")
    @ConditionalOnMissingBean(PrintAfterInitBean.class)
    @ConditionalOnProperty(prefix = "init",value = "message") 
    public PrintAfterInitBean printAfterInitBean() {
        return new PrintAfterInitBean();
    }
}複製程式碼
  • @ConfigurationProperties 是Spring Boot提供的方便屬性注入的註解,功能其實和@Value類似

  • @ConditionalOnMissingBean 表示當BeanFactory中沒有PrintAfterInitBean型別的Bean才會建立,否則就會忽略這個Bean。這個就是上圖中所謂的【滿足自動配置條件】,同理的,ConditionalOnProperty表示當存在配置字首為init,配置值為message的配置的時候,才會生效。@ConditionalOnXXX 系列的註解都是為了在自動配置中,不侵入使用者的配置。

第三步,建立spring.factories

在resources下面建立META-INF/spring.factories, 然後在檔案中把第二步的類配置進去:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.xxx.TestAutoConfig複製程式碼

這樣就完成一個Spring Boot自動配置,如果存在init.message的配置,那麼Spring Boot啟動的時候就會列印init.message配置對應值。

小結

Spring Boot的自動配置為我們在編寫一個重複的配置程式碼(或者xml檔案)中提供一套簡便的部署方式,這樣當用其他spring boot的專案依賴我們jar時候,配置起來就十分方便拉。從程式碼可以看出,Spring Boot 其實並沒有什麼實質性的創新,只是把一些“約定”的配置資訊轉換原來通過程式碼或xml實現的配置。

常用註解

@ConditionalOnXXX

前面已經介紹過,@ConditionalOnXXX 系列主要是自動配置是否生效,例如ConditionalOnClass,就是在某個Class存在的情況下才生效。這一系列的註解通過名字就知道用法,因此不再做過多的介紹。@ConditionalOnXXX 可以用於類名和方法名上。

  • 用於類名上,要和 @Configuration一起使用,決定該配置類是否生效

  • 用於方法名上(注:前提是該方法也是一個配置類,即有@Configuration註解),結合@Bean一起使用,判斷該@Bean是否生成

用DataSourceAutoConfiguration 程式碼來說明。

@Configuration
// 注:當存在DataSource.class 和 EmbeddedDatabaseType.class 存在的情況下,該配置路徑才生效
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {

    private static final Log logger = LogFactory
            .getLog(DataSourceAutoConfiguration.class);

    @Bean
         // 注:只有當BeanFactory中不存在DataSourceInitializer類的Bean的情況下才會有效
    @ConditionalOnMissingBean
    public DataSourceInitializer dataSourceInitializer(DataSourceProperties properties,
            ApplicationContext applicationContext) {
        return new DataSourceInitializer(properties, applicationContext);
    }
...
}複製程式碼

自動配置的核心思想就是不侵佔使用者的程式碼,類似於“你有就用你的,你沒有我就幫你做預設設定”。因此,我們在自己開發一個自動配置類的時候也需要注意這一點,不然就有點霸王條款的感覺。

@EnableConfigurationProperties

一般我們的自動配置類都會依賴外部的配置資訊,而這些外部的配置資訊可以封裝成一個類,類似上面DataSourceAutoConfiguration中的@EnableConfigurationProperties(DataSourceProperties.class),DataSourceProperties類就是用來儲存DataSource相關的配置資訊。“約定優於配置”的思想就在這裡體現,如果配置資訊是以spring.datasource為字首,那麼配置資訊都會注入到DataSourceProperties類中,供DataSourceAutoConfiguration使用。

@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties
        implements BeanClassLoaderAware, EnvironmentAware, InitializingBean {

        ...
    private Class<? extends DataSource> type;
    private String driverClassName;
    private String url;
    private String username;
    private String password;
        ...

}複製程式碼

@AutoConfigureAfter

在一些特殊的情況下,一些自動配置類需要在某一些其他配置類後進行,例如依賴另外一個自動配置的Bean,這個時候就@AutoConfigureAfter來進行約束。

@Import

@Import也是比較常見的一個配置註解,主要用於引入其他配置類,但是另外一個比較有用的配置就是引入一個ImportBeanDefinitionRegistrar介面,而這個就是用於使用在ApplicationContext初始化階段的時候,註冊(register)一些BeanDefinition。當然常見的Bean是可以通過@Bean註解注入,但是一些Spring ApplicationContext啟動過程中用的到一些Bean則不行,例如BeanPostProcessor,BeanFactoryPostProcessor。

總結

Spring Boot 核心思想就是“約定優於配置”思想,在建立一個微服務的時候有很多得天獨厚的優勢,往往只用短短几行配置,就可以部署一個應用。這樣在編碼更多的是一些業務層面。而如果我們自己編寫的一個公共包也能夠通過短短几行配置即可以完成,不僅僅是程式碼層面的減少,更是接入方來說是一種“一站式服務”體驗。當然前提是接入方也是使用的Spring Boot。

歡迎工作一到五年的Java工程師朋友們加入Java進階之路:878249276

群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!



相關文章