Spring Boot SPI 教程

​​​一 概念与版本差异​

  • ​SPI(Service Provider Interface)​ 是一种在运行时发现并加载服务实现的机制,核心是"​接口与实现分离​ "。在 ​JDK​ 中通过 ​META-INF/services/接口全限定名​ 文件与 ​ServiceLoader​ 实现;在 ​Spring Boot​ 中扩展了该思想,使用 ​META-INF/spring.factories​​SpringFactoriesLoader​ 来批量加载自动配置、监听器等扩展点。自 ​Spring Boot 2.7​ 起,官方为自动配置新增了 ​META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports​ 文件以替代 spring.factories 的自动配置注册方式,二者可并存(老项目仍可用 spring.factories)。Spring 的 SPI 加载机制与 IoC 容器深度集成,支持按条件加载与更灵活的实例化策略。

​二 两种 SPI 用法速览​

原生 Java SPI

  • 约定路径:​META-INF/services/接口全限定名​ ;内容为每行一个​实现类全限定名​
  • 加载方式:​ServiceLoader.load(接口.class)​,迭代器按需实例化实现类(延迟加载、默认无参构造)。
  • 适用:与容器无关、轻量插件发现。

Spring Boot SPI

  • 约定路径与方式:
    • 自动配置:Spring Boot 2.7+ 使用 ​META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports​ (每行一个自动配置类);2.7 之前使用 ​META-INF/spring.factories​​org.springframework.boot.autoconfigure.EnableAutoConfiguration​ 键。
    • 其他扩展点:在 ​META-INF/spring.factories​ 中以键值对注册(如 ​ApplicationListener​、自定义扩展接口)。
  • 加载方式:​SpringFactoriesLoader.loadFactories/loadFactoryNames​ 读取并实例化,可与 Spring 条件注解、环境集成。

​三 实战一 自定义 Starter 并启用自动配置(Spring Boot 2.7+)​

步骤

  1. 新建模块(如 ​my-spi-starter​ ),无需启动类;添加依赖:
    • ​spring-boot-autoconfigure​
    • (可选)​spring-boot-configuration-processor​(生成配置元数据)
  2. 定义业务接口与实现:
    • 接口:​com.example.spi.GreetingService​
    • 实现:​com.example.spi.impl.EnglishGreetingService​​ChineseGreetingService​
  3. 编写自动配置类:
    • 路径:​com.example.spi.config.GreetingAutoConfiguration​
    • 要点:使用 ​@Configuration​ 、条件注解(如 ​@ConditionalOnClass​ )、以及 ​@ConditionalOnMissingBean​ 保证用户可覆盖默认 Bean。
  4. 注册自动配置:在 ​resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports​ 写入自动配置类全限定名(每行一个)。
  5. 使用:在业务项目中引入 starter 依赖,按类型注入 ​GreetingService​ 即可使用(若用户自行定义了同类型 Bean,则以用户 Bean 为准)。

关键文件示例

  • AutoConfiguration.imports

    java 复制代码
    com.example.spi.config.GreetingAutoConfiguration
  • GreetingAutoConfiguration.java

    java 复制代码
    @Configuration
    @ConditionalOnClass(GreetingService.class)
    public class GreetingAutoConfiguration {
    
        @Bean
        @ConditionalOnMissingBean
        public GreetingService greetingService() {
            // 可按条件选择默认实现,或返回抽象工厂
            return new EnglishGreetingService();
        }
    }

说明

  • 若需兼容 ​Spring Boot <2.7​ ,可在同模块 ​resources/META-INF/spring.factories​ 增加:

    java 复制代码
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
      com.example.spi.config.GreetingAutoConfiguration
  • 条件注解(如 ​@ConditionalOnClass/@ConditionalOnMissingBean​)是编写自动配置的最佳实践,可避免冲突并提升可覆盖性。

​四 实战二 使用 Java SPI 插件机制​

步骤

  1. 定义插件接口:​com.example.spi.Plugin​

  2. 多个实现:​com.example.spi.impl.PluginA​​PluginB​

  3. 注册插件:在 ​resources/META-INF/services/com.example.spi.Plugin​ 写入实现类全限定名(每行一个)。

  4. 加载插件(可在任意 Spring Bean 中):

    java 复制代码
    import java.util.ServiceLoader;
    
    ServiceLoader<Plugin> loader = ServiceLoader.load(Plugin.class);
    for (Plugin p : loader) {
        p.execute();
    }

适用场景

  • 与 Spring 容器解耦的纯发现机制;若需要依赖注入、AOP、条件控制,优先考虑 Spring Boot 的 ​SpringFactoriesLoader​ 或在自动配置中封装 [ServiceLoader]。

​五 常见问题与最佳实践​

版本与路径

  • ​Spring Boot 2.7+​ 推荐将自动配置写入 ​META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports​ ;老项目或第三方库仍可能使用 ​META-INF/spring.factories​,注意维护兼容性。

条件装配

  • 在自动配置类上使用 ​@ConditionalOnClass/@ConditionalOnMissingBean​ 等,明确生效条件与可覆盖性,避免与用户配置冲突。

避免类路径冲突

  • 明确依赖版本与导出包,防止不同 JAR 提供同名实现导致不可预期行为。

扩展点选择

  • 启动生命周期、环境处理等框架扩展点可用 ​spring.factories​ 注册(如 ​SpringApplicationRunListener​​EnvironmentPostProcessor​ );业务插件发现可用 ​Java SPI​​SpringFactoriesLoader​

可维护性与文档

  • 为自定义 ​Starter​ 提供清晰的 ​README​、配置示例与可覆盖策略说明,便于团队接入与二次开发。
相关推荐
努力努力再努力wz几秒前
【Linux网络系列】:网络+网络编程(UDPsocket+TCPsocket)
java·linux·c语言·开发语言·数据结构·c++·centos
占疏3 分钟前
流程图编辑
java·数据库·sql
heartbeat..4 分钟前
Java List 完全指南:从接口特性到四大实现类深度解析
java·list
韩立学长6 分钟前
【开题答辩实录分享】以《智慧酒店管理——手机预订和住宿管理》为例进行选题答辩实录分享
android·java·后端
何中应6 分钟前
【面试题-8】Spring/Spring MVC/Spring Boot/Spring Cloud
java·spring boot·后端·spring·mvc·面试题
坐不住的爱码6 分钟前
mybatis-动态sql语句-<foreach>
java·sql·mybatis
while(1){yan}10 分钟前
HTTP的数据报格式
java·开发语言·网络·网络协议·http·青少年编程·面试
ID_1800790547312 分钟前
淘宝关键词搜索 API 系列 数据返回参考(附解析与实战)
java·服务器·前端
Neolnfra14 分钟前
SMB、FTP、MySQL... 配置不当,即是漏洞
linux·数据库·mysql·安全·网络安全·系统安全·安全架构
雷神乐乐14 分钟前
Mysql数据泵导入导出数据
数据库·oracle