您好,欢迎访问代理记账网站
移动应用 微信公众号 联系我们

咨询热线 -

电话 15988168888

联系客服
  • 价格透明
  • 信息保密
  • 进度掌控
  • 售后无忧

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

Dubbo-SPI系列文章目录

Dubbo-SPI(一)-加载机制概述
Dubbo-SPI(五)-@Activate注解


文章目录

  • Dubbo-SPI系列文章目录
  • Java SPI(Service Provider Interface)
  • Dubbo SPI的改进
  • 扩展点配置规范
  • 扩展点的分类与缓存
  • 扩展点的特性
    • 自动包装
    • 自动加载
    • 自适应
    • 自动激活


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
  • 其他缓存:扩展类加载器缓存、扩展名缓存
集合名缓存类型
Holder<Map<String,Class<?>>> cachedClasses普通扩展类缓存,不包括自适应扩展类 和 包装扩展类
Set<Class<?>> cachedWrapperClasses包装扩展类缓存
Class<?> cachedAdaptiveClass自适应扩展类缓存,只能同时存在一个
Holder<Obejct> cachedAdaptiveInstance实例化后的 自适应扩展类的 对象,只能同时存在一个
============================
ConcurrendMap<Sting, Holder<Object>> cachedInstances扩展名 与 扩展对象缓存
Map<Stirng, Activate> cachedActivates扩展名 与 @Activate的缓存
============================
ConcurrendMap<Class<?>, ExtensionLoader<?>> EXTESION_LOADERS扩展类 与 对应的扩展类加载器缓存
ConcurrendMap<Class<?>, String> cachedNames扩展类 与 扩展名缓存
ConcurrendMap<Class<?>, Object> EXTESION_INSTANCES扩展类 与 类初始化后的实例

扩展点的特性

自动包装

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

自动加载

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

自适应

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

自动激活

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


分享:

低价透明

统一报价,无隐形消费

金牌服务

一对一专属顾问7*24小时金牌服务

信息保密

个人信息安全有保障

售后无忧

服务出问题客服经理全程跟进