最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot借助spring.factories文件跨模塊實(shí)例化Bean

 更新時(shí)間:2022年04月28日 16:40:41   作者:CoderJ  
這篇文章主要介紹了SpringBoot借助spring.factories文件跨模塊實(shí)例化Bean,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,需要的小伙伴可以參考一下

1. 前言

SpringBoot在包掃描時(shí),并不會(huì)掃描子模塊下的內(nèi)容,這樣就使得我們的子模塊中的Bean無(wú)法注入到Spring容器中。SpringBoot就為我們提供了spring.factories這個(gè)文件,讓我們可以輕松的將子模塊的Bean注入到我們的Spring容器中,本篇文章我們就一起探究一下spring.factories 跨模塊實(shí)例化Bean的原理。

我們?cè)?a href="http://m.fzitv.net/article/246336.htm" rel="nofollow" target="_blank">SpringBoot項(xiàng)目為何引入大量的starter?如何自定義starter?文章中也講到構(gòu)建自己構(gòu)建starter,其中spring.factories就起到重要的作用,我們是通過spring.factories讓starer項(xiàng)目中的Bean注入到Web模塊的Spring容器中。本篇文章就來(lái)探究一下spring.factories文件,更深層次的東西,以及我們是如何借助該文件實(shí)例化Bean的。

2. 配置

spring.factories文件一般都是配置在src/main/resources/META-INF/ 目錄下。

也就是說我們?cè)贗DEA新建的SpringBoot項(xiàng)目或者M(jìn)aven項(xiàng)目的資源文件resources目錄下新建一個(gè)META-INF文件夾,再建一個(gè)spring.factories文件即可,新建的文件沒有問題的化,一般IDEA都能自動(dòng)識(shí)別,如下圖所示。

spring.factories 的文件內(nèi)容就是接口對(duì)應(yīng)其實(shí)現(xiàn)類,實(shí)現(xiàn)類可以有多個(gè)

文件內(nèi)容必須是kv形式,即properties類型

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.zhj.config.AutoConfiguration

如其一個(gè)接口有多個(gè)實(shí)現(xiàn),如下配置:

org.springframework.boot.logging.LoggingSystemFactory=\
org.springframework.boot.logging.logback.LogbackLoggingSystem.Factory,\
org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.Factory,\
org.springframework.boot.logging.java.JavaLoggingSystem.Factory

3. 原理

spring -core 中定義了SpringFactoriesLoader 類,這個(gè)類就是讓spring.factories文件發(fā)揮作用的類。SpringFactoriesLoader類的作用就是檢索META-INF/spring.factories文件,并獲取指定接口將其實(shí)現(xiàn)實(shí)例化。 在這個(gè)類中定義了兩個(gè)對(duì)外的方法:

  • loadFactories 根據(jù)給定的接口類獲取其實(shí)現(xiàn)類的實(shí)例,這個(gè)方法返回的是對(duì)象列表
  • loadFactoryNames 根據(jù)給定的類型加載類路徑的全限定類名,這個(gè)方法返回的是全限定類名的列表。

源碼如下:

public final class SpringFactoriesLoader {
    
 ? ?// 文件位置
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    
 ? ?// 緩存
    private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
?
?
    private SpringFactoriesLoader() {
    }
?
?
    /**
     * 根據(jù)給定的類型加載并實(shí)例化工廠的實(shí)現(xiàn)類
     */
    public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
        Assert.notNull(factoryType, "'factoryType' must not be null");
        // 獲取類加載器
        ClassLoader classLoaderToUse = classLoader;
        if (classLoaderToUse == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }
        // 加載類的全限定名
        List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
        if (logger.isTraceEnabled()) {
            logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
        }
        List<T> result = new ArrayList<>(factoryImplementationNames.size());
        for (String factoryImplementationName : factoryImplementationNames) {
            // 實(shí)例化Bean,并將Bean放入到List集合中
            result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
        }
        AnnotationAwareOrderComparator.sort(result);
        return result;
    }
    
    /**
     * 根據(jù)給定的類型加載類路徑的全限定類名
     */
    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        
 ? ? ? ?// 獲取工廠類型名稱
        String factoryTypeName = factoryType.getName();
        // 加載所有META-INF/spring.factories中的value
        return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }
    
    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        // 根據(jù)類加載器從緩存中獲取,如果緩存中存在,就直接返回,如果不存在就去加載
        MultiValueMap<String, String> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }
    
        try {
            // 獲取所有jar中classpath路徑下的META-INF/spring.factories
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            // 遍歷所有的META-INF/spring.factories
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                // 將META-INF/spring.factories中的key value加載為Prpperties對(duì)象
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    // key就是接口的類名稱
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                        // 以factoryTypeName為key,實(shí)現(xiàn)類為value放入map集合中
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }
            // 加入緩存
            cache.put(classLoader, result);
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }
    
    // 通過反射實(shí)例化Bean對(duì)象
    @SuppressWarnings("unchecked")
    private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) {
        try {
            Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);
            if (!factoryType.isAssignableFrom(factoryImplementationClass)) {
                throw new IllegalArgumentException(
                        "Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]");
            }
            return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance();
        }
        catch (Throwable ex) {
            throw new IllegalArgumentException(
                "Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]",
                ex);
        }
    }
?
}

4. 總結(jié)

Spring通過SpringFactoriesLoader實(shí)例化Bean的過程

  • 獲取SpringFactoriesLoader對(duì)應(yīng)的類加載器
  • 查找緩存,查看緩存中是否已經(jīng)讀取到所有jar中classpath路徑下的META-INF/spring.factories的內(nèi)容
  • 如果緩存已經(jīng)存在,根據(jù)/spring.factories文件中配置的全限定類名通過反射實(shí)例化Bean
  • 如果緩存中沒有值,則掃描所有jar中的這個(gè)META-INF/spring.factories文件,并將其以讀取到緩存中,并返回這個(gè)配置列表
  • 然后根據(jù)這個(gè)全限定類名的列表再通過反射實(shí)例化Bean

到此這篇關(guān)于SpringBoot借助spring.factories文件跨模塊實(shí)例化Bean的文章就介紹到這了,更多相關(guān)SpringBoot實(shí)例化Bean內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文帶你搞懂Java8的LocalDateTime

    一文帶你搞懂Java8的LocalDateTime

    LocalDateTime?是Java8中新加入的日期時(shí)間類,現(xiàn)在都?Java20?了,不會(huì)還有人沒用過?LocalDateTime?吧?今天給大家演示一下?LocalDateTime?的常用方法
    2023-04-04
  • MyBatisPlus3.x中使用代碼生成器(全注釋)

    MyBatisPlus3.x中使用代碼生成器(全注釋)

    這篇文章主要介紹了MyBatisPlus3.x中使用代碼生成器(全注釋),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • java 多態(tài)與抽象類詳解總結(jié)

    java 多態(tài)與抽象類詳解總結(jié)

    在面向?qū)ο蟮母拍钪?,所有的?duì)象都是通過類來(lái)描繪的,但是反過來(lái),并不是所有的類都是用來(lái)描繪對(duì)象的,如果一個(gè)類中沒有包含足夠的信息來(lái)描繪一個(gè)具體的對(duì)象,這樣的類就是抽象類,而多態(tài)是同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力
    2021-11-11
  • 淺談java多態(tài)的實(shí)現(xiàn)主要體現(xiàn)在哪些方面

    淺談java多態(tài)的實(shí)現(xiàn)主要體現(xiàn)在哪些方面

    下面小編就為大家?guī)?lái)一篇淺談java多態(tài)的實(shí)現(xiàn)主要體現(xiàn)在哪些方面。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2016-09-09
  • 全排列算法-遞歸與字典序的實(shí)現(xiàn)方法(Java)

    全排列算法-遞歸與字典序的實(shí)現(xiàn)方法(Java)

    下面小編就為大家?guī)?lái)一篇全排列算法-遞歸與字典序的實(shí)現(xiàn)方法(Java) 。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2017-04-04
  • springboot項(xiàng)目中后端接收前端傳參的方法示例詳解

    springboot項(xiàng)目中后端接收前端傳參的方法示例詳解

    這篇文章主要介紹了springboot項(xiàng)目中一些后端接收前端傳參的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • MyBatisPlus批量添加的優(yōu)化與報(bào)錯(cuò)解決

    MyBatisPlus批量添加的優(yōu)化與報(bào)錯(cuò)解決

    MybatisPlus是一個(gè)高效的java持久層框架,它在Mybatis的基礎(chǔ)上增加了一些便捷的功能,提供了更加易用的API,可以大幅度提高開發(fā)效率,這篇文章主要給大家介紹了關(guān)于MyBatisPlus批量添加的優(yōu)化與報(bào)錯(cuò)解決的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • Java線程池的工作機(jī)制詳解

    Java線程池的工作機(jī)制詳解

    本文講述了Java線程池的工作機(jī)制,包括線程池的創(chuàng)建、任務(wù)調(diào)度、線程復(fù)用、資源管理和拒絕策略,通過合理配置線程池參數(shù),可以提升系統(tǒng)的并發(fā)性能和穩(wěn)定性
    2024-12-12
  • Java環(huán)境變量配置教程

    Java環(huán)境變量配置教程

    這篇文章主要介紹了Java環(huán)境變量配置教程,簡(jiǎn)單介紹了java的環(huán)境變量設(shè)置方法,感興趣的小伙伴們可以參考一下
    2016-06-06
  • java字符流緩沖區(qū)詳解

    java字符流緩沖區(qū)詳解

    這篇文章主要為大家詳細(xì)介紹了java字符流緩沖區(qū)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08

最新評(píng)論

凤庆县| 娄底市| 台安县| 台北市| 会宁县| 奉节县| 会昌县| 西吉县| 盱眙县| 宁蒗| 霍邱县| 紫云| 鄂托克前旗| 东丽区| 桐柏县| 平塘县| 隆德县| 新平| 通渭县| 永靖县| 宝鸡市| 眉山市| 盐源县| 渑池县| 蒙城县| 阿拉善盟| 东台市| 夏河县| 汕头市| 大渡口区| 通许县| 陆丰市| 永嘉县| 应用必备| 洛南县| 武汉市| 高尔夫| 固始县| 苏尼特右旗| 会同县| 兴和县|