6-Dubbo Extension Wrapper 包装扩展源码解析

作者: vnjohn / 发表于 2025-05-20 / 专栏: Dubbo 3.3

Dubbo3, 源码

6.1 普通扩展对象的加载与创建

分析 ExtensionLoader 类型的 getExtension(String name) 方法,通过自适应扩展的铺垫,这里理解起来就更容易了

getExtension 是根据扩展名字获取具体扩展的通用方法,下面以某个类型来获取扩展进行举例

ApplicationModel 中获取配置管理器对象

configManager = (ConfigManager) this.getExtensionLoader(ApplicationExt.class).getExtension(ConfigManager.NAME);

6.1.1 getExtension 源码

先看下 ExtensionLoader#getExtension 方法源码,根据扩展名字查询扩展对象

public T getExtension(String name) {
  // 传入参数 wrap 为 true
  T extension = getExtension(name, true);
  if (extension == null) {
    throw new IllegalArgumentException("Not find extension: " + name);
  }
  return extension;
}

@SuppressWarnings("unchecked")
public T getExtension(String name, boolean wrap) {
  // 检查扩展加载器是否已被销毁
  checkDestroyed();
  if (StringUtils.isEmpty(name)) {
    throw new IllegalArgumentException("Extension name == null");
  }
  // 扩展名字为 true 则加载默认扩展
  if ("true".equals(name)) {
    return getDefaultExtension();
  }
  String cacheKey = name;
  // 非 wrap 类型则将缓存的扩展名字 key 加上 _origin 后缀
  // wrap 属于 aop 机制,俗称切面
  // 这个 origin 在 aop 里面可以称为切点,下面的 wrap 扩展可以称为增强通知的类型,普通扩展和 wrap 扩展的扩展名字是一样的
  if (!wrap) {
    cacheKey += "_origin";
  }
  // 从 cachedInstances 缓存中查询
  final Holder<Object> holder = getOrCreateHolder(cacheKey);
  Object instance = holder.get();
  // 缓存中不存在则创建扩展对象 双重校验锁
  if (instance == null) {
    synchronized (holder) {
      instance = holder.get();
      if (instance == null) {
        instance = createExtension(name, wrap);
        holder.set(instance);
      }
    }
  }
  return (T) instance;
}

先着手来看下默认扩展的加载代码:

public T getDefaultExtension() {
  // 加载扩展类型对应的所有扩展 SPI 实现类型
  // 在加载所有扩展实现类型的时候会缓存这个扩展的默认实现类型,将对象缓存在 cachedDefaultName 中
  getExtensionClasses();
  if (StringUtils.isBlank(cachedDefaultName) || "true".equals(cachedDefaultName)) {
    return null;
  }
  // 再回到加载扩展的方法
  return getExtension(cachedDefaultName);
}

创建扩展对象 ExtensionLoader#createExtension 方法和自适应扩展的创建过程类似,具体过程如下:

  1. 加载扩展类型:getExtensionClasses
  2. 创建扩展对象:createExtensionInstance(clazz)
  3. 注入自适应扩展:injectExtension(instance)
  4. wrapper 包装处理
private T createExtension(String name, boolean wrap) {
  // 扩展的创建的第一步扫描所有 jar 中的扩展实现,扫描完之后获取对应名字的扩展实现 Class 对象
  Class<?> clazz = getExtensionClasses().get(name);
  if (clazz == null || unacceptableExceptions.contains(name)) {
    // 出现异常,转换异常信息以后再抛出
    throw findException(name);
  }
  try {
    // 当前扩展对象是否已经创建过了则直接从缓存中获取
    T instance = (T) extensionInstances.get(clazz);
    if (instance == null) {
      // 第一次获取缓存中肯定没有则创建扩展对象然后缓存起来
      extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
      instance = (T) extensionInstances.get(clazz);
      instance = postProcessBeforeInitialization(instance, name);
      // 注入自适应扩展方法的自适应扩展对象,该方法前面讲自适应扩展时候说了
      injectExtension(instance);
      instance = postProcessAfterInitialization(instance, name);
    }
    // 是否开启了 wrap -> Dubbo 通过 Wrapper 实现 AOP
    if (wrap) {
      List<Class<?>> wrapperClassesList = new ArrayList<>();
      // wrap 类型排序 这个 wrap 类型是如何来的呢
      // 在前面扫描扩展类型时,若当前扩展类型不是 Adaptive 注解修饰的,并且当前类型 type 有个构造器参数是 type 自身的
      // 也是在前面加载扩展类型时说的装饰器模式,可以参考 DubboProtocol 构造器
      if (cachedWrapperClasses != null) {
        wrapperClassesList.addAll(cachedWrapperClasses);
        // 根据 Wrapper 注解 order 值来进行排序值越小越在列表的前面
        wrapperClassesList.sort(WrapperComparator.COMPARATOR);
        // 反转之后值越大就会在列表的前面
        Collections.reverse(wrapperClassesList);
      }
      // 从缓存中查到了 wrapper 扩展则遍历这些 wrapper 扩展进行筛选
      if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
        for (Class<?> wrapperClass : wrapperClassesList) {
          Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
          // 需要包装的扩展名。当此数组为空时,默认值为匹配
          // wrapper 注解不存在或者 matches 匹配,或者 mismatches 不包含当前扩展
          // 若匹配到了说明当前扩展对象需要进行 wrapper,就创建 wrapper 扩展对象后进行包装
          boolean match = (wrapper == null)
            || ((ArrayUtils.isEmpty(wrapper.matches())
                 || ArrayUtils.contains(wrapper.matches(), name))
                && !ArrayUtils.contains(wrapper.mismatches(), name));
          if (match) {
            // 一旦匹配就创建所有 wrapper 类型对象,同时将构造器参数设置为当前类型
            instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
            instance = postProcessAfterInitialization(instance, name);
          }
        }
      }
    }
    // Warning: After an instance of Lifecycle is wrapped by cachedWrapperClasses, 
    // it may not still be Lifecycle instance, this application may not invoke the lifecycle.initialize hook.
    // 初始化扩展,如果当前扩展是 Lifecycle 类型则调用初始化方法
    initExtension(instance);
    return instance;
  } catch (Throwable t) {
    throw new IllegalStateException(
      "Extension instance (name: " + name + ", class: " + type + ") couldn't be instantiated: "
      + t.getMessage(),
      t);
  }
}

6.1.2 创建扩展对象

前面加载扩展类型在自适应扩展 ExtensionLoader#createAdaptiveExtension 方法已经说过了,这里具体来看下扩展对象的方法创建过程:createExtensionInstance

前面创建自适应扩展对象时仅仅是使用反射 newInstance 操作,而创建普通的扩展对象过程就相对复杂一点,接下来看下 ExtensionLoader#createExtensionInstance 方法

private Object createExtensionInstance(Class<?> type) throws ReflectiveOperationException {
  // 在 ExtensionLoader 构造器中,有个 initInstantiationStrategy 方法中 new 了一个初始化策略 InstantiationStrategy 类型对象
  return instantiationStrategy.instantiate(type);
}

实例化对象方法:InstantiationStrategy#instantiate

public <T> T instantiate(Class<T> type) throws ReflectiveOperationException {
  // should not use default constructor directly, maybe also has another constructor matched scope model arguments
  // 1. try to get default constructor
  Constructor<T> defaultConstructor = null;
  try {
    // 反射获取对应类型的无参构造器
    defaultConstructor = type.getConstructor();
  } catch (NoSuchMethodException e) {
    // ignore no default constructor
  }
  // 2. use matched constructor if found
  List<Constructor<?>> matchedConstructors = new ArrayList<>();
  // 获取所有构造器
  Constructor<?>[] declaredConstructors = type.getConstructors();
  for (Constructor<?> constructor : declaredConstructors) {
    // 校验构造器参数类型是否为 ScopeModel 类型,若为 ScopeModel 则是匹配的构造器
    // 说明扩展类型在这个版本想要让这个构造器生效,参数类型必须为 ScopeModel
    if (isMatched(constructor)) {
      matchedConstructors.add(constructor);
    }
  }
  // remove default constructor from matchedConstructors
  if (defaultConstructor != null) {
    matchedConstructors.remove(defaultConstructor);
  }
  /*
   match order:
   1. the only matched constructor with parameters
   2. default constructor if absent
   */
  Constructor<?> targetConstructor;
  // 匹配的参数 ScopeModel 构造器太多了就抛出异常
  if (matchedConstructors.size() > 1) {
    throw new IllegalArgumentException("Expect only one but found " + matchedConstructors.size()
                                       + " matched constructors for type: " + type.getName() + ", matched constructors: "
                                       + matchedConstructors);
    // 一个参数一般为一个参数类型 ScopeModel 构造器
  } else if (matchedConstructors.size() == 1) {
    targetConstructor = matchedConstructors.get(0);
    // 如果没有自定义构造器则使用空参数构造器
  } else if (defaultConstructor != null) {
    targetConstructor = defaultConstructor;
  } else {
    // 没有自定义构造器,抛出异常
    throw new IllegalArgumentException("None matched constructor was found for type: " + type.getName());
  }
  // create instance with arguments
  // 反射获取构造器参数的参数类型列表
  Class<?>[] parameterTypes = targetConstructor.getParameterTypes();
  Object[] args = new Object[parameterTypes.length];
  for (int i = 0; i < parameterTypes.length; i++) {
    // 借助 scopeModelAccessor 工具获取参数类型,这个参数类型为当前的域模型对象
    args[i] = getArgumentValueForType(parameterTypes[i]);
  }
  return (T) targetConstructor.newInstance(args);
}

6.2 Wrap 机制

6.2.1 Wrapper 机制说明

Dubbo 通过 Wrapper 实现 AOP,Wrapper 机制,即扩展点自动包装

Wrapper 类同样实现了扩展点接口,但是 Wrapper 不是扩展点的真正实现。其用途主要是用于从 ExtensionLoader 返回扩展点时,包装在真正的扩展点实现类。

从 ExtensionLoader 中返回的实际上是 Wrapper 类的实例,Wrapper 持有了实际的扩展点实现类

扩展点的 Wrapper 类可以有多个,也可以按照需要进行新增。通过 Wrapper 类可以将所有扩展点公共逻辑迁移至 Wrapper 中,新加的 Wrapper 在所有的扩展点上添加了逻辑,有些类似 AOP,即 Wrapper 代理了扩展点

Wrapper 规范 Wrapper 机制不是通过注解实现的,而是通过一套 Wrapper 规范实现的,Wrapper 类在定义时要遵循如下规范:

  1. 类要实现 SPI 接口
  2. 类中要持有 SPI 接口的引用
  3. 类中必须含有一个带参的构造方法且参数只能有一个类型为 SPI 接口
  4. 在接口实现方法中要调用 SPI 接口引用对象的相应方法
  5. 类名称以 Wrapper 结尾

比如有如下几个扩展类型:

class org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
class org.apache.dubbo.qos.protocol.QosProtocolWrapper
class org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
class org.apache.dubbo.qos.protocol.QosProtocolWrapper

6.2.2 扫描 Wrapper 类型

回顾下 Wrapper 扩展类型的扫描用于对象的创建,Wrapper 类型的扫描代码(来自 5.2.3 小节的 ExtensionLoader#loadClass 方法)如下:

if (clazz.isAnnotationPresent(Adaptive.class)) {
  cacheAdaptiveClass(clazz, overridden);
// 扩展子类型构造器中是否有这个类型的接口 (这个可以想象下我们了解的 Java IO 流中的类型使用到的装饰器模式 构造器传个类型)
} else if (isWrapperClass(clazz)) {
  cacheWrapperClass(clazz);
} else {
// Activate 类型扫描
}

isWrapperClass 方法通过判断构造器类型是否将当前类型标识为 Wrapper 类型

protected boolean isWrapperClass(Class<?> clazz) {
  Constructor<?>[] constructors = clazz.getConstructors();
  for (Constructor<?> constructor : constructors) {
    // 参数类型只有一个,并且参数类型 = 当前 SPI 接口类型
    if (constructor.getParameterTypes().length == 1 && constructor.getParameterTypes()[0] == type) {
      return true;
    }
  }
  return false;
}

若当前类型满足 Wrapper 条件,将其追加到 ExtensionLoader cachedWrapperClasses 集合元素中

6.2.3 创建 Wrapper 类型

将 6.1.1 小节分析到的 ExtensionLoader#createExtension 方法部分代码截取过来

ExtensionLoader#getExtension 方法获取扩展对象时,会查询扩展对象是否有对应的 Wrapper 类型可扩展,再为其创建 Wrapper 扩展对象,如下代码所示:

// 是否开启了wrap -> Dubbo 通过 Wrapper 实现 AOP
if (wrap) {
  List<Class<?>> wrapperClassesList = new ArrayList<>();
  // wrap 类型排序 这个 wrap 类型是如何来的呢
  // 在前面扫描扩展类型时,若当前扩展类型不是 Adaptive 注解修饰的,并且当前类型 type 有个构造器参数是 type 自身的
  // 也是在前面加载扩展类型时说的装饰器模式,可以参考 DubboProtocol 构造器
  if (cachedWrapperClasses != null) {
    wrapperClassesList.addAll(cachedWrapperClasses);
    // 根据 Wrapper 注解 order 值来进行排序值越小越在列表的前面
    wrapperClassesList.sort(WrapperComparator.COMPARATOR);
    // 反转之后值越大就会在列表的前面
    Collections.reverse(wrapperClassesList);
  }
  // 从缓存中查到了 wrapper 扩展则遍历这些 wrapper 扩展进行筛选
  if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
    for (Class<?> wrapperClass : wrapperClassesList) {
      Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
      // 需要包装的扩展名。当此数组为空时,默认值为匹配
      // wrapper 注解不存在或者 matches 匹配,或者 mismatches 不包含当前扩展
      // 若匹配到了说明当前扩展对象需要进行 wrapper,就创建 wrapper 扩展对象后进行包装
      boolean match = (wrapper == null)
        || ((ArrayUtils.isEmpty(wrapper.matches())
             || ArrayUtils.contains(wrapper.matches(), name))
            && !ArrayUtils.contains(wrapper.mismatches(), name));
      if (match) {
        // 一旦匹配就创建所有 wrapper 类型对象,同时将构造器参数设置为当前类型
        instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
        instance = postProcessAfterInitialization(instance, name);
      }
    }
  }
}

主要是要看在什么情况下才能为当前扩展类型来创建 Wrapper 包装类型:

  1. Wrapper 注解不存在,前面 6.2.2 是可以通过构造函数来满足 Wrapper 包装条件的
  2. 存在 Wrapper 注解:matches 属性匹配或者 mismatches 属性不包含当前扩展名称

若匹配到当前扩展对象是需要进行 Wrapper 的,就为当前扩展创建 Wrapper 扩展对象后进行包装

6.3 Wrapper 包装扩展类加载流程图

在这里插入图片描述

参考文献

https://www.ktyhub.com/zh/chapter_dubbo/6-extension-wrapper/

vnjohn

作者

vnjohn

后端研发工程师。喜欢探索新技术,空闲时也折腾 AIGC 等效率工具。 可以在 GitHub 关注我了解更多,也可以加我微信(vnjohn) 与我交流。