1. 什么叫SPI?

简单总结就是一种使用类名字符串来动态实例化java类的方式,也就是反射。

2. java SPI与Dubbo SPI有什么区别

(此图来自网上,我没有刻意去截图)

然后在这个文件里面写入实现类

com.blueskykong.javaspi.serializer.KryoSerializer

com.blueskykong.javaspi.serializer.JavaSerializer

但是dubbo的SPI格式变了,也就意味着不能直接使用java SPI了

文件的目录相似,但是里面的内容变为了key-value

adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory

结论:所谓的这些SPI只不过是一种方式而已,最后都是反射生成类(还有classloader的问题,这里我们不讨论),组织方式可以随便变,但是既然是分析dubbo,那么这里就看dubbo是怎么最终实现的

3. 为什么dubbo要自己实现所谓的SPI?

dubbo相当于使用了key-value的形式,用key来映射每个类,这样用户就可以在url加入这个key来实现动态加载某个类的需求,

那么为什么java SPI的方式不行:

  • java SPI的文件里面仅仅只有类名,如果想让用户动态指定,那么需要按照这个类名来标识用户想要哪个类,太长,或者是在类名字上加上一定的区分规则
  • java SPI的加载是一次性会加载所有的类,但是并不是每个类都需要

4. dubbo spi实现方式详解

4.1 背景

现在使用key-value的方式已经可以由用户指定key去加载class,但是出于系统的考虑还有一些功能需要扩展

  • key-value的指定是由@Adaptive和@SPI来辅助实现,@SPI可以指定类级别的默认的类,@Adaptive可以设置函数级别需要加载哪个class
  • 针对FIlter需要指定是否起效,以及在provider起效还是consumer起效,以及Filter之间的优先级

4.2 源码

dubbo中负责SPI的处理的类主要是 ExtensionLoader

这里我标注出主要的变量含义

/**
* 这个三个代表需要从哪个resource路径下加载我们的key-value文件
*/
private static final String SERVICES_DIRECTORY = "META-INF/services/"; private static final String DUBBO_DIRECTORY = "META-INF/dubbo/"; private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/"; /**
* 在注解里面的value是可以使用逗号(,)来设置多个值
*/
private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*"); /**
* ExtensionLoader 是每个接口对应一个 这个map保存了接口和对应的ExtensionLoader的对应
*/
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>(); /**
* 保存了配置文件中所有value-key之间的映射
*/
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>(); // 以上都是静态变量也就是是全局的 /**
* 当前这个ExtensionLoader 对应的那个接口
*/
private final Class<?> type; private final ExtensionFactory objectFactory; /**
* value-key之间的反映射
*/
private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>(); /**
* 配置文件中key-value之间的映射 value指的是类class
*/
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>(); /**
* 这里保存着这个接口的实现类含有@Activate注解
*/
private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
/**
* 这个接口下 key-value的映射 value指的是实例
*/
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>(); /**
* 适配类的实例
*/
private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
/***
* 这个接口的适配类 也就是注解@Adaptive的注解加载类的这个类就是适配类 所谓的适配类 就是实现根据url里面的参数
* 来决定使用这个接口的哪个子类
*/
private volatile Class<?> cachedAdaptiveClass = null;
/**
* SPI注解里面value 作为这个接口的默认加载类
*/
private String cachedDefaultName;

总结一下:

  1. 每一个接口比如Protocol和ExtensionLoader之间是一一对应的关,但是Protocol这个接口有很多子类,以及默认类,那么这些管理都是在ExtensionLoader里面管理,上面的大多数字段都是为了管理而存在
  2. ExtensionLoader最主要的功能是为了根据key来获取类,然后其他的都是一些变化。
  3. ExtensionLoader的主要功能和思想(为了实现key到value的转换),也就是说我想在有了key-value之间的关系,你可以认为这就是一个小型db,那么你想查询某一个接口的class有多少,以及每个class对应的key是什么,这些都只是功能的问题,核心是我有了关系,只要能从这些元数据推导出来,那么ExtensionLoader都可以做到。

5. 高级

5.1 包装类

  在key-value映射中,会分为包装类和正常类,所谓的包装类就是利用装饰器模式,来实现对原功能进行一些额外的处理,识别方式是按照是否有一个构造方法含有这个接口作为参数为标识

5.2 注入

  这里的注入是指对接口里面的变量进行注入实例

还在更新......

dubbo源码分析--dubbo spi解析的更多相关文章

  1. Dubbo源码分析之 SPI(一)

    一.概述 dubbo SPI 在dubbo的作用是基础性的,要想分析研究dubbo的实现原理.dubbo源码,都绕不过 dubbo SPI,掌握dubbo SPI 是征服dubbo的必经之路. 本篇文 ...

  2. Dubbo源码分析之SPI(二)

    一.概述 本篇文章是dubbo SPI源码分析的第二篇,接着第一篇继续分析dubbo SPI的内容,我们主要介绍 getDefaultExtension() 获取默认扩展点方法. 由于此方法比较简单, ...

  3. dubbo源码分析2——SPI机制中的SPI实现类的读取和预处理

    SPI机制中的SPI实现类的读取和预处理是由ExtensionLoader类的loadFile方法来完成的 loadFile方法的作用是读取dubbo的某个SPI接口的spi描述文件,然后进行缓存,缓 ...

  4. dubbo源码分析6——SPI机制中的AOP

    在 ExtensionLoader 类的loadFile方法中有下图的这段代码: 类如现在这个ExtensionLoader中的type 是Protocol.class,也就是SPI接口的实现类中Xx ...

  5. dubbo源码分析5——SPI机制_AdaptiveExtension的原理和作用

    private T createAdaptiveExtension() { try { return injectExtension((T) getAdaptiveExtensionClass().n ...

  6. dubbo源码分析4——SPI机制_ExtensionFactory类的作用

    ExtensionFactory的源码: @SPI public interface ExtensionFactory { /** * Get extension. * * @param type o ...

  7. dubbo源码分析3——SPI机制中的ExtensionLoader类的objectFactory属性分析

    ExtensionLoader类是整个SPI的核心类,每个SPI都会对应一个ExtensionLoader类实例,这个类的构造方法如下: private ExtensionLoader(Class&l ...

  8. dubbo源码分析1——SPI机制的概要介绍

    插件机制是Dubbo用于可插拔地扩展底层的一些实现而定制的一套机制,比如dubbo底层的RPC协议.注册中心的注册方式等等.具体的实现方式是参照了JDK的SPI思想,由于JDK的SPI的机制比较简单, ...

  9. Dubbo源码分析之SPI(三)

    一.概述 本篇介绍自适应扩展,方法getAdaptiveExtension()的实现.ExtensionLoader类本身很多功能也使用到了自适应扩展.包括ExtensionFactory扩展. 通俗 ...

随机推荐

  1. 不需要SDK调用图灵机器人的方法

    图灵机器人的调用其实就是你给服务器发一个文字消息过去,他回你一个,看起来模仿人类对话一样. 不知道为什么要弄个SDK这么麻烦的方法,以前的接口官网上已经没有了,但是还是可以用的.返回的是JSON但也懒 ...

  2. 设备控制接口ioctl详解

    [转]Linux设备控制接口 序言设备驱动程序的一个基本功能就是管理和控制设备,同时为用户应用程序提供管理和控制设备的接口.我们前面的“Hello World”驱动程序已经可以提供读写功能了,在这里我 ...

  3. Html Meta标签记录

    记录学习过程中碰到的meta标签 方便今后查阅 X-UA-Compatible: 设置浏览器兼容 如<meta http-equiv="X-UA-Compatible" co ...

  4. CMake 自定义编译选项

    自定义编译选项 CMake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案. 例如,可以将 MathFunctions 库设为一个可选库,如果该选项为 ON ,就使用该库定义 ...

  5. Linux bind-utils

    一.简介 DNS是一种将域名解析为IP地址的服务.如:www.turbolinux.com.cn通过DNS解析,可以得到210.77.38.126.bind是linux系统下的一个DNS服务程序.bi ...

  6. 2、awk的输出

    1.常见的输出格式整理 awk '{print "this is " $1, $2, $1*$2, NR, NF, $NF}' file1   ###字符输出,字段输出,运算输出, ...

  7. 10.LIKE 操作符

    LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式. LIKE 操作符 LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式. SQL LIKE 操作符语法 SELECT colum ...

  8. hdu 4286 (list的reverse时间复杂度为n)

    list 的翻转reverse源码: // 将链表倒置 // 其算法核心是历遍链表, 每次取出一个结点, 并插入到链表起始点 // 历遍完成后链表满足倒置 template <class T, ...

  9. [GO]结构体及普通变量初始化

    结构体是一种聚合的数据类型,它是由一系列相同类型或者不同类型的数据构成的数据集合,每个数据称为结构体的成员 1.结构体的初始化 package main import "fmt" ...

  10. GC: CMS垃圾回收器三(实践)

    jstat -gc -t [pid] 1000 监控日志... ,抽取其中关键记录不一定连续 应用启动时间 2015-06-23 10:22:27 ,换算后,第二条记录时间是2015-06-24 22 ...