《Spring核心机制》第六篇:一篇读懂 SPI
在 Spring 生态中,经常听到一句话:
“Spring 之所以强大,很大程度上是因为它把扩展点做得非常彻底,而这些扩展点绝大多数都是通过 SPI 机制来实现的。”
今天我们就来彻底搞清楚:Spring 到底是怎么玩 SPI 的?
1. 什么是 Java SPI?(基础回顾)
Java SPI 全称:Service Provider Interface
核心思想一句话总结:
“接口定义在核心包里,实现类写在第三方 jar 包里,通过配置文件让系统自动发现并加载这些实现。”
经典的配置文件位置(JDK 标准):
META-INF/services/接口全限定名
文件内容示例(一行一个实现类全限定名):
com.mysql.cj.jdbc.Driver
org.postgresql.Driver
JDK 加载方式:
ServiceLoader.load(Driver.class)
.forEach(driver -> System.out.println(driver.getClass().getName()));
2. Spring 是怎么“玩坏”Java SPI 的?
Spring 并没有完全沿用 JDK 原生的 ServiceLoader,而是自己实现了一套更强大、更灵活的 Spring Factories 机制(也被称为 Spring SPI)。
最核心的区别对比:
| 特性 | JDK 原生 SPI (ServiceLoader) | Spring Factories (Spring SPI) | 谁更强? |
|---|---|---|---|
| 配置文件位置 | META-INF/services/ | META-INF/spring.factories | Spring |
| 配置文件格式 | 纯文本,一行一个实现类 | Properties 格式,支持 key=value | Spring |
| 一个接口允许多个实现 | 是 | 是,且更友好(可以按 key 分类) | Spring |
| 支持按 key 分组 | 不支持 | 支持(同一个文件里可以定义很多不同种类的 SPI) | Spring 大胜 |
| 支持排序/优先级 | 不支持(加载顺序不确定) | 支持 @Order / Ordered 接口 | Spring |
| 支持条件装配 | 不支持 | 支持 @Conditional 等条件注解 | Spring |
| 懒加载 | 部分支持(迭代时才加载) | 支持延迟加载(Spring Boot 更进一步) | Spring Boot |
| 循环依赖/重复加载问题 | 容易出现问题 | 框架层面做了大量优化与保护 | Spring |
| 当前主流使用量 | JDBC、JDBC驱动、日志框架等 | Spring 全家桶几乎全部依赖它 | Spring 完胜 |
3. Spring Boot 中最常见的 spring.factories 内容示例
# 核心配置类加载器(最重要的一行,几乎所有 Spring Boot 项目都会用到)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
...
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# 模板解析器(Thymeleaf、FreeMarker 等)
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
...
# 嵌入式容器工厂
org.springframework.boot.web.embedded.EmbeddedWebServerFactoryCustomizer=\
...
一句话总结 spring.factories 的地位:
它就是 Spring Boot 自动配置的“大脑”和“插件注册表”
4. Spring SPI 的几种典型使用场景对比
| 使用场景 | 典型 key(接口) | 典型实现类举例 | 加载时机 |
|---|---|---|---|
| 自动配置 | EnableAutoConfiguration | xxxAutoConfiguration | 容器启动早期 |
| 初始化器 | ApplicationContextInitializer | ConfigDataApplicationContextInitializer | 非常早期 |
| 监听器 | ApplicationListener | LoggingApplicationListener | 容器生命周期各个阶段 |
| BeanFactoryPostProcessor | BeanFactoryPostProcessor | PropertySourcesPlaceholderConfigurer | Bean 定义阶段 |
| BeanPostProcessor | BeanPostProcessor | AutowiredAnnotationBeanPostProcessor | Bean 初始化前后 |
| 嵌入式容器自定义 | WebServerFactoryCustomizer | TomcatServletWebServerFactoryCustomizer | Web 容器启动时 |
| 自定义 HealthIndicator | HealthIndicator | DiskSpaceHealthIndicator | Actuator 健康检查时 |
5. 面试/实战最常被问的几个 SPI 相关问题
Q1:Spring Boot 是怎么做到“引入一个 starter 就自动配置”的?
A:靠的就是 spring.factories 中的 EnableAutoConfiguration 那一行。
Spring Boot 启动时会读取所有 jar 包里的 spring.factories,把所有自动配置类收集起来,然后根据 @Conditional 条件决定哪些生效。
Q2:为什么不直接用 JDK SPI?
A:
- JDK SPI 不支持分组(所有实现都一股脑加载)
- 没有优先级控制
- 没有条件加载能力
- 加载时机和方式不够灵活
Q3:如果我自己写一个 starter,应该怎么定义 SPI?
最常见的三种方式(推荐顺序):
# 方式1:最推荐(自动配置)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.yourcompany.yourstarter.YourAutoConfiguration
# 方式2:自定义初始化器(极早期介入)
org.springframework.context.ApplicationContextInitializer=\
com.yourcompany.yourstarter.YourInitializer
# 方式3:自定义监听器
org.springframework.context.ApplicationListener=\
com.yourcompany.yourstarter.YourListener
6. 2025-2026 年的新趋势(小彩蛋)
- Spring Boot 3.x + GraalVM:很多自动配置类开始使用
@NativeHint来配合原生编译 - 模块化 starter:越来越多的 starter 采用“分层 SPI”设计(核心 + 可选扩展)
- 函数式 + SPI:Spring Boot 3.x 中大量使用函数式 Bean 定义,也会结合 spring.factories 注册
- eBPF + Spring:部分云原生场景开始通过 eBPF 动态注册/替换 Spring 的 SPI 实现(实验阶段)
一句话总结本篇核心认知:
Spring 之所以能做到“高度可扩展却又使用简单”,最核心的秘密武器之一,就是它把 Java SPI 升级成了功能强大、分类清晰、条件丰富、优先级可控的 Spring Factories 机制。
下一期想看什么?
- Spring 的 @Conditional 家族全家桶深度解析
- EnableAutoConfiguration 背后的加载原理与源码流程
- 如何优雅地自定义一个高质量 Spring Boot Starter(包含 SPI 实践)
- Spring Factories 与 JDK SPI、Dubbo SPI、OSGi 的终极对比
告诉我你的选择~