Java dubbo spring springboot中的spi機制
在 Java 生態中,SPI(Service Provider Interface) 是一種服務發現機制,允許框架或接口定義方通過配置文件指定接口的實現類,第三方可以通過實現接口并配置文件來擴展功能,實現 “接口與實現分離”。Dubbo、Spring、SpringBoot 均基于 SPI 思想設計了各自的擴展機制,但實現方式和應用場景有所不同。
一、Java 原生 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)加載所有實現類。
- 定義接口(如
-
缺點:
- 一次性加載所有實現類,無法按需加載(浪費資源);
- 無緩存機制,每次加載都重新實例化;
- 不支持 IOC、AOP 等增強。
二、Dubbo 的 SPI 機制
Dubbo 基于 Java 原生 SPI 做了增強,解決了原生 SPI 的缺陷,是 Dubbo 擴展機制的核心(如協議、注冊中心、序列化等均通過 SPI 擴展)。
1. 實現原理
- 配置文件位置:擴展配置文件放在
META-INF/dubbo/、META-INF/dubbo/internal/、META-INF/services/目錄下(優先級依次降低)。 - 配置文件格式:鍵值對形式(區別于 Java 原生的純實現類),格式為
接口全類名作為文件名,文件內容為擴展鍵=實現類全類名(如dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol)。 - 核心類:
ExtensionLoader,負責加載、緩存、管理擴展類,支持:- 按需加載:通過 “擴展鍵” 只加載指定實現類(而非全部);
- IOC 依賴注入:自動注入擴展類的其他依賴(通過 setter 方法);
- AOP 增強:支持對擴展類生成代理(如 Wrapper 包裝類);
- 自適應擴展:通過
@Adaptive注解動態生成自適應實現類(根據運行時參數選擇具體實現); - 激活擴展:通過
@Activate注解指定條件(如 URL 參數、分組)激活擴展。
2. 擴展方式(自定義 Dubbo 擴展)
以擴展 Dubbo 的協議(
Protocol 接口)為例:-
定義擴展接口(若擴展已有接口,可跳過此步,直接實現 Dubbo 內置接口):
// 需用@SPI注解標記為Dubbo SPI接口 @SPI("myprotocol") // 默認擴展鍵 public interface Protocol { String export(); } -
實現接口:
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"); // 通過擴展鍵加載 System.out.println(protocol.export()); // 輸出:自定義協議實現
三、Spring 的 SPI 機制(Factories 機制)
Spring 的 SPI 機制稱為 “Factories 機制”,核心用于框架內部的擴展點發現(如第三方組件集成 Spring 時,提供自定義的初始化器、監聽器等)。
1. 實現原理
- 核心目的:允許第三方通過配置文件向 Spring 注冊接口實現類(如
ApplicationContextInitializer、BeanFactoryPostProcessor等)。 - 配置文件位置:
META-INF/spring.factories(固定路徑和文件名)。 - 配置文件格式:鍵值對形式,鍵為 “接口 / 類全類名”,值為 “實現類全類名列表”(用逗號分隔),例如:
org.springframework.context.ApplicationContextInitializer=com.example.MyApplicationContextInitializer - 核心類:
SpringFactoriesLoader,通過loadFactories(Class<T> factoryType, ClassLoader classLoader)方法加載指定類型的所有實現類。
2. 擴展方式(自定義 Spring 擴展)
以擴展
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 擴展)
SpringBoot 的 SPI 機制是對 Spring Factories 的進一步強化,核心用于自動配置(AutoConfiguration) 和第三方 Starter 的擴展,是 SpringBoot “約定大于配置” 的核心實現。
1. 實現原理
- 核心目的:通過配置文件自動注冊 Bean、啟用功能(如自動配置類、條件注解等)。
- 配置文件位置:
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:啟動錯誤分析等。
- 加載邏輯:SpringBoot 啟動時,通過
SpringFactoriesLoader加載EnableAutoConfiguration對應的自動配置類,結合@Conditional條件注解(如@ConditionalOnClass、@ConditionalOnMissingBean)判斷是否生效,最終向容器注冊 Bean。
2. 擴展方式(自定義 SpringBoot Starter)
以自定義一個 “示例 Starter” 為例,實現自動配置 Bean:
-
創建自動配置類:
@Configuration @ConditionalOnClass(MyService.class) // 當類路徑存在MyService時生效 public class MyAutoConfiguration { @Bean @ConditionalOnMissingBean // 當容器中沒有MyService時才注冊 public MyService myService() { return new MyService(); } } public class MyService { public String hello() { return "自定義Starter:Hello"; } } -
配置自動配置類:
- SpringBoot 2.7+:在
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
- SpringBoot 2.7+:在
-
使用擴展:其他項目引入該 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()); // 輸出:自定義Starter:Hello } }
總結:三者 SPI 的核心差異
| 特性 | Dubbo SPI | Spring Factories | SpringBoot SPI(基于 Spring) |
|---|---|---|---|
| 配置文件位置 | META-INF/dubbo/ 等 | META-INF/spring.factories | META-INF/spring/imports 或 factories |
| 配置格式 | 鍵值對(擴展鍵 = 實現類) | 鍵值對(接口 = 實現類列表) | 純實現類列表(2.7+)或鍵值對 |
| 核心能力 | 按需加載、IOC、AOP、自適應擴展 | 服務發現(擴展點注冊) | 自動配置、條件注冊 Bean |
| 典型場景 | 協議、注冊中心等 Dubbo 組件擴展 | Spring 上下文初始化器等擴展 | 自定義 Starter、自動配置功能 |
擴展時需根據框架特性,遵循其配置規范和加載邏輯即可。
郭慕榮博客園

浙公網安備 33010602011771號