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

Java中的Spring.factories文件詳解

 更新時間:2026年03月30日 08:57:18   作者:大阿明  
文章主要介紹了在SpringBoot項目中如何使用spring.factories文件來注冊項目依賴包中的bean,包括SpringFactories的實現(xiàn)原理、SpringBoot中的SPI機制、SpringFactories在SpringBoot中的應用、Beans的配置等內(nèi)容,從而實現(xiàn)解耦的擴展機制,感興趣的朋友一起看看吧

1.概述

在 Spring Boot 項目中,怎樣將 pom.xml 文件里面添加的依賴中的 bean 注冊到 Spring Boot 項目的 Spring 容器中呢?

你可能會首先想到使用@ComponentScan 注解,遺憾的是 @ComponentScan 注解只能掃描 Spring Boot 項目包內(nèi)的 bean 并注冊到 Spring 容器中,項目依賴包中的 bean 不會被掃描和注冊。此時,我們需要使用 @EnableAutoConfiguration 注解來注冊項目依賴包中的 bean。而 spring.factories 文件,可用來記錄項目包外需要注冊的 bean 類名。

使用 spring.factories 文件有什么好處呢?假如我們封裝了一個插件,該插件提供給其他開發(fā)人員使用。我們可以在spring.factories 文件中指定需要自動注冊到 Spring 容器的 bean 和一些配置信息。使用該插件的開發(fā)人員只需少許配置,甚至不進行任何配置也能正常使用。

2.Spring Boot的擴展機制之Spring Factories

寫在前面:Spring Boot中有一種非常解耦的擴展機制:Spring Factories。這種擴展機制實際上是仿照Java中的SPI擴展機制來實現(xiàn)的。

2.1什么是 SPI機制

SPI的全名為Service Provider Interface.大多數(shù)開發(fā)人員可能不熟悉,因為這個是針對廠商或者插件的。在java.util.ServiceLoader的文檔里有比較詳細的介紹。
簡單的總結(jié)下java SPI機制的思想。我們系統(tǒng)里抽象的各個模塊,往往有很多不同的實現(xiàn)方案,比如日志模塊的方案,xml解析模塊、jdbc模塊的方案等。面向的對象的設計里,我們一般推薦模塊之間基于接口編程,模塊之間不對實現(xiàn)類進行硬編碼。一旦代碼里涉及具體的實現(xiàn)類,就違反了可拔插的原則,如果需要替換一種實現(xiàn),就需要修改代碼。為了實現(xiàn)在模塊裝配的時候能不在程序里動態(tài)指明,這就需要一種服務發(fā)現(xiàn)機制。
java SPI就是提供這樣的一個機制:為某個接口尋找服務實現(xiàn)的機制。有點類似IOC的思想,就是將裝配的控制權(quán)移到程序之外,在模塊化設計中這個機制尤其重要。

2.2 Spring Boot中的SPI機制

在Spring中也有一種類似與Java SPI的加載機制。它在META-INF/spring.factories文件中配置接口的實現(xiàn)類名稱,然后在程序中讀取這些配置文件并實例化。
這種自定義的SPI機制是Spring Boot Starter實現(xiàn)的基礎。

2.3 Spring Factories實現(xiàn)原理是什么

spring-core包里定義了SpringFactoriesLoader類,這個類實現(xiàn)了檢索META-INF/spring.factories文件,并獲取指定接口的配置的功能。在這個類中定義了兩個對外的方法:

loadFactories 根據(jù)接口類獲取其實現(xiàn)類的實例,這個方法返回的是對象列表。
loadFactoryNames 根據(jù)接口獲取其接口類的名稱,這個方法返回的是類名的列表。
上面的兩個方法的關鍵都是從指定的ClassLoader中獲取spring.factories文件,并解析得到類名列表,具體代碼如下↓

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    try {
        Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        List<String> result = new ArrayList<String>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
            String factoryClassNames = properties.getProperty(factoryClassName);
            result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
        }
        return result;
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
}

從代碼中我們可以知道,在這個方法中會遍歷整個ClassLoader中所有jar包下的spring.factories文件。也就是說我們可以在自己的jar中配置spring.factories文件,不會影響到其它地方的配置,也不會被別人的配置覆蓋。

spring.factories的是通過Properties解析得到的,所以我們在寫文件中的內(nèi)容都是安裝下面這種方式配置的:

com.xxx.interface=com.xxx.classname

如果一個接口希望配置多個實現(xiàn)類,可以使用’,’進行分割。

2.4 Spring Factories在Spring Boot中的應用

在Spring Boot的很多包中都能夠找到spring.factories文件,接下來我們以spring-boot包為例進行介紹

在日常工作中,我們可能需要實現(xiàn)一些SDK或者Spring Boot Starter給被人使用時,
我們就可以使用Factories機制。Factories機制可以讓SDK或者Starter的使用只需要很少或者不需要進行配置,只需要在服務中引入我們的jar包即可。

3.用法及配置Bean

spring.factories 文件的用法,以及介紹該文件中可以配置那些 Bean。內(nèi)容如下:

## Initializers
org.springframework.context.ApplicationContextInitializer=

com.huangx.springboot.autoconfig.MyApplicationContextInitializer

## Application Listeners
org.springframework.context.ApplicationListener=

com.huangx.springboot.autoconfig.MyApplicationListener

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

com.huangx.springboot.autoconfig.MyAutoConfigurationImportListener

## Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=

com.huangx.springboot.autoconfig.MyConfigurationCondition

## Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=

com.huangx.springboot.autoconfig.MyConfiguration

## Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=

com.huangx.springboot.autoconfig.MyFailureAnalyzer

## Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=

com.huangx.springboot.autoconfig.MyTemplateAvailabilityProvider

#后置環(huán)境變量處理器
org.springframework.boot.env.EnvironmentPostProcessor=cn.telecom.starter.cloud.LoadProperties

下面將分別介紹各種配置的具體含義:

3.1 ApplicationContextInitializer

該配置項用來配置實現(xiàn)了ApplicationContextInitializer 接口的類,這些類用來實現(xiàn)上下文初始化。配置如下:

org.springframework.context.ApplicationContextInitializer=

com.huangx.springboot.autoconfig.MyApplicationContextInitializer

實例代碼:

public class MyApplicationContextInitializer implements
        ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("MyApplicationContextInitializer.initialize() " + applicationContext);
    }
}

3.2 ApplicationListener

配置應用程序監(jiān)聽器,該監(jiān)聽器必須實現(xiàn) ApplicationListener 接口。它可以用來監(jiān)聽ApplicationEvent 事件。配置如下:

org.springframework.context.ApplicationListener=

com.huangx.springboot.autoconfig.MyApplicationListener

實例代碼:

public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("MyApplicationListener.onApplicationEvent() " + event);
        if(event instanceof ApplicationStartedEvent) {
            throw new RuntimeException("我故意拋出的錯誤,僅僅為了觸發(fā)自定義 MyFailureAnalyzer");
        }
    }
}

3.3 AutoConfigurationImportListener

該配置項用來配置自動配置導入監(jiān)聽器,監(jiān)聽器必須實現(xiàn)AutoConfigurationImportListener 接口。該監(jiān)聽器可以監(jiān)聽 AutoConfigurationImportEvent 事件。配置如下:

org.springframework.boot.autoconfigure.AutoConfigurationImportListener=

com.huangx.springboot.autoconfig.MyAutoConfigurationImportListener

實例代碼:

public class MyAutoConfigurationImportListener implements AutoConfigurationImportListener {
    @Override
    public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) {
        System.out.println("MyAutoConfigurationImportListener.onAutoConfigurationImportEvent() " + event);
    }
}

3.4 AutoConfigurationImportFilter

配置自動配置導入過濾器,過濾器必須實現(xiàn)AutoConfigurationImportFilter 接口。該過濾器用來過濾那些自動配置類可用,配置信息:

org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=

com.huangx.springboot.autoconfig.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];
    }
}

3.5 EnableAutoConfiguration

配置自動配置類。這些配置類需要添加@Configuration 注解,配置如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=

com.huangx.springboot.autoconfig.MyConfiguration

實例代碼:

@Configuration
public class MyConfiguration {
    public MyConfiguration() {
        System.out.println("MyConfiguration()");
    }
}

3.6 FailureAnalyzer

配置自定的錯誤分析類,該分析器需要實現(xiàn)FailureAnalyzer 接口。配置信息:

org.springframework.boot.diagnostics.FailureAnalyzer=

com.huangx.springboot.autoconfig.MyFailureAnalyzer

實例代碼:

/**
 * 自定義自己的錯誤分析器 FailureAnalyzer
 * @author Administrator 2021/4/1 13:14
 * @version 1.0
 */
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);
    }
}

運行效果如下圖:

3.7 TemplateAvailabilityProvider

配置模板的可用性提供者,提供者需要實現(xiàn)TemplateAvailabilityProvider 接口,配置如下:

org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=

com.huangx.springboot.autoconfig.MyTemplateAvailabilityProvider

實例代碼:

/**
 * 驗證指定的模板是否支持
 * @author Administrator 2021/4/1 13:22
 * @version 1.0
 */
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;
    }
}

3.8 EnvironmentPostProcessor

環(huán)境后置處理器

org.springframework.boot.env.EnvironmentPostProcessor=cn.telecom.starter.cloud.LoadProperties

實例代碼:

public class LoadProperties implements EnvironmentPostProcessor {
    /**
     * 文件名
     */
    private static final String FILE_NAME = "test-starter-cloud.properties";
    /**
     * 版本鎖
     */
    private static int version = 0;
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        // 通過版本號控制解決啟動服務時加載兩次的問題
        if (version++ == 0) {
            System.out.println("動態(tài)加載自定義配置:" + getClass().getName());
            MutablePropertySources sources = environment.getPropertySources();
            // 加載指定的配置文件(效率較高,但需要指定文件)
            loadPropertySource(sources, FILE_NAME);
        }
    }
    /**
     * 加載配置文件資源
     *
     * @param sources
     * @param file
     */
    private void loadPropertySource(MutablePropertySources sources, String file) {
        try {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            InputStream is = classLoader.getResourceAsStream(file);
            if (is != null) {
                Properties properties = new Properties();
                properties.load(is);
                PropertiesPropertySource propertySource = new PropertiesPropertySource("dynamic", properties);
                sources.addLast(propertySource);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

文章內(nèi)容來源:

Spring Boot的擴展機制之Spring Factories_伊成的博客-CSDN博客_spring.factories文件

Spring Boot 你不得不會的 spring.factories 配置 - 人人編程網(wǎng)

到此這篇關于Java中的Spring.factories文件詳解的文章就介紹到這了,更多相關Spring.factories內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

调兵山市| 定州市| 武威市| 洪洞县| 红桥区| 黄大仙区| 辽阳市| 睢宁县| 民丰县| 华蓥市| 克山县| 娄底市| 神池县| 三明市| 开江县| 桂林市| 和硕县| 民和| 辽源市| 建湖县| 淮北市| 宁国市| 信阳市| 桂林市| 济南市| 南雄市| 华安县| 开鲁县| 大竹县| 吉安市| 外汇| 乃东县| 津市市| 筠连县| 韶山市| 房产| 乐昌市| 阳原县| 抚州市| 临泽县| 龙江县|