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​、配置示例与可覆盖策略说明,便于团队接入与二次开发。
相关推荐
YOU OU12 小时前
Redis基础常识与命令
数据库·redis·缓存
腻害兔12 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社13 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
萧瑟余晖14 小时前
JDK 26 新特性详解
java·开发语言
Database_Cool_14 小时前
OLTP 和 OLAP 区别详解:分析型数据库和事务型数据库怎么选(附阿里云 AnalyticDB MySQL 选型指南)
数据库·mysql·阿里云
爱写代码的阿森14 小时前
鸿蒙三方库 | harmony-utils之KvUtil键值型数据库操作详解
数据库·华为·harmonyos·鸿蒙·huawei
马优晨14 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
Database_Cool_15 小时前
单机 MySQL 迁移到分布式数据库方便吗?阿里云 PolarDB-X 100% MySQL 协议兼容零改造平滑迁移
数据库·分布式·mysql
姜太小白15 小时前
【MySQL】 索引优化实战:解决 WHERE 等值 + IS NULL 查询,TEXT 字段报错 1167 的完整指南
数据库·mysql