【dubbo】java SPI (Service Provider Interface)

本文介绍了Dubbo框架中的SPI机制,解释了如何通过SPI实现可插拔的服务提供者,包括其工作原理、约定及示例代码。

看dobbo源码的时候,有几个类绕来绕去的,在调用Protocol的导出服务时,怎么也没找到在哪儿配置的具体实现,例如Exporter<?> exporter = protocol.export(invoker); 在debug调试时,看protocol的类型是
com.alibaba.dubbo.rpc.Protocol$Adpative,如下:

163445_Ts69_2457218.png

通过命名可以看出,这是属于com.alibaba.dubbo.rpc.Protocol类的一个内部类,而这个内部类在Protocol类中又没有定义,真正调用export方法时,调用的真正实现是RegistryProtocol。着实费解,然后去看Protocol这个接口,看到这个接口上有一个@SPI的注解,这个注解是dubbo框架自己定义的注解,突然间想到Java的SPI,应该是dubbo自己实现了一套spi机制,于是去官方文档去找了一下,确实有相关阐述。http://dubbo.io/developer-guide/%E6%89%A9%E5%B1%95%E7%82%B9%E5%8A%A0%E8%BD%BD.html

我们自己写代码的时候,这个东西用的比较少,但是在相关的框架中,还是有一些应用的,例如commos-logging日志包和新版的数据库连接DriverManager,就用到Java SPI。

SPI介绍

    为了可以实现可插拔的功能,也就是我们常用的接口,上游厂商定义了标准,而具体的实现放在下游厂商中进行实现。各家下游厂商各自独立实现不同的功能。很常见的就是我们的电脑预留了USB的接口,USB接口就是一个标准,然后各家厂商生产自己的USB接口的鼠标,键盘等等其他外设设备,它们需要符合USB接口的规范,具体的功能由各个生产厂家自己定制,用的时候插上,不用的时候拔掉,SPI(Service Provider Interface)就是基于这种思想的。
不会把硬代码侵入到接口的定义中,而是把实现放在了外部。

约定

    基于这种思想,为了方便广大程序员使用,Java的jdk中实现了SPI机制,具体的类是Java.util.ServiceLoader,针对此机制,所以会有一些我们使用上的约定,在这个类的文档中,有对使用的约定的详细描述,并且oracle文档中也有阐述(http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html)总结如下:

  1. 服务声明者是一个接口或者是一个抽象类
  2.   在META-INF文件夹下需要有一个services文件夹
  3. services文件夹下有一个文件,名称是服务提供者的全类名,并且文件的格式是UTF-8的
  4. 文件中只有一行,就是实现类的全称(包名和类名)不能有空格以及其他不可见的字符

示例

    实现一个打印机的功能,声明一个打印机接口,接口中有一个打印方法doPrint,然后

类结构如下:
├─java
│  └─com
│      └─tofuwang
│          └─myrpc
│              └─spi
│                      BlackPrinter.java
│                      Printer.java
│                      PrintMain.java
└─resources
    └─META-INF
        │services
                com.tofuwang.myrpc.spi.Printer
定义一个打印机接口Printer,里面有一个打印的方法doPrint

public interface Printer {
    public void doPrint(String body);
}

有一个黑白打印机的类BlackPrinter,实现了Printer接口

public class BlackPrinter implements Printer {
    @Override
    public void doPrint(String body) {
        System.out.println("黑白打印机打印出内容:"+body);
    }
}

调用方式如下,在PrintMain中定义

public class PrintMain {
    public static void main(String[] args) {
        ServiceLoader<Printer> load = ServiceLoader.load(Printer.class);
        Iterator<Printer> iterator = load.iterator();
        while (iterator.hasNext()){
            Printer next = iterator.next();
            next.doPrint("社会主义好!");
        }
    }
}

在main方法中,并没有对黑白打印的显示调用,但是确实是有黑白打印机的输出。

163523_nFhN_2457218.png

以上就是一个非常浅显的SPI使用示例。

转载于:https://my.oschina.net/u/2457218/blog/1511268

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值