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

解讀spring.factories文件配置詳情

 更新時間:2025年03月22日 11:38:20   作者:曠野歷程  
這篇文章主要介紹了解讀spring.factories文件配置詳情,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

使用場景

在程序開發(fā)中,可能會出現(xiàn)包名不一樣的情況(如:pom 依賴的很多的 jar),如何解決Spring Boot不能被默認路徑掃描呢?

  • 方法一:在 Spring Boot Application 主類上使用 @Import 注解。
  • 方法二:使用 spring.factories 文件

方法一比較簡單,在此就不做過多介紹,主要談談 spring.factories 使用。

作用

spring.factories 的作用是使用外部 jar 時不用再寫配置,會自動加入已經(jīng)配置好的配置。

內部原理機制

spring.factories 這種機制實際上是仿照 java 中的 SPI 擴展機制實現(xiàn)的。

SPI機制

SPI全稱Service Provider Interface,是 Java 提供的一套用來被第三方實現(xiàn)或者擴展的接口,其意義在于為某個接口尋找服務的實現(xiàn),主要應用在框架中用來尋找組件,提高擴展性。

面向的對象設計里,我們一般推薦模塊之間基于接口編程,模塊之間不對實現(xiàn)類進行硬編碼。一旦代碼里涉及了具體的實現(xiàn)類,就違反了可插拔的原則,如果需要替換一種實現(xiàn),就需要修改代碼。為了實現(xiàn)在模塊裝配的時候能不在程序里動態(tài)指明,這就需要一種服務發(fā)現(xiàn)機制。

  • Java 中的 SPI 機制:為某個接口尋找服務的實現(xiàn)的機制,有點類似 IOC 的思想,就是將裝配的控制權移到程序之外,在模塊化設計中這個機制很重要。
  • Spring Boot 中的 SPI 機制:在 META-INFO/spring.factories 文件中配置接口的實現(xiàn)類名稱,然后在程序中讀取這些配置文件并實例化。這種自定義的 SPI 機制就是 Spring Boot Starter 實現(xiàn)的基礎。

Spring Factories 實現(xiàn)原理

spring.factories 實現(xiàn)是依賴 spring-core 包里的 SpringFactoriesLoader 類,這個類實現(xiàn)了檢索 META-INF/spring.factories 文件,并獲取指定接口的配置的功能。

這個類中定義了兩個對外的方法:

  • loadFactories:根據(jù)接口類獲取其實現(xiàn)類的實例,這個方法返回的是對象列表
  • loadFactoryNames:根據(jù)接口獲取其接口類的名稱,這個方法返回的是類名的列表

上面兩個方法的關鍵都是從指定的 ClassLoader 中獲取 spring.factories 文件,并解析得到類名列表,具體代碼如下:

public final class SpringFactoriesLoader {
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
    private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();

    private SpringFactoriesLoader() {
    }

    public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
        Assert.notNull(factoryType, "'factoryType' must not be null");
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == 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());
        Iterator var5 = factoryImplementationNames.iterator();

        while(var5.hasNext()) {
            String factoryImplementationName = (String)var5.next();
            result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
        }

        AnnotationAwareOrderComparator.sort(result);
        return result;
    }

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryImplementationName = var9[var11];
                            result.add(factoryTypeName, factoryImplementationName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

    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() + "]");
            } else {
                return ReflectionUtils.accessibleConstructor(factoryImplementationClass, new Class[0]).newInstance();
            }
        } catch (Throwable var4) {
            throw new IllegalArgumentException("Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]", var4);
        }
    }
}

從上述代碼中可以看到,在這個方法中會遍歷整個 ClassLoader 中所有 jar 包下的 spring.factories 文件,文件之間不會相互影響配置,也不回被別人的配置覆蓋。

spring.factories 的是通過 Properties 解析得到的,所以在寫文件中的內容都是按照下面這種方式配置的。

用法及配置

spring.factories 文件必須放在 resources 目錄下的 META-INF 的目錄下,否則不會生效。如果一個接口希望配置多個實現(xiàn)類,可以用","分割。

spring.factories 各種配置的具體含義

ApplicationContextInitializer

  • 該配置項用來配置實現(xiàn)了 ApplicationContextInitializer 接口的類,這些類用來實現(xiàn)上下文初始化。
  • 配置如下:
org.springframework.context.ApplicationContextInitializer=\
com.xh.config.MyApplicationContextInitializer
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
 
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("MyApplicationContextInitializer.initialize() " + applicationContext);
    }
 
}

ApplicationListener

  • 配置應用程序監(jiān)聽器,該監(jiān)聽器必須實現(xiàn) ApplicationListener 接口。它可以用來監(jiān)聽 ApplicationEvent 事件。
  • 配置如下:
org.springframework.context.ApplicationListener=\
com.xh.factories.listener.EmailApplicationListener
@Slf4j
public class EmailApplicationListener implements ApplicationListener<EmailMessageEvent> {

    @Override
    public void onApplicationEvent(EmailMessageEvent event) {
        log.info("模擬發(fā)送郵件... ");
        log.info("EmailApplicationListener 接受到的消息:{}", event.getContent());
    }
}

AutoConfigurationImportListener

  • 該配置項用來配置自動配置導入監(jiān)聽器,監(jiān)聽器必須實現(xiàn) AutoConfigurationImportListener 接口。
  • 該監(jiān)聽器可以監(jiān)聽 AutoConfigurationImportEvent 事件。
  • 配置如下:
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
com.xh.config.MyAutoConfigurationImportListener
public class MyAutoConfigurationImportListener implements AutoConfigurationImportListener {
 
    @Override
    public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) {
        System.out.println("MyAutoConfigurationImportListener.onAutoConfigurationImportEvent() " + event);
    }
 
}

AutoConfigurationImportFilter

  • 配置自動配置導入過濾器,過濾器必須實現(xiàn) AutoConfigurationImportFilter 接口。
  • 該過濾器用來過濾那些自動配置類可用。
  • 配置如下:
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
com.xh.config.MyConfigurationCondition
public class MyConfigurationCondition implements AutoConfigurationImportFilter {
 
    @Override
    public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
        System.out.println("MyConfigurationCondition.match() autoConfigurationClasses=" +  Arrays.toString(autoConfigurationClasses) + ", autoConfigurationMetadata=" + autoConfigurationMetadata);
        return new boolean[0];
    }
 
}

EnableAutoConfiguration

  • 配置自動配置類。這些配置類需要添加 @Configuration 注解。
  • 配置如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xh.config.MyConfiguration
@Configuration
public class MyConfiguration {
 
    public MyConfiguration() {
        System.out.println("MyConfiguration()");
    }
 
}

FailureAnalyzer

  • 配置自定的錯誤分析類,該分析器需要實現(xiàn) FailureAnalyzer 接口。
  • 配置如下:
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.huangx.springboot.autoconfig.MyFailureAnalyzer
/**
 * 自定義錯誤分析器
 */
public class MyFailureAnalyzer implements FailureAnalyzer {
 
    @Override
    public FailureAnalysis analyze(Throwable failure) {
        System.out.println("MyFailureAnalyzer.analyze() failure=" + failure);
        return new FailureAnalysis("MyFailureAnalyzer execute", "test spring.factories", failure);
    }
 
}

TemplateAvailabilityProvider

  • 配置模板的可用性提供者,提供者需要實現(xiàn) TemplateAvailabilityProvider 接口。
  • 配置如下:
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
com.huangx.springboot.autoconfig.MyTemplateAvailabilityProvider
/**
 * 驗證指定的模板是否支持
 */
public class MyTemplateAvailabilityProvider implements TemplateAvailabilityProvider {
 
    @Override
    public boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader, ResourceLoader resourceLoader) {
        System.out.println("MyTemplateAvailabilityProvider.isTemplateAvailable() view=" + view + ", environment=" + environment + ", classLoader=" + classLoader + "resourceLoader=" + resourceLoader);
        return false;
    }
 
}

總結

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • MyBatis基本實現(xiàn)過程

    MyBatis基本實現(xiàn)過程

    這篇文章主要介紹了Spring整合mybatis實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2021-07-07
  • Token的作用及原理分析

    Token的作用及原理分析

    文章詳細介紹了Token的作用和原理,包括防止表單重復提交和身份驗證兩個主要用途,Token具有防止跨站偽造攻擊、無狀態(tài)化、支持跨域訪問、適用于移動端和RESTfulAPI等優(yōu)點,Token的存儲方式包括本地存儲、客戶端存儲和服務器存儲,Token的存在使得身份驗證更加安全
    2026-05-05
  • Spring將MultipartFile轉存到本地磁盤的三種方式

    Spring將MultipartFile轉存到本地磁盤的三種方式

    在Java中處理文件向來是一種不是很方便的操作,然后隨著Spring框架的崛起,使用Spring框架中的MultipartFile來處理文件也是件很方便的事了,今天就給大家介紹Spring將MultipartFile轉存到本地磁盤的方式,需要的朋友可以參考下
    2024-10-10
  • 如何在Spring boot加入shiro支持

    如何在Spring boot加入shiro支持

    這篇文章主要介紹了如何在Spring boot加入shiro支持,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • java——多線程基礎

    java——多線程基礎

    Java多線程實現(xiàn)方式有兩種,第一種是繼承Thread類,第二種是實現(xiàn)Runnable接口,兩種有很多差異,下面跟著本文一起學習吧,希望能給你帶來幫助
    2021-07-07
  • SpringBoot整合騰訊云COS對象存儲實現(xiàn)文件上傳的示例代碼

    SpringBoot整合騰訊云COS對象存儲實現(xiàn)文件上傳的示例代碼

    本文主要介紹了SpringBoot整合騰訊云COS對象存儲實現(xiàn)文件上傳的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • 基于RxPaparazzo實現(xiàn)圖片裁剪、圖片旋轉、比例放大縮小功能

    基于RxPaparazzo實現(xiàn)圖片裁剪、圖片旋轉、比例放大縮小功能

    這篇文章主要為大家詳細介紹了基于RxPaparazzo實現(xiàn)圖片裁剪、圖片旋轉、比例放大縮小功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Java實現(xiàn)將Markdown文檔轉換為Word與PDF的實戰(zhàn)指南

    Java實現(xiàn)將Markdown文檔轉換為Word與PDF的實戰(zhàn)指南

    這篇文章主要為大家詳細介紹了Java如何利用 Spire.Doc for Java實現(xiàn)將Markdown文檔轉換為Word與PDF,文中的示例代碼講解詳細,感興趣的小伙伴可以了解下
    2026-04-04
  • Springboot如何獲取配置文件application.yml中自定義的變量并使用

    Springboot如何獲取配置文件application.yml中自定義的變量并使用

    這篇文章主要介紹了Springboot中獲取配置文件(application.yml)中自定義的變量并使用,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • 淺談spring-kafka消費異常處理

    淺談spring-kafka消費異常處理

    本文主要介紹了spring-kafka消費異常處理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-09-09

最新評論

肃北| 桦甸市| 伊川县| 平湖市| 高陵县| 化州市| 噶尔县| 准格尔旗| 轮台县| 大石桥市| 汉川市| 泸水县| 同江市| 高淳县| 江都市| 高安市| 定远县| 张家港市| 湖口县| 宁国市| 通化县| 晋州市| 崇礼县| 乌拉特后旗| 庄河市| 吉林省| 康保县| 桦甸市| 泸西县| 孟津县| 上虞市| 南投县| 东乡族自治县| 华蓥市| 新干县| 延庆县| 儋州市| 句容市| 陕西省| 东台市| 康乐县|