news 2026/5/1 7:49:52

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/1 5:03:23

PDF-Extract-Kit实战案例:智能文档检索系统

PDF-Extract-Kit实战案例&#xff1a;智能文档检索系统 1. 引言 在科研、教育和企业办公场景中&#xff0c;PDF 文档作为知识传递的核心载体&#xff0c;往往包含大量结构化信息——如文字、表格、数学公式和图像。然而&#xff0c;传统方式难以高效提取这些内容并进行二次利…

作者头像 李华
网站建设 2026/4/30 3:08:47

从下载到运行:Proteus Windows安装完整示例

从零开始搭建电路仿真环境&#xff1a;Proteus Windows 安装与首个项目实战指南 你是不是也曾在学习单片机或做课程设计时&#xff0c;被“画错一根线就得重焊一遍”的现实折磨得够呛&#xff1f;有没有想过&#xff0c;在电脑上就能把整个电路连好、程序烧进去、还能用虚拟示…

作者头像 李华
网站建设 2026/3/4 14:40:55

基于TouchGFX的智能温控面板开发实战案例

从零打造专业级智能温控面板&#xff1a;TouchGFX STM32 实战全解析你有没有过这样的体验&#xff1f;家里的空调面板反应迟钝&#xff0c;调个温度要等半秒才动&#xff1b;或者工业设备上的操作屏&#xff0c;界面像十几年前的老家电&#xff0c;按钮生硬、动画卡顿。这些“…

作者头像 李华
网站建设 2026/4/26 20:34:03

混元翻译1.5模型对比:1.8B vs 7B选型指南

混元翻译1.5模型对比&#xff1a;1.8B vs 7B选型指南 随着多语言交流需求的持续增长&#xff0c;高质量、低延迟的机器翻译模型成为智能应用落地的关键基础设施。腾讯开源的混元翻译大模型&#xff08;HY-MT1.5&#xff09;系列在近期发布了两个核心版本&#xff1a;HY-MT1.5-…

作者头像 李华
网站建设 2026/4/23 12:32:53

PDF智能提取工具箱实战:医学报告关键指标提取

PDF智能提取工具箱实战&#xff1a;医学报告关键指标提取 1. 引言&#xff1a;医学报告结构化提取的挑战与解决方案 在医疗信息化进程中&#xff0c;大量临床数据以非结构化的PDF格式存储&#xff0c;尤其是体检报告、检验单、影像诊断书等关键文档。这些文档中蕴含着血压、血…

作者头像 李华
网站建设 2026/4/18 13:28:55

image2lcd在OLED显示驱动中的实战案例详解

从一张图片到OLED屏幕&#xff1a;用image2lcd打通嵌入式图形显示的“最后一公里”你有没有过这样的经历&#xff1f;UI设计师发来一个精致的Logo PNG图&#xff0c;说&#xff1a;“这个要显示在设备开机画面上。”你打开工程&#xff0c;心想&#xff1a;好家伙&#xff0c;怎…

作者头像 李华