八、Dubbo框架源码分析:dubbo扩展机制实现

一、SPI机制:

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

package com.example;

public interface Spi {

    boolean isSupport(String name);

    String sayHello();

}

ServiceLoader 会遍历所有 jar 查找 META-INF/services/com.example.Spi 文件

A 厂商提供实现

package com.a.example;

public class SpiAImpl implements Spi {

    public boolean isSupport(String name) {

    return "SPIA".equalsIgnoreCase(name.trim());

}

public String syaHello() {

    return “hello 我是厂商 A”;

}

A 厂商提供的 jar 包中的 META-INF/services/com.example.Spi 文件内容为:

com.a.example.SpiAImpl #厂商 A 的 spi 实现全路径类名

B 厂商提供实现

package com.b.example;

public class SpiBImpl implements Spi {

    public boolean isSupport(String name) {

    return "SPIB".equalsIgnoreCase(name.trim());

public String syaHello() {

    return “hello 我是厂商 B”;

}

B 厂商提供的 jar 包中的 META-INF/services/com.example.Spi 文件内容为:

com.b.example.SpiBImpl #厂商 B 的 spi 实现全路径类名

ServiceLoader.load(Spi.class) 读 取 厂 商 A 、 B 提 供 jar 包 中 的 文 件 ,ServiceLoader 实现了 Iterable 接口可通过 while for 循环语句遍历出所有实现。

一个接口多种实现,就如策略模式一样提供了策略的实现,但是没有提供策略的选择, 使用方可以根据 isSupport 方法根据业务传入厂商名来选择具体的厂商。

public class SpiFactory {

    //读取配置获取所有实现

    private static ServiceLoader spiLoader = ServiceLoader.load(Spi.class);

    //根据名字选取对应实现

    public static Spi getSpi(String name) {

        for (Spi spi : spiLoader) {

            if (spi.isSupport(name) ) {

                return spi;

            }

        }

    return null;

}}

二、dubbo实现的SPI机制:

1.标记哪些接口支持SPI 机制:Dubbo 提供一个注解 ,通过该注解标记的接口支持SPI功能。

2.SPI接口实现类的信息从哪里读取?

3.SPI接口实现类加载流程:

1、首选获取SPI接口的ExtensionLoader 类,每个接口会缓存ExtensionLoader 类,ExtensionLoader 类相当于ServiceLoader 

2.通过ExtensionLoader 类加载接口的实现类

a) 先读取 SPI 注解的 value 值,有值作为默认扩展实现的 key

b) 依次读取路径的文件

    META-INF/dubbo/internal/ com.alibaba.dubbo.rpc.Protocol

    META-INF/dubbo/ com.alibaba.dubbo.rpc.Protocol

    META-INF/services/ com.alibaba.dubbo.rpc.Protocol

逐行读取对应的实现类并通过反射构造实现类。

4.SPI接口实现类加载好了,n个实现类用那个?

dubbo 提供SPI 接口的决策类:适配器类。

为什么要创建设配类,一个接口多种实现, SPI 机制也是如此,这是策略模式,但是我们在代码执行过程中选择哪种具体的策略呢。 Dubbo 采用统一数据模式 com.alibaba.dubbo.common.URL( 它是 dubbo 定义的数据模型不是 jdk 的类),它会穿插于系统的整个执行过程, URL 中定义的协 议 类 型 字 段 protocol , 会 根 据 具 体 业 务 设 置 不 同 的 协 议 。url.getProtocol()值可以是 dubbo 也是可以 webservice, 可以是zookeeper 也可以是 redis。

dubbo有两种适配类的实现方式:

1、静态@Adaptive

2、动态生成适配器代码:


获取对应的策略适配器类:

1) 生成 Adaptive 代码 code

2) 利用 dubbo 的 spi 扩展机制获取 compiler 的设配类

3) 编译生成的 adaptive 代码

策略适配器类决策逻辑:更加URL 信息

SPI实现类依赖其他类怎么办?IOC

IOC 大 家 所 熟 知 的 ioc 是 spring 的 三 大 基 础 功 能 之 一 , dubbo 的ExtensionLoader 在加载扩展实现的时候内部实现了个简单的 ioc 机制来实现对扩展实现所依赖的参数的注入, dubbo 对扩展实现中公有的 set 方法且入参个数为一个的方法,尝试从对象工厂 ObjectFactory 获取值注入到扩展点实现中去。

1、Dubbo的容器工厂是怎样的?

dubbo 的容器工厂也是采用SPI 支持扩展。

它 跟 Compiler 接 口 一 样 设 配 类 注 解 @Adaptive 是 打 在 类AdaptiveExtensionFactory 上的不是通过 javassist 编译生成的。AdaptiveExtensionFactory 持有所有 ExtensionFactory 对象的集合, dubbo内 部 默 认 实 现 的 对 象 工 厂 是SpiExtensionFactory 和SpringExtensionFactory,他们经过 TreeMap 排好序的查找顺序是优先先从SpiExtensionFactory 获取,如果返回空在从 SpringExtensionFactory 获取。


工厂适配器类:

静态适配器类查找容器的SPI实现放入List<ExtensionFactory> factories


1) SpiExtensionFactory 工厂获取要被注入的对象,就是要获取 dubbo spi扩展的实现,所以传入的参数类型必须是接口类型并且接口上打上了@SPI 注解,返回的是一个设配类对象。

2) SpringExtensionFactory, Dubbo 利用 spring 的扩展机制跟 spring 做了很好的融合。在发布或者去引用一个服务的时候,会把 spring 的容器添加到 SpringExtensionFactory 工厂集合中去, 当 SpiExtensionFactory没有获取到对象的时候会遍历SpringExtensionFactory 中的 spring 容器来获取要注入的对象


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349