首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >[Java]Java SPI机制

[Java]Java SPI机制

作者头像
master336
发布2026-06-15 19:33:31
发布2026-06-15 19:33:31
650
举报
目录

  • 基础环境
  • 概念
  • 实践
    • SPI规范
    • SPI设计思想
    • 代码实践
      • 项目结构:
      • 定义Serivece
      • 定义Serivece Provider
        • 接口实现类(定义三个)
        • 抽象类实现类
        • 子类重写
      • 编写测试应用
      • 执行结果
  • 扩展使用
  • 代码地址

基础环境

JDK 1.8

概念

SPI(Service Provider Interface): 服务提供接口,是JDK提供的一种服务加载机制,简单理解就是通过此JDK规范可实现服务的发现并加载。主要有三部分组成: Service: 服务,更准确来说是服务定义,可以接口、抽象类,同样可以是普通的类(服务提供者为其子类,不过一般不这么来定义) Service Provider: 服务提供者,可以是Service接口实现类,Service抽象类的实现,以及Service类的继承 ServiceLoader: 一个简单的服务提供者加载工具

原始的参考资料可参考JDK源码中对java.util.ServiceLoader的描述。

在这里插入图片描述
在这里插入图片描述

实践

SPI规范

  1. 配置文件路径: Service Provider声明配置文件必须在META-INF/services 目录下;
  2. 配置文件名称: Service接口、实现类等全限定类名
  3. 配置文件内容:Service实现类(一个实现类一行)
  4. 保证实现类jar包被正确加载(放置classpath中或自定义Class Loader保证加载)
  5. 实现类提供无参构造方法 参考示例:
在这里插入图片描述
在这里插入图片描述

SPI设计思想

面向接口编程、接口隔离原则(ISP)

代码实践

项目结构:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
定义Serivece
  1. 接口cn.com.demo.api.ISpiDemo
代码语言:javascript
复制
package cn.com.demo.api;

public interface ISpiDemo {
    String name();
    String exec(String msg);
}
  1. 抽象类 cn.com.demo.api.AnstractSpiDemo
代码语言:javascript
复制
package cn.com.demo.api;

public abstract class AnstractSpiDemo {
   public abstract String sayHello();
}
  1. 普通类 cn.com.demo.api.SpiDemo
代码语言:javascript
复制
package cn.com.demo.api;

public class SpiDemo {
   public String sayHello(){
       return this.getClass().getSimpleName();
   }
}
定义Serivece Provider
接口实现类(定义三个)

cn.com.demo.impl.Hello0ISpiDemo

代码语言:javascript
复制
package cn.com.demo.impl;

import cn.com.demo.api.ISpiDemo;

public class Hello0ISpiDemo implements ISpiDemo {
   @Override
   public String name() {
       return this.getClass().getSimpleName();
   }

   @Override
   public String exec(String msg) {
       return name()+msg;
   }
}

cn.com.demo.impl.Hello1ISpiDemo

代码语言:javascript
复制
package cn.com.demo.impl;

import cn.com.demo.api.ISpiDemo;

public class Hello1ISpiDemo implements ISpiDemo {
  @Override
  public String name() {
      return this.getClass().getSimpleName();
  }

  @Override
  public String exec(String msg) {
      return name()+msg;
  }
}

cn.com.demo.impl.Hello2ISpiDemo

代码语言:javascript
复制
package cn.com.demo.impl;

import cn.com.demo.api.ISpiDemo;

public class Hello2ISpiDemo implements ISpiDemo {
  @Override
  public String name() {
      return this.getClass().getSimpleName();
  }

  @Override
  public String exec(String msg) {
      return name()+msg;
  }
}

META-INF/services/下定义 文件名:cn.com.demo.api.ISpiDemo 文件内容:

代码语言:javascript
复制
cn.com.demo.impl.Hello1ISpiDemo
cn.com.demo.impl.Hello2ISpiDemo
在这里插入图片描述
在这里插入图片描述

注意: 这里的cn.com.demo.impl.Hello0ISpiDemo未被定义到services文件中,应用将不会注册此类。

抽象类实现类

cn.com.demo.impl.AnstractSpiDemoImpl

代码语言:javascript
复制
package cn.com.demo.impl;

import cn.com.demo.api.AnstractSpiDemo;

public class AnstractSpiDemoImpl extends AnstractSpiDemo {
   @Override
   public String sayHello() {
       return this.getClass().getSimpleName();
   }
}

META-INF/services/下定义 文件名:cn.com.demo.api.AnstractSpiDemo 文件内容:

代码语言:javascript
复制
cn.com.demo.impl.AnstractSpiDemoImpl
在这里插入图片描述
在这里插入图片描述
子类重写

cn.com.demo.impl.SpiDemoChild

代码语言:javascript
复制
package cn.com.demo.impl;

import cn.com.demo.api.SpiDemo;

public class SpiDemoChild extends SpiDemo {
    @Override
    public String sayHello() {
        return  this.getClass().getSimpleName();
    }
}

META-INF/services/下定义 文件名:cn.com.demo.api.SpiDemo 文件内容:

代码语言:javascript
复制
cn.com.demo.impl.SpiDemoChild
在这里插入图片描述
在这里插入图片描述
编写测试应用

cn.com.demo.app.SpiTest

代码语言:javascript
复制
package cn.com.demo.app;

import cn.com.demo.api.ISpiDemo;
import cn.com.demo.api.SpiDemo;
import cn.com.demo.api.AnstractSpiDemo;
import lombok.extern.java.Log;

import java.util.ServiceLoader;

@Log
public class SpiTest {
    public static void main(String[] args) {
        ServiceLoader<ISpiDemo> load = ServiceLoader.load(ISpiDemo.class);
        for (ISpiDemo spiDemo : load) {
            log.info(spiDemo.name()+"-"+spiDemo);
        }
        log.info("------------------------------");
        ServiceLoader<AnstractSpiDemo> loader = ServiceLoader.load(AnstractSpiDemo.class);
        for (AnstractSpiDemo spiDemoC : loader) {
            log.info(spiDemoC.sayHello());
        }
        log.info("------------------------------");
        ServiceLoader<SpiDemo> loader1 = ServiceLoader.load(SpiDemo.class);
        for (SpiDemo spiDemo : loader1) {
            log.info(spiDemo.sayHello());
        }

    }
}
执行结果
在这里插入图片描述
在这里插入图片描述

扩展使用

  1. 利用spi的加载机制,在Class Loader加载和实例化时,可在静态代码块、非静态代码块、无参构造等处做服务的初始化工作,如JDBC4.0规范之后不再需要Class.forName()来注册驱动就是因为在静态代码块中已经完成了DriverManager.registerDriver(new Driver())。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-06-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 基础环境
  • 概念
  • 实践
    • SPI规范
    • SPI设计思想
    • 代码实践
      • 项目结构:
      • 定义Serivece
      • 定义Serivece Provider
      • 编写测试应用
      • 执行结果
  • 扩展使用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档