关于spring.factories的常用配置项说明
作者:飘零未归人
概述
spring.factories 实现是依赖 spring-core 包里的 SpringFactoriesLoader 类,这个类实现了检索 META-INF/spring.factories 文件,并获取指定接口的配置的功能。
Spring Factories机制提供了一种解耦容器注入的方式,帮助外部包(独立于spring-boot项目)注册Bean到spring boot项目容器中。
spring.factories 这种机制实际上是仿照 java 中的 SPI 扩展机制实现的。
Spring Factories机制原理
核心类SpringFactoriesLoader
从上文可知,Spring Factories机制通过META-INF/spring.factories文件获取相关的实现类的配置信息,而SpringFactoriesLoader的功能就是读取META-INF/spring.factories,并加载配置中的类。
SpringFactoriesLoader主要有两个方法:loadFactories和loadFactoryNames。
- loadFactoryNames
用于按接口获取Spring Factories文件中的实现类的全称,其方法定义如下所示,其中参数factoryType指定了需要获取哪个接口的实现类,classLoader用于读取配置文件资源。
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader)
- loadFactories
用于按接口获取Spring Factories文件中的实现类的实例,其方法定义如下所示,其中参数factoryType指定了需要获取哪个接口的实现类,classLoader用于读取配置文件资源和加载类。
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader)
用法及配置
spring.factories 文件必须放在 resources 目录下的 META-INF 的目录下,否则不会生效。
如果一个接口希望配置多个实现类,可以用","分割。
BootstrapConfiguration
该配置项用于自动引入配置源,类似于spring-cloud的bootstrap和nacos的配置,通过指定的方式加载我们自定义的配置项信息。
该配置项配置的类必须是实现了PropertySourceLocator接口的类。
org.springframework.cloud.bootstrap.BootstrapConfiguration=\ xxxxxx.configure.config.ApplicationConfigure
public class ApplicationConfigure { @Bean @ConditionalOnMissingBean({CoreConfigPropertySourceLocator.class}) public CoreConfigPropertySourceLocator configLocalPropertySourceLocator() { return new CoreConfigPropertySourceLocator(); } } public class CoreConfigPropertySourceLocator implements PropertySourceLocator { ..... }
ApplicationContextInitializer
该配置项用来配置实现了 ApplicationContextInitializer 接口的类,这些类用来实现上下文初始化
org.springframework.context.ApplicationContextInitializer=\ xxxxxx.config.TestApplicationContextInitializer
public class TestApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("TestApplicationContextInitializer.initialize() " + applicationContext); } }
ApplicationListener
配置应用程序监听器,该监听器必须实现 ApplicationListener 接口。
它可以用来监听 ApplicationEvent 事件。
org.springframework.context.ApplicationListener=\ xxxxxxx.factories.listener.TestApplicationListener
@Slf4j public class TestApplicationListener implements ApplicationListener<TestMessageEvent> { @Override public void onApplicationEvent(EmailMessageEvent event) { log.info("模拟消息事件... "); log.info("TestApplicationListener 接受到的消息:{}", event.getContent()); } }
AutoConfigurationImportListener
该配置项用来配置自动配置导入监听器,监听器必须实现 AutoConfigurationImportListener 接口。
该监听器可以监听 AutoConfigurationImportEvent 事件。
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ xxxx.config.TestAutoConfigurationImportListener
public class TestAutoConfigurationImportListener implements AutoConfigurationImportListener { @Override public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) { System.out.println("TestAutoConfigurationImportListener.onAutoConfigurationImportEvent() " + event); } }
AutoConfigurationImportFilter
配置自动配置导入过滤器,过滤器必须实现 AutoConfigurationImportFilter 接口。
该过滤器用来过滤那些自动配置类可用。
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ xxxxxx.config.TestConfigurationCondition
public class TestConfigurationCondition implements AutoConfigurationImportFilter { @Override public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { System.out.println("TestConfigurationCondition.match() autoConfigurationClasses=" + Arrays.toString(autoConfigurationClasses) + ", autoConfigurationMetadata=" + autoConfigurationMetadata); return new boolean[0]; } }
EnableAutoConfiguration
配置自动配置类。
这些配置类需要添加 @Configuration 注解,可用于注册bean。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ xxxxx.config.TestConfiguration
@Configuration public class MyConfiguration { public MyConfiguration() { System.out.println("MyConfiguration()"); } @Bean public Testbean testbean(){ return new Testbean() } //注册过滤器 @Bean public TestFilter testFilter(){ return new TestFilter() } }
FailureAnalyzer
配置自定的错误分析类,该分析器需要实现 FailureAnalyzer 接口。
org.springframework.boot.diagnostics.FailureAnalyzer=\ xxxxx.config.TestFailureAnalyzer
/** * 自定义错误分析器 */ public class TestFailureAnalyzer implements FailureAnalyzer { @Override public FailureAnalysis analyze(Throwable failure) { System.out.println("TestFailureAnalyzer.analyze() failure=" + failure); return new FailureAnalysis("TestFailureAnalyzer execute", "test spring.factories", failure); } }
TemplateAvailabilityProvider
配置模板的可用性提供者,提供者需要实现 TemplateAvailabilityProvider 接口。
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\ xxxxx.config.TestTemplateAvailabilityProvider
/** * 验证指定的模板是否支持 */ public class TestTemplateAvailabilityProvider implements TemplateAvailabilityProvider { @Override public boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader, ResourceLoader resourceLoader) { System.out.println("TestTemplateAvailabilityProvider.isTemplateAvailable() view=" + view + ", environment=" + environment + ", classLoader=" + classLoader + "resourceLoader=" + resourceLoader); return false; } }
自定义Spring Factories机制
首先我们需要先定义两个模块,第一个模块A用于定义interface和获取interface的实现类。
代码如下:
package com.zhong.spring.demo.demo_7_springfactories; public interface DemoService { void printName(); } package com.zhong.spring.demo.demo_7_springfactories; import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import java.util.List; @Slf4j @Service public class DemoServiceFactory { @PostConstruct public void printService(){ List<String> serviceNames = SpringFactoriesLoader.loadFactoryNames(DemoService.class,null); for (String serviceName:serviceNames){ log.info("name:" + serviceName); } List<DemoService> services = SpringFactoriesLoader.loadFactories(DemoService.class,null); for (DemoService demoService:services){ demoService.printName(); } } }
另一个模块B引入A模块,并实现DemoService类。并且配置spring.factories
代码如下:
package com.zhong.spring.usuldemo.impl; import com.zhong.spring.demo.demo_7_springfactories.DemoService; import lombok.extern.slf4j.Slf4j; @Slf4j public class DemoServiceImpl1 implements DemoService { @Override public void printName() { log.info("-----------DemoServiceImpl2------------"); } } import com.zhong.spring.demo.demo_7_springfactories.DemoService; import lombok.extern.slf4j.Slf4j; @Slf4j public class DemoServiceImpl2 implements DemoService { @Override public void printName() { log.info("-----------DemoServiceImpl2------------"); } }
spring.factory配置如下:
com.zhong.spring.demo.demo_7_springfactories.DemoService=\ com.zhong.spring.usuldemo.impl.DemoServiceImpl1,\ com.zhong.spring.usuldemo.impl.DemoServiceImpl2
启动模块B
得到以下日志;
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。