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​、配置示例与可覆盖策略说明,便于团队接入与二次开发。
相关推荐
海边夕阳200622 分钟前
主流定时任务框架对比:Spring Task/Quartz/XXL-Job怎么选?
java·后端·spring·xxl-job·定时任务·job
q***985230 分钟前
VS Code 中如何运行Java SpringBoot的项目
java·开发语言·spring boot
帧栈40 分钟前
开发避坑指南(72):HttpHeaders 的add()方法和set()方法有什么区别?
java·spring·http
unclecss1 小时前
把 Spring Boot 的启动时间从 3 秒打到 30 毫秒,内存砍掉 80%,让 Java 在 Serverless 时代横着走
java·jvm·spring boot·serverless·graalvm
避避风港1 小时前
MySQL 从入门到实战
数据库·mysql
s***4531 小时前
MSSQL2022的一个错误:未在本地计算机上注册“Microsoft.ACE.OLEDB.16.0”提供程序
数据库·microsoft
tuokuac1 小时前
@PathVariable与@RequestParam
java·spring
q***16081 小时前
Tomcat的server.xml配置详解
xml·java·tomcat
程序员西西1 小时前
SpringBoot整合Apache Spark实现一个简单的数据分析功能
java·后端