Dubbo源码分析之ExtensionLoader

参考:http://dubbo.apache.org/zh-cn/docs/source_code_guide/dubbo-spi.html

1.简介

SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。如果大家想要学习 Dubbo 的源码,SPI 机制务必弄懂。接下来,我们先来了解一下 Java SPI 与 Dubbo SPI 的用法,然后再来分析 Dubbo SPI 的源码。

需要特别说明的是,本篇文章的源码版本为 dubbo-4.0.0。因此大家在阅读文章的过程中,需注意将代码版本切换到 dubbo-4.0.0 tag 上。

dubbo的目录结构如下,感兴趣的可以自行到github上去下载到本地

本次记录的ExtensionLoader用法是在如下目录下。

首先咱们 先来看一下他的基本用法

找到dubbo的test

我们来随便在测试类里面写个测试

@Test
public void testExt2() throws Exception {
    ExtensionLoader<Ext2> extensionLoader = ExtensionLoader.getExtensionLoader(Ext2.class);
    Ext2 impl1 = extensionLoader.getExtension("impl1");
    String value = impl1.echo(new UrlHolder(), "2");
    System.err.println(value);
    //==========================
    Ext2 impl2 = extensionLoader.getExtension("impl2");
    String value2 = impl2.echo(new UrlHolder(), "2");
    System.err.println(value2);
}

点击Ext2类进去看见是一个接口

@SPI
public interface Ext2 {
    // one of the properties of an argument is an instance of URL.
    @Adaptive
    String echo(UrlHolder holder, String s);

    String bang(URL url, int i);
}

并且是加了@SPI和在方法上加了 @Adaptive注解的接口,这里需要留意下。后面源码分析时候会讲到。

通过idea看见Ext2 有定义了三个实现类

三个实现类几乎一样,只是作为区分而已

public class Ext2Impl2 implements Ext2 {
    public String echo(UrlHolder holder, String s) {
        return "Ext2Impl2-echo";
    }

    public String bang(URL url, int i) {
        return "bang2";
    }
}

接下来看一下三个实现类定义的文件

内容为:

impl1=org.apache.dubbo.common.extension.ext2.impl.Ext2Impl1
impl2=org.apache.dubbo.common.extension.ext2.impl.Ext2Impl2
impl3=org.apache.dubbo.common.extension.ext2.impl.Ext2Impl3

可以看出是个键值对。值为实现类的全类名。

运行测试类得到如下

Dubbo SPI 除了支持按需加载接口实现类,还增加了 IOC 和 AOP 等特性。

上面简单演示了 Dubbo SPI 的使用方法。我们首先通过 ExtensionLoader 的 getExtensionLoader 方法获取一个 ExtensionLoader 实例,然后再通过 ExtensionLoader 的 getExtension 方法获取拓展类对象。这其中,getExtensionLoader 方法用于从缓存中获取与拓展类对应的 ExtensionLoader,若缓存未命中,则创建一个新的实例。该方法的逻辑比较简单,本章就不进行分析了。下面我们从 ExtensionLoader 的 getExtension 方法作为入口,对拓展类对象的获取过程进行详细的分析。

由于篇幅有限并且文章太长会让读者没兴趣看下去。下篇我们再来看Dubbo 的SPI 源码。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章