news 2026/5/9 18:50:15

Spring.factories

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring.factories

目录

1.概述

2.Spring Boot的扩展机制之Spring Factories

2.1什么是 SPI机制

2.2 Spring Boot中的SPI机制

2.3 Spring Factories实现原理是什么

2.4 Spring Factories在Spring Boot中的应用

3.用法及配置Bean

3.1 ApplicationContextInitializer

3.2 ApplicationListener

3.3 AutoConfigurationImportListener

3.4 AutoConfigurationImportFilter

3.5 EnableAutoConfiguration

3.6 FailureAnalyzer

3.7 TemplateAvailabilityProvider

3.8 EnvironmentPostProcessor?


1.概述

在 Spring Boot 项目中,怎样将 pom.xml 文件里面添加的依赖中的 bean 注册到 Spring Boot 项目的 Spring 容器中呢?

你可能会首先想到使用@ComponentScan 注解,遗憾的是 @ComponentScan 注解只能扫描 Spring Boot 项目包内的 bean 并注册到 Spring 容器中,项目依赖包中的 bean 不会被扫描和注册。此时,我们需要使用 @EnableAutoConfiguration 注解来注册项目依赖包中的 bean。而 spring.factories 文件,可用来记录项目包外需要注册的 bean 类名。

使用 spring.factories 文件有什么好处呢?假如我们封装了一个插件,该插件提供给其他开发人员使用。我们可以在spring.factories 文件中指定需要自动注册到 Spring 容器的 bean 和一些配置信息。使用该插件的开发人员只需少许配置,甚至不进行任何配置也能正常使用。

2.Spring Boot的扩展机制之Spring Factories

写在前面:Spring Boot中有一种非常解耦的扩展机制:Spring Factories。这种扩展机制实际上是仿照Java中的SPI扩展机制来实现的。

2.1什么是 SPI机制

SPI的全名为Service Provider Interface.大多数开发人员可能不熟悉,因为这个是针对厂商或者插件的。在java.util.ServiceLoader的文档里有比较详细的介绍。
简单的总结下java SPI机制的思想。我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。
java SPI就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。

2.2 Spring Boot中的SPI机制

在Spring中也有一种类似与Java SPI的加载机制。它在META-INF/spring.factories文件中配置接口的实现类名称,然后在程序中读取这些配置文件并实例化。
这种自定义的SPI机制是Spring Boot Starter实现的基础。

2.3 Spring Factories实现原理是什么

spring-core包里定义了SpringFactoriesLoader类,这个类实现了检索META-INF/spring.factories文件,并获取指定接口的配置的功能。在这个类中定义了两个对外的方法:

loadFactories 根据接口类获取其实现类的实例,这个方法返回的是对象列表。
loadFactoryNames 根据接口获取其接口类的名称,这个方法返回的是类名的列表。
上面的两个方法的关键都是从指定的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解析得到的,所以我们在写文件中的内容都是安装下面这种方式配置的:

com.xxx.interface=com.xxx.classname

如果一个接口希望配置多个实现类,可以使用’,’进行分割。

2.4 Spring Factories在Spring Boot中的应用

在Spring Boot的很多包中都能够找到spring.factories文件,接下来我们以spring-boot包为例进行介绍

在日常工作中,我们可能需要实现一些SDK或者Spring Boot Starter给被人使用时,
我们就可以使用Factories机制。Factories机制可以让SDK或者Starter的使用只需要很少或者不需要进行配置,只需要在服务中引入我们的jar包即可。

3.用法及配置Bean

spring.factories 文件的用法,以及介绍该文件中可以配置那些 Bean。内容如下:

## 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

#后置环境变量处理器 org.springframework.boot.env.EnvironmentPostProcessor=cn.telecom.starter.cloud.LoadProperties

下面将分别介绍各种配置的具体含义:

3.1 ApplicationContextInitializer

该配置项用来配置实现了ApplicationContextInitializer 接口的类,这些类用来实现上下文初始化。配置如下:

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

配置应用程序监听器,该监听器必须实现 ApplicationListener 接口。它可以用来监听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("我故意抛出的错误,仅仅为了触发自定义 MyFailureAnalyzer"); } } }

3.3 AutoConfigurationImportListener

该配置项用来配置自动配置导入监听器,监听器必须实现AutoConfigurationImportListener 接口。该监听器可以监听 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

配置自动配置导入过滤器,过滤器必须实现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

配置自定的错误分析类,该分析器需要实现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

配置模板的可用性提供者,提供者需要实现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

环境后置处理器

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("动态加载自定义配置:" + 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(); } } }

文章内容来源:

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

Spring Boot 你不得不会的 spring.factories 配置 - 人人编程网

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/2 4:01:17

PDF-Extract-Kit教程:PDF文档图像质量增强方法

PDF-Extract-Kit教程&#xff1a;PDF文档图像质量增强方法 1. 引言 1.1 技术背景与应用场景 在数字化办公和学术研究中&#xff0c;PDF 文档已成为信息传递的核心载体。然而&#xff0c;许多 PDF 文件来源于扫描件或低分辨率图像&#xff0c;导致文字模糊、公式失真、表格变…

作者头像 李华
网站建设 2026/4/26 11:42:38

PDF-Extract-Kit性能测试:处理1000页PDF的实战报告

PDF-Extract-Kit性能测试&#xff1a;处理1000页PDF的实战报告 1. 背景与测试目标 1.1 PDF智能提取的技术挑战 在科研、教育和出版领域&#xff0c;大量非结构化文档以PDF格式存在。传统方法依赖人工摘录或基础OCR工具&#xff0c;难以应对复杂版式中的表格、公式、图文混排…

作者头像 李华
网站建设 2026/5/9 10:48:33

BRAM在图像处理缓存中的实现:完整示例解析

BRAM在图像处理缓存中的实战设计&#xff1a;从原理到可综合代码你有没有遇到过这样的问题——明明FPGA的逻辑资源还很充裕&#xff0c;但图像处理流水线却频频卡顿&#xff1f;像素流断了、卷积核等数据、边缘检测结果延迟飙升……最终发现&#xff0c;瓶颈不在算法&#xff0…

作者头像 李华
网站建设 2026/5/6 9:51:49

腾讯混元翻译1.5:少数民族语言支持实战

腾讯混元翻译1.5&#xff1a;少数民族语言支持实战 随着全球化与多语言交流的不断深化&#xff0c;高质量、低延迟的机器翻译需求日益增长。尤其在民族地区和跨文化场景中&#xff0c;对小语种与方言变体的支持成为技术落地的关键瓶颈。腾讯近期开源的混元翻译大模型 HY-MT1.5…

作者头像 李华
网站建设 2026/5/2 4:08:57

PDF智能提取工具箱实战:手写公式转LaTeX完整步骤

PDF智能提取工具箱实战&#xff1a;手写公式转LaTeX完整步骤 1. 引言&#xff1a;从扫描文档到结构化数据的智能化跃迁 在科研、教学和工程实践中&#xff0c;PDF文档中常包含大量手写或印刷体数学公式、表格和文本内容。传统方式下&#xff0c;将这些非结构化信息转化为可编…

作者头像 李华
网站建设 2026/5/2 2:01:51

STM32烧录必备:STLink驱动下载与配置实战案例

STM32烧录不翻车&#xff1a;STLink驱动安装与配置全实战指南 你有没有遇到过这样的场景&#xff1f; 新买了一块Nucleo开发板&#xff0c;兴冲冲插上USB线准备下载第一个“Hello World”程序&#xff0c;结果STM32CubeIDE弹出一串红字&#xff1a;“No target connected”。 …

作者头像 李华