首頁 > 軟體

springBoot 之spring.factories擴充套件機制範例解析

2023-09-06 22:05:48

引言

這個月準備寫完Spring原始碼解析系列文章。我相信大多點進來看的同學們都應該或多或少對springBoot的擴充套件機制有一些瞭解,我們這次通過八股文歸納法和原始碼淺層解析,達到大家對SpringBoot擴充套件的機制的理解。全文看完大概三分鐘,希望大家都有收穫,畢竟藝多不壓身,知其然知其所以然。

在Spring Boot中,我們通常會看到一些原始碼包的META-INF下又一個檔案spring.factories。大家都知道它是一種擴充套件機制,有的同學可能在其他部落格中看到把它稱之為Spring Boot SPI。為什麼這麼稱謂呢,後續我專門分享一篇Java SPI。那麼到底它是如何實現spring Boot的擴充套件的呢。在本文中,我們將深入探討這種擴充套件機制的底層原始碼實現,以及我們在原始碼上標註註釋的形式,共同揭開Spring.factories 的神祕面紗。

1. spring.factories八股總結

如果只是需要應付面試或者只是想大概瞭解,看完此章節就可以了

1.1 spring.factories檔案格式

在分析spring.factories的底層實現之前,我們需要了解spring.factories檔案的格式。spring.factories檔案是一個標準的Properties檔案,其中鍵是要擴充套件的型別的全限定名,值是要註冊的bean的全限定名。

例如 

org.springframework.boot.autoconfigure.EnableAutoConfiguration= com.example.MyAutoConfiguration。

1.2 SpringFactoriesLoader類

SpringFactoriesLoader是一個實用類,它用於載入spring.factories檔案並註冊bean定義。以下是SpringFactoriesLoader類的原始碼: loadFactory方法首先使用傳遞的Class物件的名稱作為鍵呼叫loadFactories方法來獲取已註冊bean的全限定名列表。然後,它使用Java 8的Stream API將全限定名列表對映到相應的Class物件,並使用反射通過無引數建構函式範例化每個Class物件。最後,它將範例化的物件收集到一個List物件中並返回。

1.3 loadFactories方法

loadFactories方法是SpringFactoriesLoader類的私有方法,它接收一個要擴充套件的型別的Class物件和一個ClassLoader物件,並返回一個包含所有已註冊bean的List物件loadFactories方法首先使用傳遞的Class物件的名稱作為鍵從快取Map中獲取已註冊bean的全限定名列表。

如果快取中沒有,則使用傳遞的ClassLoader物件從classpath中獲取所有spring.factories檔案的URL,並使用PropertiesLoaderUtils類載入每個檔案中的Properties物件。

對於每個Properties物件,它獲取與傳遞的Class物件的名稱相對應的屬性值, 在Spring Boot中,spring.factories是一個非常重要的組態檔,它用於實現Spring Boot的自動化設定。這個檔案位於META-INF/spring.factories路徑下,通常可以在專案的classpath下找到。

spring.factories檔案的格式如下所示:

# Auto Configuration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.example.MyAutoConfiguration

這個檔案中定義了一個名為org.springframework.boot.autoconfigure.EnableAutoConfiguration的屬性,它的值是一個類的完全限定名,即com.example.MyAutoConfiguration。這個類通常是一個Spring設定類,用於定義一些自動化設定。

Spring Boot在啟動時會掃描classpath中的所有spring.factories檔案,並讀取其中定義的屬性。然後,它會根據這些屬性值載入對應的類,並將它們註冊到Spring的ApplicationContext中。

好吧,如上所示是Spring Boot中spring.factories的底層原始碼解析: 整個載入過程我們可以大致分為5步.

你也可以理解為咱們整理的為了方便記憶八股文吧 

  • Spring Boot通過SpringFactoriesLoader類來載入spring.factories檔案。這個類是Spring框架中的一個工具類,用於載入classpath下的所有spring.factories檔案,並將它們的內容儲存在一個Map<String, List<String>>物件中。
  • Spring Boot使用SpringFactoriesLoader.loadFactoryNames方法來載入指定屬性名的所有實現類。這個方法會從步驟1中載入的Map<String, List<String>>物件中獲取對應屬性名的實現類列表。
  • Spring Boot使用SpringFactoriesLoader.loadFactories方法來載入指定屬性名的所有實現類的範例。這個方法會遍歷步驟2中獲取的實現類列表,並使用反射機制範例化每一個類。
  • Spring Boot會將步驟3中範例化的類註冊為Spring的Bean。它會呼叫AnnotationConfigUtils.registerAnnotationConfigProcessors方法來註冊自動設定類。這個方法會呼叫BeanDefinitionRegistryPostProcessor介面的實現類的postProcessBeanDefinitionRegistry方法,來註冊自動設定類的BeanDefinition。
  • Spring Boot會啟動Spring的ApplicationContext,並讓它自動掃描所有的Bean。它會呼叫AnnotationConfigApplicationContext.refresh方法來啟動ApplicationContext,並讓它自動掃描所有的Bean。在掃描過程中,Spring會發現步驟4中註冊的自動設定類,並嘗試自動設定應用程式。
/**
 * SpringFactoriesLoader類是Spring框架中的一個工具類,用於載入classpath下的所有spring.factories檔案,
 * 並將它們的內容儲存在一個Map<String, List<String>>物件中。
 */
public final class SpringFactoriesLoader {
    /**
     * 私有建構函式,不允許範例化。
     */
    private SpringFactoriesLoader() {
    }
    /**
     * 載入指定屬性名的所有實現類的類名列表。
     * @param factoryType 屬性名
     * @param classLoader 類載入器
     * @return 類名列表
     */
    public static List<String> loadFactoryNames(Class<?> factoryType, ClassLoader classLoader) {
        // ...
    }
    /**
     * 載入指定屬性名的所有實現類的範例。
     * @param factoryType 屬性名
     * @param classLoader 類載入器
     * @param <T> 實現類的型別
     * @return 實現類的範例列表
     */
    public static <T> List<T> loadFactories(Class<T> factoryType, ClassLoader classLoader) {
        // 省略 ...
    }
}
/**
 * AnnotationConfigUtils類提供了一些用於處理註解設定的工具方法。
 */
class AnnotationConfigUtils {
    /**
     * 註冊自動設定類。
     * @param registry Bean定義註冊器
     */
    public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
        // ...
    }
}
/**
 * AnnotationConfigApplicationContext類是Spring的ApplicationContext介面的一個實現類,
 * 用於支援基於Java設定的應用程式上下文。
 */
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    /**
     * 啟動ApplicationContext,並讓它自動掃描所有的Bean。
     */
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        // ...
    }
}

好了,今天的內容就到這兒了,每天寫點東西整理和總結。謝謝大家的閱讀。放棄很容易但堅持一定很酷。一起加油

更多關於springBoot spring.factories擴充套件的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com