基于:Dubbo SPI
使用Wrapper 类对扩展点进行自动包装。Wrapper 类也实现了扩展点接口,但是 Wrapper 不是扩展点的真正实现。它的用途主要是包装真正的扩展点实现。即从 ExtensionLoader 中返回的实际上是 Wrapper 类的实例,Wrapper 持有了实际的扩展点实现类。

一、加载流程

  1. ExtensionLoader<Protocol> extensionLoader = ExtensionLoader.getExtensionLoader(Protocol.class);
  2. //获取到的实例为Wrapper类型
  3. Protocol protocol = extensionLoader.getExtension("http");
  4. System.out.println(protocol);
  1. 入参:扩展点接口Class(例如:Protocol.class)类型,初始化扩展点加载器。
    1. 首先利用JDK SPI机制加载所有dubbo扩展点加载策略(即开启dubbo spi功能)。ExtensionLoader#loadLoadingStrategies();
    2. 在构造函数中,利用加载器type记录,扩展点接口Class类型,
    3. 在构造函数中,初始化扩展点工厂实例(objectFactory)仍然是先。
      1. 如果是ExtensionFactory.class,则不需要工厂实例
      2. 如果非ExtensionFactory.class,则先通过步骤1,获取ExtensionFactory.class加载器,并调用getAdaptiveExtension(),获得工厂实例(objectFactory
      3. 加载ExtensionFactory类型实现类,并实例化。路径:META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory

  2. 根据名称(例如:http),从缓存cachedClasses中获取具体实现类
    1. 获取SPI注解,在接口(例如:Protocol.class)配置的默认实现类名称
    2. 加载扩展点接口Class(例如:Protocol.class)类型所有实现类。并缓存至cachedClasses
    3. 反射实例化、依赖注入
    4. 生成包装类型,并调用初始化方法

      SPI 加载器初始化

      1. public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
      2. //1.非空判断
      3. if (type == null) {
      4. throw new IllegalArgumentException("Extension type == null");
      5. }
      6. //2.Class类必须为接口
      7. if (!type.isInterface()) {
      8. throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
      9. }
      10. //3.接口类必须被 @SPI 标记
      11. if (!withExtensionAnnotation(type)) {
      12. throw new IllegalArgumentException("Extension type (" + type +
      13. ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
      14. }
      15. //4.根据Class,从本地缓存中获取加载器。如果为空初始化加载器,并放入缓存中
      16. ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
      17. if (loader == null) {
      18. EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
      19. loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
      20. }
      21. return loader;
      22. }

      加载SPI 扩展点

      SPI 加载流程

image.png