Dubbo-SPI(一)-加载机制概述

Dubbo-SPI系列文章目录

Dubbo-SPI(一)-加载机制概述
Dubbo-SPI(二)-@SPI注解
Dubbo-SPI(三)-getExtension实现原理
Dubbo-SPI(四)-@Adaptive注解
Dubbo-SPI(五)-@Activate注解



Java SPI(Service Provider Interface)

Java SPI 使用了 策略模式,一个接口 多种实现
只需要声明接口
具体的实现并不在程序中 直接确定
而是由程序之外的配置掌控,用于具体实现的装配
步骤如下:

  1. 定义一个接口 及 对应方法
  2. 对接口进行实现
  3. 在META/service/ 目录下,创建一个 以 接口全路径 命名的文件
  4. 文件内中 为 具体实现类的 全路径名,如果有多个,用分行符 分隔
  5. 在代码中 通过 java.util.ServiceLoader 来加载 具体的 实现类

Dubbo SPI的改进

  • Java SPI 会 一次性 实例化 扩展点的所有实现,扩展实现可能很耗时,也可能用不上,会浪费资源
  • 如果扩展加载失败,连扩展的名称都获取不到,异常信息也可能会被 “吞掉”,问题追踪比较困难;Dubbo SPI 在扩展 加载失败的时候 会 先抛出 真实异常 并 打印日志,扩展点 在 被动加载的时候,即使 有部分扩展加载失败 也不会影响 其他扩展点和整个框架的使用
  • Dubbo SPI 增加了 对扩展的 IOC 和 AOP 支持,一个扩展 可以 直接setter注入 其他扩展
  • Dubbo SPI 只是加载 配置文件中的类,并 分成 不同种类的缓存 放在内存中,而不会 立即 全部 初始化,在性能上会有更好的表现
  • Dubbo SPI 支持 包装 扩展类,推荐 把通用的抽象逻辑 放在 包装类中,用于实现扩展点的AOP特性。这和Spring的动态代理 思想一样,在被代理类 的 前后 插入自己的逻辑 进行增强

扩展点配置规范

规范名规范说明
SPI配置文件路径META-INF/services(兼容Java SPI)、META-INF/dubbo/(用户扩展)、META-INF/dubbo/internal (Dubbo内部使用)
SPI配置文件名称全路径类名
文件内容格式key=value,多个 用 换行符 分隔

扩展点的分类与缓存

  • Class缓存:Dubbo SPI 获取 扩展类时,会先从缓存中读取。如果缓存中不存在,则 加载配置文件,根据配置 把Class 缓存到内存中,并不会直接 全部初始化
  • 实例缓存:缓存 实例化后的对象,每次获取的时候,会先从缓存中读取,如果缓存中读取不到,则重新加载 并 缓存起来,按需实例化并缓存

被缓存的Class和对象实例 可以根据不同的特性 分别不同的类别

  • 普通扩展类:最基础的,配置在SPI配置文件中的 扩展类实现
  • 包装扩展类:这种Wrapper(包装)类 没有具体的实现逻辑,只是做了通过逻辑的抽象,并且 需要 在构造方法中 传入 一个 具体的 扩展接口的实现
  • 自适应扩展类:一个扩展接口 会有 多种实现类,具体使用哪个,可以不写死在配置 或者 代码中,在运行时,通过传入URL对象中的 某些参数parameter来动态确定,相关注解是@Adaptive
  • 其他缓存:扩展类加载器缓存、扩展名缓存

Class缓存

集合名缓存类型
Holder<Map<String,Class<?>>> cachedClasses普通扩展类缓存,不包括自适应扩展类 和 包装扩展类
Set<Class<?>> cachedWrapperClasses包装扩展类缓存
Class<?> cachedAdaptiveClass自适应扩展类缓存,只能同时存在一个
Map<Stirng, Activate> cachedActivates扩展名 与 @Activate(自动激活)的缓存
ConcurrendMap<Class<?>, ExtensionLoader<?>> EXTESION_LOADERS扩展类 与 对应的类加载器缓存
ConcurrendMap<Class<?>, String> cachedNames扩展类 与 扩展名缓存

实例缓存

集合名缓存类型
Holder<Obejct> cachedAdaptiveInstance实例化后的 自适应扩展类的 对象,只能同时存在一个
ConcurrendMap<Sting, Holder<Object>> cachedInstances扩展名 与 扩展对象实例缓存
ConcurrendMap<Class<?>, Object> EXTESION_INSTANCES扩展类 与 类初始化后的实例

扩展点的特性

自动包装

ExtensionLoader在加载扩展时,如果发现 这个扩展类 包含 其他扩展点 作为 构造函数的参数,则这个扩展类 就会被认为是 封装类

自动加载

如果某个扩展类 是 另外一个 扩展类的成员属性,并且拥有setter方法,那么 框架也会 自动注入 对应的 扩展点实例。

自适应-Adaptive

使用@Adaptive注解,可以 动态地 通过URL中的参数 来确定 要使用哪一个具体的实现类,从而解决 自动加载中的 实例注入问题

自动激活-Activate

使用@Activate注解,可以标记 对应的扩展点 默认被激活启用这个注解 还可以通过 传入不同的参数,设置 扩展点 在不同的条件下 被 自动激活
主要使用场景 是 某个扩展点 的 多个实现类 需要同时启用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值