news 2026/10/20 8:16:21

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/10/17 23:20:46

科哥PDF工具箱教程:自动化脚本批量处理PDF

科哥PDF工具箱教程&#xff1a;自动化脚本批量处理PDF 1. 引言 1.1 PDF-Extract-Kit&#xff1a;智能提取的工程化实践 在科研、教育和文档数字化场景中&#xff0c;PDF 文件常包含复杂的结构元素——公式、表格、图文混排等。传统手动提取方式效率低、易出错&#xff0c;难…

作者头像 李华
网站建设 2026/10/13 10:49:02

Spring 的三种注入方式?

1. 实例的注入方式 首先来看看 Spring 中的实例该如何注入&#xff0c;总结起来&#xff0c;无非三种&#xff1a;属性注入set 方法注入构造方法注入我们分别来看下。 1.1 属性注入 属性注入是大家最为常见也是使用最多的一种注入方式了&#xff0c;代码如下&#xff1a; Servi…

作者头像 李华
网站建设 2026/10/13 10:49:14

基于深度学习 YOLOv8➕pyqt5的西红柿成熟度检测系统

基于深度学习 YOLOv8➕pyqt5的西红柿成熟度检测系统&#xff0c; 完整源码源文件已标注的数据集训练好的模型环境配置教程程序运行说明文档 可以替换自己训练的模型&#xff0c;实现检测目标自定义 blog.csdnimg.cn/direct/31c61653310648458126c961a01fd682.png) 以下文章及示…

作者头像 李华
网站建设 2026/10/19 8:56:44

HY-MT1.5部署实战:5分钟搭建企业级翻译系统

HY-MT1.5部署实战&#xff1a;5分钟搭建企业级翻译系统 在AI驱动的全球化浪潮中&#xff0c;高质量、低延迟的机器翻译能力已成为企业出海、跨语言协作的核心基础设施。腾讯近期开源的混元翻译大模型HY-MT1.5系列&#xff0c;凭借其卓越的翻译质量与灵活的部署能力&#xff0c…

作者头像 李华
网站建设 2026/10/13 10:49:03

PDF-Extract-Kit性能对比测试:不同硬件配置下的表现

PDF-Extract-Kit性能对比测试&#xff1a;不同硬件配置下的表现 1. 引言 1.1 技术背景与选型需求 在当前AI驱动的文档智能处理领域&#xff0c;PDF内容提取已成为科研、教育、出版等多个行业的重要基础能力。传统OCR工具虽能完成基本文字识别&#xff0c;但在面对复杂版式、…

作者头像 李华