spring 不直接使用 java 原生 serviceloader,而是通过 meta-inf/spring.factories 文件与 springfactoriesloader 实现更灵活的扩展机制:该文件以键值对形式声明扩展点及其对应类,支持多值、跨 jar 加载和自动合并;springfactoriesloader 负责扫描、解析并实例化,将其无缝嵌入容器生命周期各阶段,实现“引入即生效”。

Spring 并不直接使用 Java 原生的 ServiceLoader(即标准 SPI),而是基于类似思想,自研了一套更灵活、更适配 Spring 生态的扩展机制——通过 META-INF/spring.factories 文件 + SpringFactoriesLoader 类实现动态加载。
spring.factories 是配置入口
这个文件放在 jar 包的 META-INF/ 目录下,格式是标准 Properties:
键是接口或抽象类的全限定名,值是对应实现类的全限定名,多个用逗号分隔。例如:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.MyAutoConfig,com.example.AnotherConfigorg.springframework.context.ApplicationContextInitializer=org.example.MyInitializerorg.springframework.boot.SpringApplicationRunListener=org.example.CustomRunListener
它不依赖 META-INF/services/ 路径,也不受 Java SPI 双亲委派限制,能跨 jar 加载,且支持同名 key 多次出现(自动合并)。
SpringFactoriesLoader 负责解析与实例化
核心类在 spring-core 中,提供两个关键静态方法:
-
loadFactoryNames(Class<t> factoryClass, ClassLoader classLoader)</t>:只读取类名列表,不实例化,适合做预判或过滤 -
loadFactories(Class<t> factoryClass, ClassLoader classLoader)</t>:根据类名反射创建实例,返回List<t></t>
它会遍历当前 ClassLoader 所有可见的 jar 和 classpath 路径,收集所有 META-INF/spring.factories 文件,逐个解析匹配 key,再统一去重、排序(按声明顺序)、实例化。
插件被纳入 Spring 容器生命周期
单纯加载出来还不够,Spring 会把它们嵌入到关键流程中:
-
ApplicationContextInitializer:在上下文刷新前执行,可用于修改环境或注册额外 bean 定义 -
ApplicationRunner/CommandLineRunner:启动后立即运行,适合初始化任务 -
SpringApplicationRunListener:监听 SpringApplication 的各个阶段(starting、environmentPrepared、contextPrepared 等) -
EnableAutoConfiguration对应的自动配置类:由@EnableAutoConfiguration触发,经AutoConfigurationImportSelector解析后注入容器
这些扩展点不是靠开发者手动注册,而是框架在启动时自动发现、排序、调用,真正做到了“引入即生效”。
为什么比原生 SPI 更适合 Spring?
Java 原生 SPI 要求 META-INF/services/接口名,且只支持单个实现类(或需自行遍历),还受限于类加载器层级。而 Spring 的方案:
- 配置集中、可多值、易维护
- 支持任意抽象类型(接口、抽象类、甚至普通类作为工厂)
- 加载时机可控,可配合 Spring 的 BeanFactory、Environment、Condition 等机制做条件化加载
- 天然兼容 Starter 模式:一个 starter jar 只需打包好
spring.factories和对应类,使用者引入依赖就自动生效
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











