Java SPI机制介绍与ServiceLoader应用

1、SPI是什么

SPI全称Service Provider Interface(服务提供接口),是专门被第三方实现或者扩展的API,可以用来启用框架扩展和替换组件,提供了为某个接口寻找对应服务类的机制。

整体机制如下:
在这里插入图片描述
(图片来源:https://www.jianshu.com/p/46b42f7f593c)

Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制。

Java SPI的实现要素:

  • 首先定义服务和接口名;
  • 不同服务提供者实现了接口的实现类后,需要在jar包的META-INF/services目录下创建一个"接口全限定名"为命名的文件,内容对应即为该实现类的全限定名;
  • 接口实现类所在jar包放在主程序classpath下;
  • 服务调用方通过该接口时,引入提供者jar包 ,通过java.util.ServiceLoder动态装载提供者的实现模块,扫描提供者的META-INF/services目录下的配置文件找到实现类的全限定名,之后再将该类加载到JVM;
  • SPI实现类必须携带一个不带参数的构造方法;

2、Java SPI demo

举个例子看看SPI的应用。

在应用Java SPI之前,假设有个mq消息处理服务:

public interface KafkaProcessService {
   
    void processOrderMsg(Object msg);

}

我们提供服务实现后,打包,假设版本号为version=1.0;团队1使用了引入该jar并且直接调用服务方法processOrderMsg()

之后团队2想调用一个支付消息处理的方法,那么我们就需要提供一个对应实现,并且将版本号升到version=2.0;;团队2使用了引入该jar并且直接调用服务方法processPayMsg()

public interface KafkaProcessService {
   
    void processPayMsg(Object msg);
}

试想如果每增加一个实现,我们就要升一个版本,这会带来很大麻烦。

如何应用用Java SPI是如何处理这种麻烦?
(1)首先定义接口:

public interface KafkaProcessService {
   
    void processMsg(Object msg);
}

具体实现类
public class KafkaOrderProcessServiceImpl implements KafkaProcessService {
   
    @Override
    public void processMsg(Object msg) {
   
        System.out.println("Order kafka msg process");
    }
}

public class KafkaPayProcessServiceImpl implements KafkaProcessService {
   
    @Override
    public void processMsg(Object msg) {
   
        System.out.println("Pay kafka msg process");
    }
}


(2)resources目录下新建/META_INF/services目录,并创建一个与接口全限定名相同的文件,在文件中输入接口对应两个实现类的全限定名:

(3)执行程序:

public class Invoker {
   

    public static void main(String[] args) {
   
            ServiceLoader<KafkaProcessService> processServices = ServiceLoader.load(KafkaProcessService.class);
            for (KafkaProcessService s : processServices) {
   
                s.processMsg(new Object());
            }

        }
}

运行项目后可以看到能够两个实现类均执行了。

3、Java SPI 在框架中的应用

有人会说上面的例子看起来和本地应用策略模式实现的没有什么不同。实际上,SPI更多的应用场景:团队1定义接口且可以提供默认实现,团队2、3…引用接口,并且可以自行拓展接口的实现。

下面通过具体实例来体会SPI的应用。

3.1 JDBC加载不同类型数据库驱动

JDBC数据库驱动的设计就是应用Java SPI机制。首先定义统一的规范:java.sql.Driver, 各大厂商(MySQL、Oracle)都会根据这个规范去实现各自的驱动逻辑。我们在使用JDBC客户端时候不需要改变代码,直接引入对应jar包,实际调用即使用对应的驱动实现。

分析下源码:

我们引入MySQL驱动后,JDBC连接数据库java.sql.DriverManager中就会使用SPI机制来加载具体的驱动实现:

public class DriverManager {
   
    // 省略部分代码
    static {
   
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }
   
   // 使用SPI机制初始化驱动
   private static void loadInitialDrivers() {
   
        // 省略部分代码
		    
        // 使用ServiceLoader找到实现Driver的接口,进行实例化
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
   
            public Void run() {
   

                ServiceLoader<Driver></
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值