Java 规范 SPI

我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。

为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。java spi就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。

1、什么是SPI

这里先说下SPI的一个概念,SPI英文为Service Provider Interface单从字面可以理解为Service提供者接口,正如从SPI的名字去理解SPI就是Service提供者接口;我对SPI的定义:提供给服务提供厂商与扩展框架功能的开发者使用的接口。

很多框架都使用了java的SPI机制,如JDBC4中的java.sql.Driver的SPI实现(mysql驱动、oracle驱动等)、common-logging的日志接口实现、dubbo的扩展实现等等框架;

2、如何编写SPI

当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。
JDK提供服务实现查找的一个工具类:java.util.ServiceLoader。

3、Example

1)Interface

public interface Speak {

    void sayHello();

}

2)Implement
有2个不同的实现,修改配置文件的时候就会实例化不同的对象.

public class SpeakImpl implements Speak {
    @Override
    public void sayHello() {
        System.out.println("haha");
    }
}

另外一个实现:

public class AnnSpeak implements Speak {
    @Override
    public void speak() {
        System.out.println("hi, ann!");
    }
}

3)Config
在resources/META-INF.services文件下添加以接口全路径命令的文件:

  • resources
    • META-INF.services
      • com.weimob.jdk.spi.api.Speak
        然后在文件中添加这个接口的实现。
com.weimob.jdk.spi.impl.CarlSpeak

这里写图片描述

4)Test

public class SPITest {

    public static void main(String[] args) {

        ServiceLoader<Speak> s = ServiceLoader.load(Speak.class);
        Iterator<Speak> searchs = s.iterator();
        if(searchs.hasNext()){
            Speak speak = searchs.next();
            speak.speak();
        }
    }

}

5)运行结果
这里写图片描述

修改配置文件为:

com.weimob.jdk.spi.impl.AnnSpeak

运行结果就是:
这里写图片描述

可以看出SPITest里没有任何和具体实现有关的代码,而是基于spi的机制去查找服务的实现。因为这只是举例这个例子是在同一个项目中运行的。在真实的环境中你可以接口与实现分离这也是能够运行成功的。

4、Q&A

1、配置文件为什么要放在META-INF/services下面?
我们可以在java.util.ServiceLoader中找到以下代码。

    private static final String PREFIX = "META-INF/services/";

2、ServiceLoader读取实现类是什么时候实例化的?
ServiceLoader.LazyIterator.nextService中实例化,即load的结果迭代时才会被实例化。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值