






















在 Java 生态中,SPI(Service Provider Interface) 是一种服务发现机制,允许框架或接口定义方通过配置文件指定接口的实现类,第三方可以通过实现接口并配置文件来扩展功能,实现 “接口与实现分离”。Dubbo、Spring、SpringBoot 均基于 SPI 思想设计了各自的扩展机制,但实现方式和应用场景有所不同。
在讲框架的 SPI 前,先了解 Java 原生 SPI,因为框架的 SPI 多基于其思想扩展:
核心目的:允许服务提供者(第三方)为接口提供实现,接口调用方通过标准方式加载实现类。
实现方式:
com.example.MyService);com.example.impl.MyServiceImpl);META-INF/services/ 目录下创建以接口全类名为文件名的文件(如 com.example.MyService),文件内容为实现类的全类名(com.example.impl.MyServiceImpl);ServiceLoader.load(MyService.class) 加载所有实现类。缺点:
Dubbo 基于 Java 原生 SPI 做了增强,解决了原生 SPI 的缺陷,是 Dubbo 扩展机制的核心(如协议、注册中心、序列化等均通过 SPI 扩展)。
META-INF/dubbo/、META-INF/dubbo/internal/、META-INF/services/ 目录下(优先级依次降低)。接口全类名 作为文件名,文件内容为 扩展键=实现类全类名(如 dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol)。ExtensionLoader,负责加载、缓存、管理扩展类,支持:
@Adaptive 注解动态生成自适应实现类(根据运行时参数选择具体实现);@Activate 注解指定条件(如 URL 参数、分组)激活扩展。以扩展 Dubbo 的协议(Protocol 接口)为例:
定义扩展接口(若扩展已有接口,可跳过此步,直接实现 Dubbo 内置接口):
// 需用@SPI注解标记为Dubbo SPI接口
@SPI("myprotocol")
实现接口:
public class MyProtocol implements Protocol {
@Override
public String export() {
return "自定义协议实现";
}
}
配置扩展文件:在项目 resources/META-INF/dubbo/ 目录下创建文件 org.apache.dubbo.rpc.Protocol(Dubbo 内置 Protocol 接口的全类名),内容为:
myprotocol=com.example.MyProtocol # 扩展键=实现类全类名
使用扩展:通过 ExtensionLoader 加载指定扩展:
ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);
Protocol protocol = loader.getExtension("myprotocol");
Spring 的 SPI 机制称为 “Factories 机制”,核心用于框架内部的扩展点发现(如第三方组件集成 Spring 时,提供自定义的初始化器、监听器等)。
ApplicationContextInitializer、BeanFactoryPostProcessor 等)。META-INF/spring.factories(固定路径和文件名)。org.springframework.context.ApplicationContextInitializer=com.example.MyApplicationContextInitializer
SpringFactoriesLoader,通过 loadFactories(Class<T> factoryType, ClassLoader classLoader) 方法加载指定类型的所有实现类。以扩展 ApplicationContextInitializer(Spring 上下文初始化器)为例:
实现 Spring 扩展接口:
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("自定义初始化器:初始化Spring上下文");
}
}
配置 spring.factories:在项目 resources/META-INF/ 目录下创建 spring.factories 文件,内容为:
org.springframework.context.ApplicationContextInitializer=com.example.MyApplicationContextInitializer
使用扩展:当 Spring 容器启动时,SpringFactoriesLoader 会自动加载 MyApplicationContextInitializer 并执行其 initialize 方法。
SpringBoot 的 SPI 机制是对 Spring Factories 的进一步强化,核心用于自动配置(AutoConfiguration) 和第三方 Starter 的扩展,是 SpringBoot “约定大于配置” 的核心实现。
META-INF/spring.factories 或 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(SpringBoot 2.7 + 推荐后者,格式更简单)。org.springframework.boot.autoconfigure.EnableAutoConfiguration:指定自动配置类(最核心);org.springframework.boot.env.EnvironmentPostProcessor:环境变量处理;org.springframework.boot.diagnostics.FailureAnalyzer:启动错误分析等。SpringFactoriesLoader 加载 EnableAutoConfiguration 对应的自动配置类,结合 @Conditional 条件注解(如 @ConditionalOnClass、@ConditionalOnMissingBean)判断是否生效,最终向容器注册 Bean。以自定义一个 “示例 Starter” 为例,实现自动配置 Bean:
创建自动配置类:
@Configuration
@ConditionalOnClass(MyService.class)
配置自动配置类:
resources/META-INF/spring/ 目录下创建 org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件,内容为自动配置类全类名:
com.example.MyAutoConfiguration
META-INF/spring.factories 中配置:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.MyAutoConfiguration
使用扩展:其他项目引入该 Starter 后,SpringBoot 启动时会自动加载 MyAutoConfiguration,并在满足条件时注册 MyService 到容器,直接注入即可使用:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
MyService service = context.getBean(MyService.class);
System.out.println(service.hello());
| 特性 | Dubbo SPI | Spring Factories | SpringBoot SPI(基于 Spring) |
|---|---|---|---|
扩展时需根据框架特性,遵循其配置规范和加载逻辑即可。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。