SpringBoot3.x中spring.factories功能被移除的解決方案

throwable 發表於 2022-12-04
Spring

背景

筆者所在專案組在搭建一個全新專案的時候選用了SpringBoot3.x,專案中應用了很多SpringBoot2.x時代相關的第三方元件例如baomidou出品的mybatis-plusdynamic-datasource等。在配置好相關依賴、最小啟動類和配置之後,發現專案無法啟動。於是根據啟動上下文日誌和按行DEBUG找到原因並且在等待元件升級相容之前進行臨時性解決。

關於spring.factories

spring.factories其實是SpringBoot提供的SPI機制,底層實現是基於SpringFactoriesLoader檢索ClassLoader中所有jar(包括ClassPath下的所有模組)引入的META-INF/spring.factories檔案,基於檔案中的介面(或者註解)載入對應的實現類並且註冊到IOC容器。這種方式對於@ComponentScan不能掃描到的並且想自動註冊到IOC容器的使用場景十分合適,基本上絕大多數第三方元件甚至部分spring-projects中編寫的元件都是使用這種方案。

sp-3-upgrade-1.png

spring.factories檔案的格式大致如下:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.autoconfigure.integration.IntegrationPropertiesEnvironmentPostProcessor

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration,\
com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration

通用格式是:介面(或者註解)全類名=\介面實現類(或者使用了該註解的類)全類名-1,\介面實現類(或者使用了該註解的類)全類名-2,\...介面實現類(或者使用了該註解的類)全類名-nspring.factories中最常用的註解是org.springframework.boot.autoconfigure.EnableAutoConfiguration,透過配置此註解對應的實現了,底層會由AutoConfigurationImportSelector對響應的目標類進行載入和自動註冊。透過閱讀Spring Boot 3.0 Migration Guide得知,spring.factories功能在Spring Boot 2.7已經廢棄,並且會在Spring Boot 3.0移除。

spring.factories被移除後的替代方案

Spring Boot 2.x升級到Spring Boot 3.0其實是一個"破壞性"升級,目前來看相對較大的影響是:

  • 必須使用JDK17
  • Jakarta EE的引入,導致很多舊的類包名稱改變
  • 部分類被徹底移除
  • spring-data模組的所有配置屬性必須使用spring.data字首,例如spring.redis.host必須更變為spring.data.redis.host
  • spring.factories功能在Spring Boot 2.7已經廢棄,在Spring Boot 3.0徹底移除(見下圖)

sp-3-upgrade-2.png

替代方案比較簡單,就是在類路徑下建立META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports檔案,檔案的內容是:每個實現類的全類名單獨一行。例如對於使用了(低版本還沒適配Spring Boot 3.0mybatis-plusdynamic-datasource元件的場景,可以在專案某個模組的resources目錄下建立META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports檔案,輸入以下內容:

com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration
com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration
com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration

對於某些社群熱度比較高的元件近期可以密切關注其基於Spring Boot 3.0適配的版本釋出,例如mybatis-springdubbo等:

sp-3-upgrade-3.png

這裡還沒詳細分析META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports的原始碼實現,從描述和檔名來看,大致看出它在使用上跟原來的spring.factories檔案中編寫org.springframework.boot.autoconfigure.EnableAutoConfiguration是相同的

小結

Spring Boot 3.0的升級門檻比較高。目前來看spring.factories功能的移除個人認為是本次版本升級的最大影響因素,有可能導致大部分第三方編寫過自動註冊板塊的元件全部失效。當然,JDK17也是一個比較高的門檻,對於大部分有歷史包袱的專案如果決定升級需要極大的容器。建議先觀望和關注團隊用到的技術棧或者框架都適配Spring Boot 3.0後再進行版本升級。

(c-1-d e-a-20221204 廣州基本開放,不需要做核酸了)