由浅入深理解Dubbo的SPI机制

前言

在分析dubbo源码的过程中,发现dubbo对于扩展点的加载实现的是非常巧妙的,可以达到用时才动态实例化对象,灵活且节约资源。其实Dubbo 的扩展点加载是从 JDK 标准的 SPI (Service Provider Interface) 扩展点发现机制加强而来。它优化了JDK必须一次性实例化扩展点所有实现的缺点。

JDK标准的SPI

一个接口可以有多个不同的实现类,但是在一些业务场景里面,我们需要根据不同的业务类型去选择具体的能够满足我当前需求的实现类。大多数时候,我们都是在内存里面维护一个Map,这样可以很高效的实现咱们的目的。但是这样扩展性太差了,每次增加一种实现类,都得去修改原来的代码,风险太大了。于是,JDK给咱们提供了SPI技术,用来去解决这一块的短板。具体的操作方式如下:

要素一:接口类

package github.com.crazyStrongboy.inter;

要素二:不同的实现类

package github.com.crazyStrongboy.jdk_api;


要素三:配置文件

在resources资源文件夹下面建立目录META-INF/services,建立接口全路径的文件,例如:


调用方式

这里drivers中会加载到咱们默认给的两个实现类,如果要增加一个实现,咱们只要新建一个模块,在配置文件中加上咱们的实现github.com.crazyStrongboy.jdk_api.xxx即可,不会入侵原来的老代码。但是这种实现的弊端也很明显,一次性加载出来了所有的扩展类,浪费资源。相关代码在github中。


自定义SPI实现

自己去定义一个SPI的实现,主要分三步走:

  1. 利用ClassLoader类加载器去读取资源文件夹指定名称的文件。
  2. 解析文件内容,并存放到一个Map容器中。键为name,值为具体实现类的Class。
  3. 封装一个对外提供的方法,参数为name值。
第一步:读取资源
第二步:解析配置文件内容
第三步:提供方法

我这边用的路径为META-INF/mars_jun/


配置文件:

调用方式

其实这个不算太完整,可以把每次初始化后的对象根据相应的name存储到另一个Map中,这样就不会每次调用getExtension都会去生成一个新的实例。但是在上面这段代码当中,咱们可以观察到,我并没有在一开始就将所有的扩展类都初始化出来,而是先保存扩展类的Class到Map中,直到咱们需要使用的时候再去初始化实例对象。解决了JDK中SPI会一次性实例化扩展点所有实现的这个缺陷。相关代码在github中。


Dubbo的SPI机制

咱们直接从下面这段代码开始:

    private static final Protocol protocol = ExtensionLoader.
            getExtensionLoader(Protocol.class).getAdaptiveExtension();

首先先普及下两个注解@Adaptive与@SPI

  1. 一个接口的实现类至多只能有一个被@Adaptive注解,在方法上不限,注解在类上意思是标记该类为默认扩展类,标记在方法上则可支持动态的创建扩展器。
  2. @SPI可指定默认动态生成的扩展类。

ExtensionLoader.getExtensionLoader(Protocol.class)这一句代码只是简单的构建了一个ExtensionLoader扩展器加载器对象,代码不太复杂。后面的getAdaptiveExtension才是重点。顺着链路调用,会到下图所示的方法:

关注上面圈红的标记处,主要分为了两步走:

第一步:加载所有配置文件

是不是感觉似曾相识~,这一块代码也就读取了dubbo指定的几个资源目录的配置,包括"META-INF/services/" "META-INF/dubbo/" "META-INF/dubbo/internal/"这三个目录,然后一个个解析出来,丢到指定的Map集合中,缓存起来供后期类似的操作使用。当然其中还包括一些注解的解析,是否是包装类等等一些操作,这些大家可以自行点进去了解。

第二步:动态编译Protocol$Adaptive文件

在没有指定自适应的cachedAdaptiveClass的情况下(也就是实现类没有一个上面有@Adaptive注解),会调用createAdaptiveExtensionClass方法生成一个xx$Adaptive 对象。

Dubbo的SPI机制的核心点也在这里,重点关注xx$Adaptive 对象Protocol对应的是Protocol$Adaptive。咱们简单看一下它生成的代码段:

它可以根据URL中的protocol字段的值去动态获取相应的扩展类,例如"dubbo"对应DubboProtocol,"registry"对应RegistryProtocol,这样是不是更加的灵活~。

这一块虽然写的不多,但核心思想点也就差不多都在这一块,顺着上面的思路一步步往下读,这个东西应该不难理解~


END

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

推荐阅读更多精彩内容