Dubbo SPI:(version:2.6.*)
Dubbo 微内核 + 插件 模式,得益于 Dubbo SPI 。其中 ExtentionLoader是 Dubbo SPI 最核心的类,它负责扩展点的加载和生命周期管理。
ExtensionLoader
ExtensionLoader 类似于 Java SPI 的 ServiceLoader,负责扩展的加载和生命周期维护,它是 Dubbo SPI 最核心的类。
Dubbo SPI 扩展点机制的基本概念
- 扩展点(Extension Point)
是一个Java的接口。 - 扩展(Extension)
扩展点的实现类。 - 扩展实例(Extension Instance)
扩展点实现类的实例。 - 扩展自适应实例(Extension Adaptive Instance)
扩展自适应实例(getAdaptiveExtension)就是一个 Extension 的代理,它实现了扩展点接口。在调用扩展点的接口方法时,会根据实际的参数来决定要使用哪个扩展。 - @SPI
@SPI 注解作用于扩展点的接口上,表明该接口是一个扩展点,可以被 Dubbo 的ExtentionLoader 加载。如果没有此注解的话, ExtensionLoader.getExtensionLoader(type) 调用会异常。 - @Adaptive
@Adaptive 注解使用在类上,表示这个类是一个扩展自适应类。当调用 ExtensionLoader.getExtensionLoader(type).getAdaptiveExtension() 会获取到该扩展自适应类的实例。@Adaptive 注解使用在方法上,表示该方法是一个自适应方法。Dubbo 在为扩展点生成扩展自适应实例时,如果方法上有 @Adaptive 注解,会为该方法生成对应的实现。实现方法内部会根据方法的参数,来决定使用哪个扩展。
使用最频繁的 API 有如下几个:
- public static ExtensionLoader getExtensionLoader(Class type)-- 获取 type 类对应的 ExtensionLoader
- public T getAdaptiveExtension()-- 获取扩展自适应实例(扩展适配器)。扩展点适配器的实现中,一般会调用下面的 API 来获取指定的扩展点实例warn: dubbo 中大多数的扩展实例,都是通过扩展点匹配器 AdaptiveExtension 来获取的
- public T getExtension(String name)-- 根据 name 获取指定的扩展实例
- public T getDefaultExtension()-- 获取 @SPI value 中指定的默认扩展点
- public List getActivateExtension(URL url, String key)-- 获取被激活的扩展点集合
举例:
上面的 Protocol 是一个 SPI 接口,@SPI("dubbo") 表示它默认的扩展点是 spi 文件里面 name 为 dubbo 的扩展点。
export() 和 refer() 方法都带有 @Adaptive 注解,它表示在获取 Protocol 类的自适应扩展实例(getAdaptiveExtension)时,会自动为这两个方法动态生成方法实现(使用 javassist 字节码技术动态生成)。
SPI 源码分析的关键
阅读 ExtentionLoader 的源码,关键在于阅读源码时搞清楚 ExtentionLoader 里面的几个缓存变量的意思
cachedAdaptiveInstance -- 缓存自适应扩展实例cachedClasses -- 缓存 SPI 扩展类 cachedDefaultName -- 缓存 @SPI 的 valuecachedAdaptiveClass -- 缓存 @Adaptive 标记的 SPI 扩展cachedWrapperClasses -- 缓存 wrapperClasscachedActivates -- 缓存 cachedNames -- 缓存
搞清楚了上面几个缓存的意思后,再去读 ExtentionLoader 的源码,那就小菜一碟了