美文网首页
Dubbo学习(二)----SPI学习

Dubbo学习(二)----SPI学习

作者: 彳亍口巴 | 来源:发表于2020-04-22 09:12 被阅读0次

1、SPI

在dubbo中包含了很多组件,各种组件又有不同的协议使得存在多种实现,而且在开发中都是推荐针对接口编程,那就存在一个问题了,如何选择合适的实现类呢?解决方案就是SPI

SPI的全名为Service Provider Interface,提供类似于插拔式的实现类选择能力。在java中使用的类是java.util.ServiceLoader,然后在META-INF/services/创建的具体文件中写上具体的实现类的类名称,就可以实现具体的类,在早期的JDBC中,必须得通过Class.forName("xxx")这种硬编码的方式去生成对应类的实例,但是现在可以直接通过SPI达到同样的目的

1.1、Java SPI DEMO

public interface Search {
    void print();
}

public class FileSearch implements Search {

    @Override
    public void print() {
        System.out.println("==== A ====");
    }
}

public class SpiTest {

    public static void main(String[] args){
        ServiceLoader<Search> serviceLoader = ServiceLoader.load(Search.class);
        Iterator<Search> it = serviceLoader.iterator();
        while (it.hasNext()){
            Search printImpl = it.next();
            printImpl.print();
        }
    }
}

spi.Search

spi.FileSearch
spi.WebSearch

image

如上图,需要在资源文件的根目录创建一个META-INF.services的文件夹,新建一个Search接口完整路径的文件,本例子是spi.Search,里面填入实现类的类全程。如下图,确实调用了两个具体的实例,迭代分别执行。

image

1.2、Java SPI 源码实现

如下图,首先获取到fullName数据,然后调用getResource获取该文件内的资源

image
    private Iterator<String> parse(Class<?> service, URL u)
        throws ServiceConfigurationError
    {
        InputStream in = null;
        BufferedReader r = null;
        ArrayList<String> names = new ArrayList<>();
        try {
            in = u.openStream();
            r = new BufferedReader(new InputStreamReader(in, "utf-8"));
            int lc = 1;
            while ((lc = parseLine(service, u, r, lc, names)) >= 0);
        } catch (IOException x) {
            fail(service, "Error reading configuration file", x);
        } finally {
            try {
                if (r != null) r.close();
                if (in != null) in.close();
            } catch (IOException y) {
                fail(service, "Error closing configuration file", y);
            }
        }
        return names.iterator();
    }

然后解析文件内的内容,存入到一个ArrayList中,并返回其迭代器(后面肯定还差一步就是实例化)

image

很明显了,在获取到类信息,直接调用newInstance方法完成实例化操作

同时根据newInstance也可以知道对外提供的spi的实现类不能有自定义的构造函数

2、Dubbo SPI 配置

dubbo的spi和java自带的spi稍有区别,如上述的demo中,是在文件中写入什么实现类,就会去实现,如果需要获取其中的一个,则需要循环迭代获取处理,而在dubbo中则采用了类似kv对的样式,在具体使用的时候则通过相关想法即可获取,而且获取的文件路径也不一致

ExtensionLoader 类文件

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

private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";

private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";

如上述代码片段可知,dubbo是支持从META-INF/dubbo/,META-INF/dubbo/internal/以及META-INF/services/三个文件夹的路径去获取spi配置

image

例如com.alibaba.dubbo.rpc.Protocol 文件内容

registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
memcached=memcom.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol

不过观察上述文件会发现,HttpProtocol是没有对应的k值,那就是说无法通过kv对获取到其协议实现类

后面通过源码可以发现,如果没有对应的name的时候,dubbo会通过findAnnotationName方法获取一个可用的name


引用(本文章只供本人学习以及学习的记录,如有侵权,请联系我删除)

Dubbo SPI 源码学习 & admin安装(二)

相关文章

网友评论

      本文标题:Dubbo学习(二)----SPI学习

      本文链接:https://www.haomeiwen.com/subject/ritoihtx.html