前言

虽然标题是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(一)的更多相关文章

  1. dubbo源码解析-spi(4)

    前言 本篇是spi的第四篇,本篇讲解的是spi中增加的AOP,还是和上一篇一样,我们先从大家熟悉的spring引出AOP. AOP是老生常谈的话题了,思想都不会是一蹴而就的.比如架构设计从All in ...

  2. dubbo源码解析-spi(3)

    前言 在上一篇的末尾,我们提到了dubbo的spi中增加了IoC和AOP的功能.那么本篇就讲一下这个增加的IoC,spi部分预计会有四篇,因为这东西实在是太重要了.温故而知新,我们先来回顾一下,我们之 ...

  3. dubbo源码解析-spi(二)

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

  4. Dubbo源码(二) - SPI源码

    前情提要 假设你已经知道Dubbo SPI的使用方式,不知道的请出门左转: Dubbo源码(一) - SPI使用 Dubbo源码地址: apache/dubbo 本文使用版本:2.6.x 测试Demo ...

  5. dubbo源码解析五 --- 集群容错架构设计与原理分析

    欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 博客园 Dubbo 入门之二 --- 项目结构解析 博客园 Dubbo 源码分析系列之 ...

  6. Dubbo 源码解析四 —— 负载均衡LoadBalance

    欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 Dubbo 入门之二 --- 项目结构解析 Dubbo 源码分析系列之三 -- 架构原 ...

  7. dubbo源码解析-zookeeper创建节点

    前言 在之前dubbo源码解析-本地暴露中的前言部分提到了两道高频的面试题,其中一道dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,那发布者和订阅者还能通信吗?在上周的dubbo源码 ...

  8. Dubbo源码解析之SPI(一):扩展类的加载过程

    Dubbo是一款开源的.高性能且轻量级的Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用.智能容错和负载均衡,以及服务自动注册和发现. Dubbo最早是阿里公司内部的RPC框架,于 ...

  9. 【Dubbo 源码解析】02_Dubbo SPI

    Dubbo SPI:(version:2.6.*) Dubbo 微内核 + 插件 模式,得益于 Dubbo SPI .其中 ExtentionLoader是 Dubbo SPI 最核心的类,它负责扩展 ...

随机推荐

  1. io编程,bio,nio,aio

    本文会从传统的BIO到NIO再到AIO自浅至深介绍,并附上完整的代码讲解. 下面代码中会使用这样一个例子:客户端发送一段算式的字符串到服务器,服务器计算后返回结果到客户端. 代码的所有说明,都直接作为 ...

  2. Java 中的“implements Runnable” 和“extends Thread”

    知识点 “implements Runnable” 和“extends Thread”的不同 具体分析 最近在学习Android中的Handler消息传递机制时,创建新线程有两种方式:一种是实现Run ...

  3. [Winfrom]Cefsharp配置与初始化

    摘要 在做客户端程序的时候,本来打算使用wpf的,但在内嵌cefsharp的时候,发现输入法有问题,所以使用了winform作为cefsharp的容器. 系列文章 CefSharp 在同一窗口打开链接 ...

  4. c# 主机和网络字节序的转换 关于网络字节序和主机字节序的转换

    最近使用C#进行网络开发,需要处理ISO8583报文,由于其中有些域是数值型的,于是在传输的时候涉及到了字节序的转换. 字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有两种字节顺序, ...

  5. Win10专业版永久激活方法

    自从升级安装了Windows10系统以后,我想很多朋友和我一样,想要激活Windows10系统,但是小编找了半天以后发现,很多激活工具都是批量激活的,也就是只有180天的使用时间,那么我们怎么永久激活 ...

  6. 为什么使用this构造器

    当一个类有多个构造函数的时候,常使用this构造器: public class SomeClass { public SomeClass() { //TODO:初始化一些字段 } public Som ...

  7. 创建 HelloWorld 项目

    在 Eclipse 的导航栏中点击 File →New →Android Application Project ,此时会弹出创建 Android 项目的对话框.其中 Application Name ...

  8. 越狱的 ios 如何 获取 读取 提取 手机上的 短信 通话记录 联系人 等信息

    http://willson.sinaapp.com/2011/12/iphone 获取短信脚本.html  Iphone获取短信脚本http://bbs.9ria.com/thread-209349 ...

  9. C#编程(六十六)----------表达式树总结

    表达式树总结 基础 表达式树提供了一个将可执行代码转换成数据的方法.如果你要在执行代码之前修改或转换此代码,那么它是很有用的.有其是当你要将C#代码----如LINQ查询表达式转换成其他代码在另一个程 ...

  10. C#编程(五十)----------栈

    栈 栈与队列是一个非常类似的容器,他们的区别在于队列是先进先出,而栈是后进先出. Stack与Stack<T>,像队列一样,栈也提供了泛型与非泛型版本. Stack的方法: 方法 说明 P ...