文档章节

Dubbo源码学习之-SPI介绍

SEOwhywhy
 SEOwhywhy
发布于 07/06 22:18
字数 1463
阅读 28
收藏 1

前言

学习之路还是要戒骄戒躁,一以贯之的积累前行。之前的公司部门技术达人少,自己总向往那些技术牛人多的团队,想象自己进去之后能跟别人学到多少东西。如今进到一个这样的团队之后,却发现之前自己的想法过于幼稚。且不说由于人与人之间性格不合导致的难以深入相处,即使相处融洽,别人也不会给你太多的帮扶,更多的还是靠自己去学习去探究。学习的道路上没有什么捷径,且会有很多的心魔需要自己去克服。闲话少叙,今天主要是说一下Dubbo中SPI的基本内容,自适应拓展的部分后面单独成文。

什么是SPI

要说Dubbo的SPI,则必须先说说Java原生的SPI。可能很多道友都没有听说过SPI,它是Service Provider Interface 即服务提供接口的简称,顾名思义,它就是用来提供服务的。

在Java中是如何提供服务的呢?简要来说,就是在资源文件目录下(即resource目录下)的META-INF/services文件夹下,建立文件名为接口的全路径名的文件,文件内容为此接口的实现类全路径名。然后在代码中通过ServiceLoader类获取这些配置的实现类,然后就可以自由的使用这么实现类了。下面是我在本地写的一个小Demo:

代码结构如下所示:

接口代码:

1 package spipackage;
2 public interface SpiInterface {
3     void getName();
4 }
两个实现类代码:

复制代码
1 package spipackage;
2 public class SpiImpl implements SpiInterface{
3     @Override
4     public void getName() {
5         System.out.println("SpiImpl");
6     }
7 }
复制代码
复制代码
1 package spipackage;
2 public class SpiImplTwo implements SpiInterface {
3     @Override
4     public void getName() {
5         System.out.println("SpiImplTwo");
6     }
7 }
复制代码
资源文件:

1 spipackage.SpiImpl
2 spipackage.SpiImplTwo
测试类:

复制代码
 1 package spipackage;
 2 import java.util.Iterator;
 3 import java.util.ServiceLoader;
 4 public class SpiTestClient {
 5     public static void main(String[] args) {
 6         ServiceLoader<SpiInterface> spiInterfaces = ServiceLoader.load(SpiInterface.class);
 7         // 循环调用实现类中的方法
 8         spiInterfaces.forEach(SpiInterface::getName);
 9         // 获取某个实现类进行调用
10         Iterator<SpiInterface> iterator = spiInterfaces.iterator();
11         while (iterator.hasNext()) {
12             SpiInterface next = iterator.next();
13             if (next instanceof SpiImplTwo) {
14                 next.getName();
15             }
16         }
17     }
18 }
复制代码
测试结果:

什么是Dubbo的SPI

从java原生SPI的使用上可知,它是一次性加载整个资源文件中的数据,当你要获取其中某个实现类时也只能通过遍历来得到。而Dubbo的开发人员们显然要让其更加灵活,所以Dubbo中的SPI是在Java原生SPI基础上做了改造升级。首先可以按需加载,需要用哪个就加载哪个,这是通过键值对来配置实现类做到的,相当于给每个实现类打上了标签;其次还实现了依赖注入,即如果实现类A中需要注入实现类B,则dubbo在获取实现类A时会自动将B注入进去。

具体的本地代码测试跟上述类似,此处就不在贴出来了,只是需将ServiceLoader换成Dubbo的ExtensionLoader,且接口需带有@SPI注解,并且资源文件也可放入META-INF/dubbo目录下。

下面简要讲一下ExtensionLoader中的源码实现。Dubbo的ExtensionLoader类中,获取服务类的主要方法是getExtension方法,而在这个方法中,核心方法是createExtension,此方法很重要,代码如下所示:

复制代码
 1 private T createExtension(String name) {
 2         // 1、先获取class类
 3         Class<?> clazz = getExtensionClasses(www.zzhehong.com).get(name);
 4         if (clazz == null)www.shengyaoyL1.com {
 5             throw findException(name);
 6         }
 7         try {
 8             T instance = (T) EXTENSION_INSTANCES.get(www.zheshengyuLe.com clazz);
 9             if (instance == null) {
10                 // 2、通过反射创建实例,且存入缓存
11                 EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
12                 instance = (www.zeshengyuLe.com) EXTENSION_INSTANCES.get(clazz);
13             }
14             // 3、注入依赖,类似spring的依赖注入
15             injectExtension(instance);
16             // 4、将扩展对象包进wrapper对象中
17             Set<Class<?>> wrapperClasses = cachedWrapperClasses;
18             if (CollectionUtils.isNotEmpty(wrapperClasses)) {
19                 for (Class<?> wrapperClass : wrapperClasses) {
20                     instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
21                 }
22             }
23             return instance;
24         } catch (Throwable t) {
25             throw new IllegalStateException(www.oushengyule.com"Extension instance (name: " + name + ", class: " +
26                     type + ") couldn't be instantiated: " + t.getMessage(), t);
27         }
28     }
复制代码
分四步获取了类的实例对象。其中第一步中包含了主要的逻辑,它读取配置文件,是通过类加载器加载文件获取输入流,然后一行一行读取的,其中包括了对空格的处理、对注释的处理。之前总感觉读取配置文件的实现很神奇,现在慢慢的可以一窥其中究竟了,觉得也没多高大上,都是很实际的操作。

小结:SPI的作用

通过SPI实现的功能扩展,更类似于插拔式的扩展。增加了某些功能类之后,通过配置文件引入,然后在某些地方获取,调用即可。SPI机制是Dubbo的基础,了解了它才能更加清楚的看清Dubbo的框架设计。另外,通过对SPI的了解,个人感觉SPI有点类似于Spring的IOC实现,也可以说Spring通过XMl配置文件或者注解实现了一种另类的SPI机制,让你不用关注实例对象的创建,只是用的时候获取到用即可,当然Spring实现的功能内容更多更易于扩展。

只要每天都有进步,都在朝目标前行,就可心安。戒骄戒躁,努力前行!

© 著作权归作者所有

SEOwhywhy
粉丝 8
博文 152
码字总数 335019
作品 0
私信 提问
动手学dubbo之Container与SPI

在动手学dubbo之初体验一文中我们了解了dubbo的架构,接下来的几篇文章我会根据阅读Quick Start里面的demo源码来深入学习dubbo的实现。这一篇主要学习Container的原理、实现和作用。 一、从启...

ginobefun
2017/07/13
0
0
dubbo源码解析-spi(二)

前言 上一篇简单的介绍了的基本一些概念,在末尾也提到了,对jdk的spi进行了一些改进,具体改进了什么,来看看文档的描述 JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很...

肥朝
2018/01/06
0
0
dubbo源码解析-spi(一)

前言 虽然标题是dubbo源码解析,但是本篇并不会出现dubbo的源码,本篇和之前的dubbo源码解析-简单原理、与spring融合一样,为dubbo源码解析专题的知识预热篇. 插播面试题 你是否了解,讲一讲什么...

肥朝
2017/12/31
0
0
Dubbo源码分析(7):SPI扩展机制剖析

我们都是知道一个合格的开源框架对于扩展的支持都要是相当弹性的,Dubbo 也不例外。Dubbo采用微内核+插件体系,使得设计优雅,扩展性强。Dubbo的扩展机制是基于SPI思想来实现的,但是并没有采...

郑加威
2018/09/28
74
0
dubbo 视频教程

深度解剖dubbo源码 为什么要学习dubbo 源码? 1.如果你想深入学习SOA的微服务架构设计,那通过读dubbo源码是一条非常不错的通往SOA架构设计之路,毕竟SOA的服务治理就是dubbo首先提出来的,比...

qq594295b3c16b8
2017/06/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
今天
1K
13
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
今天
38
0
计算机实现原理专题--二进制减法器(二)

在计算机实现原理专题--二进制减法器(一)中说明了基本原理,现准备说明如何来实现。 首先第一步255-b运算相当于对b进行按位取反,因此可将8个非门组成如下图的形式: 由于每次做减法时,我...

FAT_mt
昨天
40
0
好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
昨天
61
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
昨天
20
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部