頭禿了,使用@AutoConfigureBefore指定配置類順序竟沒生效?

愛撒謊的男孩發表於2020-11-25

持續原創輸出,點選上方藍字關注我

前言

日常工作中對於Spring Boot 提供的一些啟動器可能已經足夠使用了,但是不可避免的需要自定義啟動器,比如整合一個陌生的元件,也想要達到開箱即用的效果。

在上一章節從底層原始碼介紹了Spring Boot 的自動配置的原理,未讀過的朋友建議看一下:Spring Boot 自動配置原始碼解析

這篇文章將會介紹如何自定義一個啟動器,同時對於自動配置類的執行順序做一個詳細的分析。

如何自定義一個starter?

啟動器的核心其實就是自動配置類,在自動配置原始碼分析的章節已經介紹過,AutoConfigurationImportSelector是從spring.factories中載入自動配置類,因此只需要將自定義的自動配置類設定在該檔案中即可。

讀過原始碼的朋友都知道自動配置類常用的一些註解,總結如下:

  1. @Configuration: 該註解標誌這是一個配置類,自動配置類可以不加該註解
  2. @EnableConfigurationProperties:這個配置也是經常使用了,使得指定的屬性配置生效。一般自動配置類都需要從全域性屬性配置中讀取自定義的配置,這就是一個開關。
  3. @ConditionalOnXxxx:該註解是自動配置類的核心了,自動配置類既要啟動時自動配置,又要保證使用者使用者自定義的配置覆蓋掉自動配置,該註解就是一個條件語句,只有當指定條件成立才會執行某操作。不理解的,請看作者前面的一篇文章:這類註解都不知道,還說用過Spring Boot~
  4. @AutoConfigureAfter:指定自動配置類的執行先後順序,下文詳細介紹。
  5. @AutoConfigureBefore:指定自動配置列的執行先後順序,下文詳細介紹。
  6. @AutoConfigureOrder:指定自動配置類的優先順序,下文詳細介紹。

有了以上準備,自定義一個starter非常簡單,分為兩個步驟。

1. 準備自己的自動配置類

啟動器的靈魂核心就是自動配置類,因此需要首先建立一個自動配置類,如下:

@Configuration
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE+5)
@ConditionalOnProperty(prefix 
"my.auto",name = "enabled",havingValue = "true",matchIfMissing = true)
public class MyCustomAutoConfiguration {

}

以上自動配置類只是作者簡單的按照格式隨手寫了一個,真實開發中需要根據啟動器的業務做預設配置。

2. 將自動配置類設定在spring.factories

標註了@Configuration註解的自動配置類如果不放在spring.factories檔案中,僅僅是一個普通的配置類而已。想要其成為自動配置類,需要在spring.factories檔案中設定,如下:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfig.MyCustomAutoConfiguration

經過以上的配置,粗略的啟動器完成了,只需要打包,然後Maven引入即可工作。

如何指定自動配置類的執行順序?

自動配置類需要定義執行順序嗎?答案:肯定的。比如Mybatis的自動配置類,肯定要在資料來源的自動配置類之後執行,否則如何建立SqlSessionFactory

如何自定義自動配置類的執行順序呢?此時就需要用到上文提到的三個註解,如下:

  1. @AutoConfigureAfter: 當前配置類在指定配置類之後執行
  2. @AutoConfigureBefore: 當前配置類在指定配置類之前執行
  3. @AutoConfigureOrder:指定優先順序,數值越小,優先順序越高。

分享一個經典的誤區

對於Spring Boot不是很瞭解的人寫出的程式碼真是不堪入目,曾經看過有人在普通的配置類上使用@AutoConfigurexxx註解,如下;

@Configuration
@AutoConfigureBefore(Config2.class)
public class Config1
{}

@Configuration
public class Config2{}

是不是感覺很爽,原來還能這麼指定配置類的執行順序.....(此處省略一萬字)

可能有時候走了狗屎運給你一種錯覺還真的配置成功了。實際上這種方式是不可行的,以上三個註解只有針對自動配置類才會生效。

原始碼分析自動配置類如何排序?

其實關鍵的程式碼還是在AutoConfigurationImportSelector中,將自動配置類從spring.factories載入出來之後會根據條件排序,在selectImports()方法中最後一行程式碼如下:

return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
     .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
     .collect(Collectors.toList());

上面的程式碼則是將排序好的自動配置類返回,跟進程式碼,發現最終的實現都在AutoConfigurationSorter.getInPriorityOrder()方法中,邏輯如下圖:

具體的流程如上圖,排序也是按照先後順序,如下:

  1. 先按照字母排序
  2. 按照@AutoConfigureOrder優先順序排序
  3. 最終按照@AutoConfigureAfter@AutoConfigureBefore排序

從上面配置的順序可以知道,最終決定權還是在@AutoConfigureAfter@AutoConfigureBefore這兩個註解。

總結

本文介紹瞭如何自定義一個啟動器以及指定自動配置類的執行順序,通過作者的介紹,希望讀者們能夠理解並靈活運用。

另外作者的第一本PDF書籍已經整理好了,由淺入深的詳細介紹了Mybatis基礎以及底層原始碼,有需要的朋友公號回覆關鍵詞Mybatis進階即可獲取,目錄如下:

相關文章