【dubbo】java SPI (Service Provider Interface)

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

经过命名能够看出,这是属于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.htmljava

咱们本身写代码的时候,这个东西用的比较少,可是在相关的框架中,仍是有一些应用的,例如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)总结以下:api

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

示例

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

类结构以下:
├─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接口ide

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

调用方式以下,在PrintMain中定义ui

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方法中,并无对黑白打印的显示调用,可是确实是有黑白打印机的输出。spa

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

相关文章
相关标签/搜索