dubbo源码解析-spi(一)
前言
虽然标题是dubbo源码解析,但是本篇并不会出现dubbo的源码,本篇和之前的dubbo源码解析-简单原理、与spring融合一样,为dubbo源码解析专题的知识预热篇.
插播面试题
你是否了解spi,讲一讲什么是spi,为什么要使用spi?
对类加载机制了解吗,说一下什么是双亲委托模式,他有什么弊端,这个弊端有没有什么我们熟悉的案例,解决这个弊端的原理又是怎么样的?
spi的简单介绍
如果提到api相信大家都知道,spi的话,知道的人就相对少一些。
简单的说,api是给使用者使用的,spi是给拓展者使用的.一个好的开源框架,必须要留一些拓展点.让参与者尽量黑盒拓展,而不是白盒修改代码,否则分支,质量,合并,冲突都会很难管理.并且框架作者能做到的功能,拓展者也一定能做到.
如果从使用层面来说,就是运行时,动态给接口添加实现类.其实这有点像IoC的思想,将装配的控制权移到程序之外
如果从生活中的例子讲,就是比如浏览器插件,比如墙上的插头不够我们就接个排插,而不是伤筋动骨改插头(感觉不是很贴切,前期你暂且这么不规范的粗略理解)
再多的言语都是抽象的,那么我们用代码来简单实现一下spi
spi的简单实现
接口和具体实现类
public interface ISayName {
void say();
}
接口的一种实现
public class SayEnglishName implements ISayName{
@Override
public void say() {
System.out.println("Toby");
}
}
接口的另一实现
public class SayChineseName implements ISayName{
@Override
public void say() {
System.out.println("肥朝");
}
}
配置文件,需放置在META-INF/services/接口全限定名
com.toby.spi.impl.SayChineseName
com.toby.spi.impl.SayEnglishName
demo目录结构
测试结果如下
通过改变配置文件,我们就能动态的改变一个接口的实现类.
细心的小伙伴可能发现,比如我想新增一个实现类SayFranceNameImpl,这样的话光改配置文件也还是不行,还要预先包里面就有这个实现类才行啊.
这个先别急,后面会介绍javassist,也就是动态字节码技术.这样可以在运行时动态生成Java类,就不存在要预先把接口的实现类先在包里放好.更多内容,关注肥朝即可.
当然细心的小伙伴可能还发现了,这个我就算不用spi,我用spring的ioc也能通过配置文件动态的注入不同的实现类啊
比如dubbo的设计中,就不想强依赖Spring的IoC容器,但是自已造一个小的IoC容器,也觉得有点过度设计.另外dubbo是不需要依赖任何第三方库的,引用官方文档原话如下
理论上 Dubbo 可以只依赖 JDK,不依赖于任何三方库运行,只需配置使用 JDK 相关实现策略
敲黑板划重点
经常看到有人问两类问题
- java人这么多,是否饱和了?
- 为什么总是要面试造火箭,进去拧螺丝?
你可以问一下你同事,你知道什么是spi吗,如果他不知道的话,那你觉得他把上面的这个简单的例子实现要多久?如果从使用这个层面做区分的话,很难做到有效的区分.无论是做什么,要想在竞争中脱颖而出,就必须做到三个字.差异化.比如之前买喜茶要排很长的队,这其实也是一种差异化.
Java基础中比较容易产生差异化的两个区域就在于JVM和并发编程.如果只是停留在使用层面,那么关注肥朝的博客意义并不大,因此,本篇的spi还需要与ClassLoader结合.
学习JVM和并发编程买本书是必不可少的,以下内容参考了实战Java虚拟机.如果你看的是深入Java虚拟机也没关系,不要纠结于获取知识的渠道,没人在意你做的是五年高考三年模拟还是王后雄学案.
以下内容截取了该书中的部分核心内容,非常感谢作者的辛勤奉献(希望大家支持正版书籍).
从ClassLoader引出spi
ClassLoader的简单介绍
Class的装载大体上可以分为加载类、连接类和初始化三个阶段,在这三个阶段中,所有的Class都是由ClassLoader进行加载的,然后Java虚拟机负责连接、初始化等操作.也就是说,无法通过ClassLoader去改变类的连接和初始化行为.
Java虚拟机会创建三类ClassLoader,分别是
- BootStrap ClassLoader(启动类加载器)
- Extension ClassLoader(扩展类加载器)
- APP ClassLoader(应用类加载器,也称为系统类加载器)
此外,每个应用还可以自定义ClassLoader
ClassLoader的双亲委托模式
在ClassLoader的结构中,还有一个重要的字段parent,它也是一个ClassLoader的实例,这个字段表示的ClassLoader也称为这个ClassLoader的双亲.在类加载的过程中,可能会将某些加载类的请求交于自己的双亲处理.
如图,应用类加载器的双亲为扩展类加载器,扩展类加载器的双亲为启动类加载器.

系统中的ClassLoader在协同工作时,默认会使用双亲委托模式.即在类加载的时候,系统会判断当前类是否已经被加载,如果被加载,就会直接返回可用的类,否则就会尝试加载,在尝试加载时,会先请求双亲处理,如果双亲请求失败,则会自己加载.
双亲委托模式的弊端
判断类是否加载的时候,应用类加载器会顺着双亲路径往上判断,直到启动类加载器.但是启动类加载器不会往下询问,这个委托路线是单向的,即顶层的类加载器,无法访问底层的类加载器所加载的类,如图

启动类加载器中的类为系统的核心类,比如,在系统类中,提供了一个接口,并且该接口还提供了一个工厂方法用于创建该接口的实例,但是该接口的实现类在应用层中,接口和工厂方法在启动类加载器中,就会出现工厂方法无法创建由应用类加载器加载的应用实例问题.
拥有这样问题的组件有很多,比如JDBC、Xml parser等.JDBC本身是java连接数据库的一个标准,是进行数据库连接的抽象层,由java编写的一组类和接口组成,接口的实现由各个数据库厂商来完成
双亲委托模式的补充
在Java中,把核心类(rt.jar)中提供外部服务,可由应用层自行实现的接口,这种方式称为为spi.那我们看一下,在启动类加载器中,访问由应用类加载器实现spi接口的原理
Thread类中有两个方法
public ClassLoader getContextClassLoader()//获取线程中的上下文加载器
public void setContextClassLoader(ClassLoader cl)//设置线程中的上下文加载器
通过这两个方法,可以把一个ClassLoader置于一个线程的实例之中,使该ClassLoader成为一个相对共享的实例.这样即使是启动类加载器中的代码也可以通过这种方式访问应用类加载器中的类了.如下图

写在最后
本篇为2017年的最后一篇,提前祝大家元旦快乐.2018年,每周一篇dubbo源码解析还会继续更新.原因很简单,越是忙碌才越要抽出时间学习.我们要训练的是如何打逆风局,而不是怎么打顺风局.当然我非常不提倡大家像我一样熬夜(因明天要外出,所以不得不在今晚完成),不要忘了目前很火的电视剧虎啸龙吟中司马懿是怎么把诸葛亮熬死的.
有了本篇的知识铺垫,下一篇将从dubbo源码入手,看看dubbo是如何实现spi的.另外剧透一下,dubbo还对JDK标准的spi进行了一些改进.期待下周继续与你相遇.鉴于本人才疏学浅,不对的地方还望斧正。
Ref:
dubbo源码解析-spi(一)的更多相关文章
- dubbo源码解析-spi(4)
前言 本篇是spi的第四篇,本篇讲解的是spi中增加的AOP,还是和上一篇一样,我们先从大家熟悉的spring引出AOP. AOP是老生常谈的话题了,思想都不会是一蹴而就的.比如架构设计从All in ...
- dubbo源码解析-spi(3)
前言 在上一篇的末尾,我们提到了dubbo的spi中增加了IoC和AOP的功能.那么本篇就讲一下这个增加的IoC,spi部分预计会有四篇,因为这东西实在是太重要了.温故而知新,我们先来回顾一下,我们之 ...
- dubbo源码解析-spi(二)
前言 上一篇简单的介绍了spi的基本一些概念,在末尾也提到了,dubbo对jdk的spi进行了一些改进,具体改进了什么,来看看文档的描述 JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩 ...
- Dubbo源码(二) - SPI源码
前情提要 假设你已经知道Dubbo SPI的使用方式,不知道的请出门左转: Dubbo源码(一) - SPI使用 Dubbo源码地址: apache/dubbo 本文使用版本:2.6.x 测试Demo ...
- dubbo源码解析五 --- 集群容错架构设计与原理分析
欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 博客园 Dubbo 入门之二 --- 项目结构解析 博客园 Dubbo 源码分析系列之 ...
- Dubbo 源码解析四 —— 负载均衡LoadBalance
欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 Dubbo 入门之二 --- 项目结构解析 Dubbo 源码分析系列之三 -- 架构原 ...
- dubbo源码解析-zookeeper创建节点
前言 在之前dubbo源码解析-本地暴露中的前言部分提到了两道高频的面试题,其中一道dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,那发布者和订阅者还能通信吗?在上周的dubbo源码 ...
- Dubbo源码解析之SPI(一):扩展类的加载过程
Dubbo是一款开源的.高性能且轻量级的Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用.智能容错和负载均衡,以及服务自动注册和发现. Dubbo最早是阿里公司内部的RPC框架,于 ...
- 【Dubbo 源码解析】02_Dubbo SPI
Dubbo SPI:(version:2.6.*) Dubbo 微内核 + 插件 模式,得益于 Dubbo SPI .其中 ExtentionLoader是 Dubbo SPI 最核心的类,它负责扩展 ...
随机推荐
- 【*】深入理解redis主从复制原理
1.复制过程 从节点执行 slaveof 命令. 从节点只是保存了 slaveof 命令中主节点的信息,并没有立即发起复制. 从节点内部的定时任务发现有主节点的信息,开始使用 socket 连接主节点 ...
- MySQL CPU %sys 高的案例分析(三)
[现象] 最近有台服务器晚上CPU告警,系统抓取的故障期间的snapshot显示CPU %sys较高,同时context switch在300K以上. 是否过高的context switch引起的%s ...
- git使用姿势
IDEA 整合Git 可以在IDEA中Terminal中进行git操作 下面所说的快捷键操作都只是对于IDEA中 拉取提交代码 git pull 从远程仓库更新代码 (ctrl+t) git comm ...
- BeagleBone Black教程之BeagleBone Black设备的连接
BeagleBone Black教程之BeagleBone Black设备的连接 BeagleBone Black开发前需要准备的材料 经过上面的介绍,相信你已经对BeagleBone有了大致的了解, ...
- js中函数的参数传递
js中所有函数的参数传递都是按值传递,也就是说把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样,基本类型值的传递如同基本类型变量的复制一样,而引用类型的值的传递则如同引用类型 ...
- 「WC 2019」数树
「WC 2019」数树 一道涨姿势的EGF好题,官方题解我并没有完全看懂,尝试用指数型生成函数和组合意义的角度推了一波.考场上只得了 44 分也暴露了我在数数的一些基本套路上的不足,后面的 \(\ex ...
- Markdown基础用法
1. 标题 文字前加#,共6级标题,# 一级标题,## 二级标题,...,###### 六级标题 2. 列表 文字前加-或* 即可变无序列表,文字前加 数字. 即可变有序列表 3. 引用 在引用文本前 ...
- 老菜鸟致青春,程序员应该选择java 还是 c#-
致青春 还记得自己那年考清华失败,被调剂到中科大软院,当初有几个方向可以选,软件设计.嵌入式.信息安全等等,毫不犹豫地选择了信息安全. 为什么选信息安全?这四个字听起来多牛多有感觉,我本科是学物理的, ...
- Centos 安装Percona Toolkit工具集
1.下载 下载地址: https://www.percona.com/downloads/percona-toolkit/LATEST/ [root@bogon ~]# wget https:// ...
- Revit Family API 找到实体某一方向上的面。
PlanarFace.Normal取得向量.IsAlmostEqualTo判断向量是否一致. // ================================================== ...