Dubbo的SPI实现以及与JDK实现的区别

作者:CQITer小编 时间:2018-07-10 09:32

字号
开发者盛宴来袭!7月28日51CTO首届开发者大赛决赛带来技术创新分享

Java 里, 为了规范开发,制定了大量的「规范」与「标准」,这些上层的内容,大多是以接口的形式提供出来。那这些接口最终实现是谁呢,在哪里呢?

Dubbo的SPI实现以及与JDK实现的区别

规范并不关心这个。

所谓规范,是指定了一系列内容,来指导我们的开发实现。比如 Servlet规范对于 Servlet 的行为做了说明,具体实现时,可以是 Tomcat,可以是Jetty 等等。

再比如 Java 的 JDBC 规范,规定了 Driver 提供者需要实现的内容,但具体是 Oracle,或者MySQL 都可以支持。关于JDBC 可以看之前一篇文章(没想到你是这样的 JDBC)。在之前我们可以通过 Class.forName来进行Driver 具体实现类的加载。从JDK1.6开始,官方提供了一个名为 「SPI」 的机制,来更方便快捷的进行对应实现类的加载,不需要我们关心。我们所需要做的,只需要将包含实现类的 JAR 文件放到 classpath中即可。

正好最近读了一些Dubbo的源码,其中有 Dubbo 的不同于JDK的另一种 SPI实现。所以这篇我们来看 Dubbo 的 「SPI」实现以及与 JDK 实现的区别。

首先,什么是 SPI 呢?

SPI(Service Provider Interfaces), 可以理解成一个交给第三方实现的API。JDK文档这样描述

A service is a well-known set of interfaces and (usually abstract) classes. A service provider is a specific implementation of a service.  

在Java 中使用到SPI的这些地方:

JDBC

JNDI

Java XML Processing API

Locael

NIO Channel Provider

……

通过这种SPI 的实现形式,我们的应用仿佛有了可插拔的能力。

我们之前的文章Tomcat 中 的可插拔以及 SCI 的实现原理 里,也分析了容器中是如何做到可插拔的。

JDK中的SPI 是怎样实现的呢?

在JDK中包含一个SPI最核心的类:ServiceLoader,在需要加载Provider类的时候,我们所要做的是:

ServiceLoader.load(Provider.class); 

在JDK中规范了 Service Provider的路径,所有 Provider必须在JAR文件的META-INF/services目录下包含一个文件,文件名就是我们要实现的Service的名称全路径。比如我们熟悉的JDBC 的MySQL实现, 在mysql-connector中,就有这样一个文件

META-INF/services/java.sql.Driver

Dubbo的SPI实现以及与JDK实现的区别

这些provider是什么时候加载的呢?

由于Provider 的加载和初始化是Lazy的实现,所以需要的时候,可以遍历Provider 的 Iterator,按需要加载,已经加载的会存放到缓存中。

但有些实现不想Lazy,就直接在 ServiceLoader 的load执行之后直接把所有的实现都加载和初始化了,比如这次说的JDBC,所以这里在Tomcat里有个处理内存泄漏的,可以查看之前的文章(Tomcat与内存泄露处理)

继续说回具体的加载时机。我们一般在Spring 的配置中会增加一个datasource,这个数据源一般会在启动时做为一个Bean被初始化,此时数据源中配置的driver会被设置。

这些内容传入Bean中,会调用DriverManager的初始化

static { 

   loadInitialDrivers(); 

    println("JDBC DriverManager initialized"); 

 

loadInitialDrivers 执行的的时候,除了ServiceLoader.load外,还进行了初始化 

 

ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class); 

Iterator<Driver> driversIterator = loadedDrivers.iterator(); 

try{ 

    while(driversIterator.hasNext()) { 

        driversIterator.next(); 

    } 

} catch(Throwable t) { 

// Do nothing 

return null; 

我们再来看 Dubbo 的SPI实现方式。如果你能看下 Dubbo 的源码就会发现,实现时并没有使用 JDK 的SPI,而是自已设计了一种。

我们以Main class启动来看看具体的实现。

我们从使用的入口处来看,第一步传入一个接口, 然后再传入期待的实现的名称

责任编辑:CQITer新闻报料:400-888-8888   本站原创,未经授权不得转载
关键词 >>Dubbo SPI JDK Java
继续阅读
热新闻
推荐
关于我们联系我们免责声明隐私政策 友情链接