<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Dubbo SPI擴展機制源碼詳解(基于2.7.10)

      Dubbo SPI

      一. 概述

      本文主要分享 Dubbo 的拓展機制 SPI

      想要理解 Dubbo ,理解 Dubbo SPI 是非常必須的。在 Dubbo 中,提供了大量的拓展點,基于 Dubbo SPI 機制加載

      Dubbo SPI官方文檔:Dubbo SPI 概述 | Apache Dubbo

      本文基于 Dubbo 2.7.10 版本

      二. Dubbo SPI特性

      在看具體的 Dubbo SPI 實現之前,我們先理解 Dubbo SPI 產生的背景:

      Dubbo 的擴展點加載從 JDK 標準的 SPI (Service Provider Interface) 擴展點發現機制加強而來。

      Dubbo 改進了 JDK 標準的 SPI 的以下問題:

      1. JDK 標準的 SPI 會一次性實例化擴展點所有實現,如果有擴展實現初始化很耗時,但如果沒用上也加載,會很浪費資源。
      2. 如果擴展點加載失敗,連擴展點的名稱都拿不到了。比如:JDK 標準的 ScriptEngine,通過 getName() 獲取腳本類型的名稱,但如果 RubyScriptEngine 因為所依賴的 jruby.jar 不存在,導致 RubyScriptEngine 類加載失敗,這個失敗原因被吃掉了,和 ruby 對應不起來,當用戶執行 ruby 腳本時,會報不支持 ruby,而不是真正失敗的原因。
      3. 增加了對擴展點 IoC 和 AOP 的支持,一個擴展點可以直接 setter 注入其它擴展點。

      用戶能夠基于 Dubbo 提供的擴展能力,很方便基于自身需求擴展其他協議、過濾器、路由等。下面介紹下 Dubbo 擴展能力的特性。

      • 按需加載。Dubbo 的擴展能力不會一次性實例化所有實現,而是用那個擴展類則實例化那個擴展類,減少資源浪費。
      • 增加擴展類的 IOC 能力。Dubbo 的擴展能力并不僅僅只是發現擴展服務實現類,而是在此基礎上更進一步,如果該擴展類的屬性依賴其他對象,則 Dubbo 會自動的完成該依賴對象的注入功能。
      • 增加擴展類的 AOP 能力。Dubbo 擴展能力會自動的發現擴展類的包裝類,完成包裝類的構造,增強擴展類的功能。
      • 具備動態選擇擴展實現的能力。Dubbo 擴展會基于參數,在運行時動態選擇對應的擴展類,提高了 Dubbo 的擴展能力。
      • 可以對擴展實現進行排序。能夠基于用戶需求,指定擴展實現的執行順序。
      • 提供擴展點的 Adaptive 能力。該能力可以使的一些擴展類在 consumer 端生效,一些擴展類在 provider 端生效。

      從 Dubbo 擴展的設計目標可以看出,Dubbo 實現的一些例如動態選擇擴展實現、IOC、AOP 等特性,能夠為用戶提供非常靈活的擴展能力。

      三. 代碼結構

      Dubbo SPI 在 dubbo-commonorg.apache.dubbo.common.extension 包實現,如下圖所示:

      四. ExtensionLoader

      org.apache.dubbo.common.extension.ExtensionLoader ,拓展加載器。這是 Dubbo SPI 的核心

      4.1 屬性

       /**
           * 拓展加載器集合
           */
          private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(64);
      
          /**
           * 拓展加載器集合
           * key:拓展接口
           */
          private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>(64);
          /**
           * 拓展接口
           */
          private final Class<?> type;
          /**
           * 對象工廠
           *
           * 用于調用 {@link #injectExtension(Object)} 方法,向拓展對象注入依賴屬性。
           *
           * 例如,StubProxyFactoryWrapper 中有 `Protocol protocol` 屬性。
           */
          private final ExtensionFactory objectFactory;
          /**
           * 緩存的拓展名與拓展類的映射。
           *
           * 和 {@link #cachedClasses} 的 KV 對調。
           *
           * 通過 {@link #loadExtensionClasses} 加載
           */
          private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();
      
          /**
           * 緩存的拓展實現類集合。
           *
           * 不包含如下兩種類型:
           *  1. 自適應拓展實現類。例如 AdaptiveExtensionFactory
           *  2. 帶唯一參數為拓展接口的構造方法的實現類,或者說拓展 Wrapper 實現類。例如,ProtocolFilterWrapper 。
           *   拓展 Wrapper 實現類,會添加到 {@link #cachedWrapperClasses} 中
           *
           * 通過 {@link #loadExtensionClasses} 加載
           */
          private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
          /**
           * 拓展名與 @Activate 的映射
           *
           * 例如,AccessLogFilter。
           *
           * 用于 {@link #getActivateExtension(URL, String)}
           */
          private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>();
          /**
           * 緩存的拓展對象集合
           *
           * key:拓展名
           * value:拓展對象
           *
           * 例如,Protocol 拓展
           *      key:dubbo value:DubboProtocol
           *      key:injvm value:InjvmProtocol
           *
           * 通過 {@link #loadExtensionClasses} 加載
           */
          private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
          /**
           * 緩存的自適應( Adaptive )拓展對象
           */
          private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
          /**
           * 緩存的自適應拓展對象的類
           *
           * {@link #getAdaptiveExtensionClass()}
           */
          private volatile Class<?> cachedAdaptiveClass = null;
          /**
           * 緩存的默認拓展名
           *
           * 通過 {@link SPI} 注解獲得
           */
          private String cachedDefaultName;
          /**
           * 創建 {@link #cachedAdaptiveInstance} 時發生的異常。
           *
           * 發生異常后,不再創建,參見 {@link #createAdaptiveExtension()}
           */
          private volatile Throwable createAdaptiveInstanceError;
          /**
           * 拓展 Wrapper 實現類集合
           *
           * 帶唯一參數為拓展接口的構造方法的實現類
           *
           * 通過 {@link #loadExtensionClasses} 加載
           */
          private Set<Class<?>> cachedWrapperClasses;
          /**
           * 拓展名 與 加載對應拓展類發生的異常 的 映射
           *
           * key:拓展名
           * value:異常
           *
           * 在 {@link #loadFile(Map, String)} 時,記錄
           */
          private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<>();
      
          private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();
      

      我們將屬性分成了兩類:1)靜態屬性;2)對象屬性。這是為啥呢?

      • 【靜態屬性】一方面,ExtensionLoader 是 ExtensionLoader 的管理容器。一個拓展( 拓展接口 )對應一個 ExtensionLoader 對象。例如,Protocol 和 Filter 分別對應一個 ExtensionLoader 對象。
      • 【對象屬性】另一方面,一個拓展通過其 ExtensionLoader 對象,加載它的拓展實現們。我們會發現多個屬性都是 “cached” 開頭。ExtensionLoader 考慮到性能和資源的優化,讀取拓展配置后,會首先進行緩存。等到 Dubbo 代碼真正用到對應的拓展實現時,進行拓展實現的對象的初始化。并且,初始化完成后,也會進行緩存。也就是說:
        • 緩存加載的拓展配置
        • 緩存創建的拓展實現對象

      4.2 獲得拓展配置

      4.2.1 getExtensionClasses
          /**
           * 緩存的拓展實現類集合。
           *
           * 不包含如下兩種類型:
           *  1. 自適應拓展實現類。例如 AdaptiveExtensionFactory
           *  2. 帶唯一參數為拓展接口的構造方法的實現類,或者說拓展 Wrapper 實現類。例如,ProtocolFilterWrapper 。
           *   拓展 Wrapper 實現類,會添加到 {@link #cachedWrapperClasses} 中
           *
           * 通過 {@link #loadExtensionClasses} 加載
           */
          private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
          /**
           * 緩存的自適應拓展對象的類
           *
           * {@link #getAdaptiveExtensionClass()}
           */
          private volatile Class<?> cachedAdaptiveClass = null;
          /**
           * 拓展 Wrapper 實現類集合
           *
           * 帶唯一參數為拓展接口的構造方法的實現類
           *
           * 通過 {@link #loadExtensionClasses} 加載
           */
          private Set<Class<?>> cachedWrapperClasses;
      
      
      	/**
           * 獲得拓展實現
           *
           * @return 拓展實現類數組
           */
          private Map<String, Class<?>> getExtensionClasses() {
              // 從緩存中,獲得拓展實現類數組
              Map<String, Class<?>> classes = cachedClasses.get();
              if (classes == null) {
                  synchronized (cachedClasses) {
                      classes = cachedClasses.get();
                      if (classes == null) {
                          // 從配置文件中,加載拓展實現類數組
                          classes = loadExtensionClasses();
                          // 設置到緩存中
                          cachedClasses.set(classes);
                      }
                  }
              }
              return classes;
          }
      
      • cachedClasses屬性,緩存的拓展實現類集合。它不包含如下兩種類型的拓展實現:
        • 自適應拓展實現類。例如 AdaptiveExtensionFactory 。
          • 拓展 Adaptive 實現類,會添加到 cachedAdaptiveClass 屬性中。
        • 帶唯一參數為拓展接口的構造方法的實現類,或者說拓展 Wrapper 實現類。例如,ProtocolFilterWrapper 。
          • 拓展 Wrapper 實現類,會添加到 cachedWrapperClasses 屬性中。
        • 總結來說,cachedClasses + cachedAdaptiveClass + cachedWrapperClasses 才是完整緩存的拓展實現類的配置。
      4.2.2 loadExtensionClasses
          private Map<String, Class<?>> loadExtensionClasses() {
              // 加載默認的拓展名
              cacheDefaultExtensionName();
      
              Map<String, Class<?>> extensionClasses = new HashMap<>();
      
              // 循環加載策略,加載對應的拓展實現
              for (LoadingStrategy strategy : strategies) {
                  loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
                  // 為了兼容 2.7 之前的老版本。在2.7之前,Dubbo還未進入Apache孵化,包名還是Alibaba
                  loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
              }
      
              return extensionClasses;
          }
      

      第一步:加載默認的擴展名

      第二步:遍歷加載策略數組,去加載不同文件夾下的擴展。

      strategies屬性是在啟動時,在 loadLoadingStrategies 方法中通過 Java SPI 加載的 LoadingStrategy 接口的實現類。

          private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();
      
          private static LoadingStrategy[] loadLoadingStrategies() {
              return stream(load(LoadingStrategy.class).spliterator(), false)
                      .sorted()
                      .toArray(LoadingStrategy[]::new);
          }
      

      它會讀取 META-INF/services 下的 org.apache.dubbo.common.extension.LoadingStrategy 文件中注冊的實現類:

      這些實現類中會指定,需要加載的拓展的配置文件路徑:

      public class DubboInternalLoadingStrategy implements LoadingStrategy {
      
          // 加載 META-INF/dubbo/internal/ 下的擴展實現
          @Override
          public String directory() {
              return "META-INF/dubbo/internal/";
          }
      
          @Override
          public int getPriority() {
              return MAX_PRIORITY;
          }
      }
      

      loadDirectory方法

          private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type,
                                     boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {
              // 獲得完整的文件名( 相對路徑 )。例如:"META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory" 。
              String fileName = dir + type;// 第4行
              try {
                  // 獲得文件名對應的所有文件數組
                  Enumeration<java.net.URL> urls = null;
                  ClassLoader classLoader = findClassLoader();
      
                  // try to load from ExtensionLoader's ClassLoader first
                  if (extensionLoaderClassLoaderFirst) {
                      ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
                      if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
                          urls = extensionLoaderClassLoader.getResources(fileName);
                      }
                  }
      
                  if (urls == null || !urls.hasMoreElements()) { // 第 18 行
                      if (classLoader != null) {
                          urls = classLoader.getResources(fileName);
                      } else {
                          urls = ClassLoader.getSystemResources(fileName);
                      }
                  } // 第 24 行
      
                  if (urls != null) {
                      while (urls.hasMoreElements()) { // 第 27 行
                          java.net.URL resourceURL = urls.nextElement();
                          // 加載指定配置文件(resourceURL)下的實現
                          loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
                      }
                  } // 第 32 行
              } catch (Throwable t) {
                  logger.error("Exception occurred when loading extension class (interface: " +
                          type + ", description file: " + fileName + ").", t);
              }
          }
      
      • 第 4 行:獲得完整的文件名( 相對路徑 )。例如:"META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory"

      • 第 18 至 24 行:獲得文件名對應的所有文件 URL 數組。例如:

      • 第 27 至 32 行:遍歷逐個文件

      loadResource方法

          private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader,
                                    java.net.URL resourceURL, boolean overridden, String... excludedPackages) {
              try {
                  try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
                      String line;
                      String clazz = null;
                      while ((line = reader.readLine()) != null) {
                          // 去除 #注釋
                          final int ci = line.indexOf('#');
                          if (ci >= 0) {
                              line = line.substring(0, ci);
                          }
                          line = line.trim();
                          if (line.length() > 0) {
                              try {
                                  // 拆分,key=value 的配置格式
                                  String name = null;
                                  int i = line.indexOf('=');
                                  if (i > 0) {
                                      name = line.substring(0, i).trim();
                                      clazz = line.substring(i + 1).trim();
                                  } else {
                                      // Dubbo SPI 會兼容 Java SPI 的配置格式,那么按照此處的解析方式,name 會為空。這種情況下,拓展名會自動生成
                                      clazz = line;
                                  }
                                  if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages)) {
                                      // 加載配置文件配置拓展的實現類
                                      loadClass(extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden);
                                  }
                              } catch (Throwable t) {
                                  IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
                                  exceptions.put(line, e);
                              }
                          }
                      }
                  }
              } catch (Throwable t) {
                  logger.error("Exception occurred when loading extension class (interface: " +
                          type + ", class file: " + resourceURL + ") in " + resourceURL, t);
              }
          }
      
      • 第 7 行:進入文件內部,逐遍歷。

      loadClass方法

          private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
                                 boolean overridden) throws NoSuchMethodException {
              // 判斷拓展實現,是否實現拓展接口
              if (!type.isAssignableFrom(clazz)) {
                  throw new IllegalStateException("Error occurred when loading extension class (interface: " +
                          type + ", class line: " + clazz.getName() + "), class "
                          + clazz.getName() + " is not subtype of interface.");
              }
              // 檢測目標類上是否有 Adaptive 注解
              if (clazz.isAnnotationPresent(Adaptive.class)) {
                  // 緩存自適應拓展對象的類到 `cachedAdaptiveClass`
                  cacheAdaptiveClass(clazz, overridden);
              } else if (isWrapperClass(clazz)) {
                  // 檢測 clazz 是否是 Wrapper 類型
                  // 緩存拓展 Wrapper 實現類到 `cachedWrapperClasses`
                  cacheWrapperClass(clazz);
              } else {
                  // 程序進入此分支,表明 clazz 是一個普通的拓展類
                  clazz.getConstructor();
                  // 未配置拓展名,自動生成。例如,DemoFilter 為 demo 。主要用于兼容 Java SPI 的配置。
                  if (StringUtils.isEmpty(name)) {
                      // 如果 name 為空,則嘗試從 Extension 注解中獲取 name,或使用小寫的類名作為 name
                      name = findAnnotationName(clazz);
                      if (name.length() == 0) {
                          throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
                      }
                  }
      
                  // 獲得拓展名,可以是數組,有多個拓展名。
                  String[] names = NAME_SEPARATOR.split(name);
                  if (ArrayUtils.isNotEmpty(names)) {
                      // 緩存 @Activate 到 `cachedActivates` 。
                      cacheActivateClass(clazz, names[0]);
                      for (String n : names) {
                          // 緩存到 `cachedNames`
                          cacheName(clazz, n);
                          // 若 isWrapperClass 方法獲取構造方法失敗,則代表是普通的拓展實現類,緩存到 extensionClasses 變量中
                          saveInExtensionClass(extensionClasses, clazz, n, overridden);
                      }
                  }
              }
          }
      

      4.3 獲得拓展加載器

      在 Dubbo 的代碼里,常常能看到如下的代碼:

      ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name)
      
      4.3.1 getExtensionLoader
          /**
            * 根據拓展點的接口,獲得拓展加載器
            *
            * @param type 接口
            * @param <T> 泛型
            * @return 加載器
            */
          public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
              if (type == null) {
                  throw new IllegalArgumentException("Extension type == null");
              }
              // 必須是接口
              if (!type.isInterface()) {
                  throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
              }
              // 必須包含 @SPI 注解
              if (!withExtensionAnnotation(type)) {
                  throw new IllegalArgumentException("Extension type (" + type +
                          ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
              }
      
              // 獲得接口對應的拓展點加載器
              ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
              if (loader == null) {
                  // 若不存在,則創建 ExtensionLoader 對象,并添加到 EXTENSION_LOADERS。
                  EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
                  loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
              }
              return loader;
          }
      
      4.3.2 構造方法

      構造方法,代碼如下:

      /**
       * 拓展接口。
       * 例如,Protocol
       */
      private final Class<?> type;
      /**
       * 對象工廠
       *
       * 用于調用 {@link #injectExtension(Object)} 方法,向拓展對象注入依賴屬性。
       *
       * 例如,StubProxyFactoryWrapper 中有 `Protocol protocol` 屬性。
       */
      private final ExtensionFactory objectFactory;
      
      private ExtensionLoader(Class<?> type) {
          this.type = type;
          objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); // 第 17 行
      }
      
      • objectFactory 屬性,對象工廠,功能上和 Spring IOC 一致
        • 用于調用 #injectExtension(instance) 方法時,向創建的拓展注入其依賴的屬性。例如,CacheFilter.cacheFactory 屬性。
        • 第 17 行:當拓展接口非 ExtensionFactory 時(如果不加這個判斷,會是一個死循環),調用 ExtensionLoader#getAdaptiveExtension() 方法,獲得 ExtensionFactory 拓展接口的自適應拓展實現對象。為什么呢?在 后文詳細解釋。

      4.4 獲得指定拓展對象

      在 Dubbo 的代碼里,常常能看到如下的代碼:

      ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name)
      
      4.4.1 getExtension
           /**
            * 返回指定名字的擴展對象。如果指定名字的擴展不存在,則拋異常 {@link IllegalStateException}.
            *
            * @param name 拓展名
            * @return 拓展對象
            */
          @SuppressWarnings("unchecked")
          public T getExtension(String name) {
              return getExtension(name, true);
          }
      
          public T getExtension(String name, boolean wrap) {
              if (StringUtils.isEmpty(name)) {
                  throw new IllegalArgumentException("Extension name == null");
              }
              // 查找 默認的 拓展對象
              if ("true".equals(name)) {
                  return getDefaultExtension();
              }
              // 從 緩存中 獲得對應的拓展對象
              final Holder<Object> holder = getOrCreateHolder(name);
              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;
          }
      
      4.4.2 createExtension

      #createExtension(name) 方法,創建拓展名的拓展對象,并緩存。代碼如下:

          /**
           * 創建拓展名的拓展對象,并緩存。
           *
           * @param name 拓展名
           * @return 拓展對象
           */
          @SuppressWarnings("unchecked")
          private T createExtension(String name, boolean wrap) {
              // 獲得拓展名對應的拓展實現類
              Class<?> clazz = getExtensionClasses().get(name);
              if (clazz == null) {
                  throw findException(name);
              }
              try {
                  // 從緩存中,獲得拓展對象。
                  T instance = (T) EXTENSION_INSTANCES.get(clazz);
                  if (instance == null) {
                      // 當緩存不存在時,創建拓展對象,并添加到緩存中。
                      EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
                      instance = (T) EXTENSION_INSTANCES.get(clazz);
                  }
                  // 注入依賴的屬性
                  injectExtension(instance);
      
      
                  if (wrap) {
      
                      List<Class<?>> wrapperClassesList = new ArrayList<>();
                      if (cachedWrapperClasses != null) {
                          wrapperClassesList.addAll(cachedWrapperClasses);
                          wrapperClassesList.sort(WrapperComparator.COMPARATOR);
                          Collections.reverse(wrapperClassesList);
                      }
      
                      if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
                          for (Class<?> wrapperClass : wrapperClassesList) {
                              Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
                              if (wrapper == null
                                      || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
                                  // 創建 Wrapper 拓展對象
                                  instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                              }
                          }
                      }
                  }
      
                  // 實例初始化
                  initExtension(instance);
                  return instance;
              } catch (Throwable t) {
                  throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                          type + ") couldn't be instantiated: " + t.getMessage(), t);
              }
          }
      

      Wrapper 類同樣實現了擴展點接口,但是 Wrapper 不是擴展點的真正實現。它的用途主要是用于從 ExtensionLoader 返回擴展點時,包裝在真正的擴展點實現外。即從 ExtensionLoader 中返回的實際上是 Wrapper 類的實例,Wrapper 持有了實際的擴展點實現類。

      擴展點的 Wrapper 類可以有多個,也可以根據需要新增。

      通過 Wrapper 類可以把所有擴展點公共邏輯移至 Wrapper 中。新加的 Wrapper 在所有的擴展點上添加了邏輯,有些類似 AOP,即 Wrapper 代理了擴展點。

      • 例如:ListenerExporterWrapper、ProtocolFilterWrapper 。
      4.4.3 injectExtension注入依賴
       	private T injectExtension(T instance) {
      
              if (objectFactory == null) {
                  return instance;
              }
      
              try {
                  for (Method method : instance.getClass().getMethods()) {
                      if (!isSetter(method)) {
                          continue;
                      }
                      /**
                       * Check {@link DisableInject} to see if we need auto injection for this property
                       */
                      if (method.getAnnotation(DisableInject.class) != null) {
                          continue;
                      }
                      // 獲得屬性的類型
                      Class<?> pt = method.getParameterTypes()[0];
                      if (ReflectUtils.isPrimitives(pt)) {
                          continue;
                      }
      
                      try {
                          // 獲取setter的屬性名,例如:setVersion,返回"version"
                          String property = getSetterProperty(method);
                          // 獲得屬性值
                          Object object = objectFactory.getExtension(pt, property); // 第 28 行
                          // 設置屬性值
                          if (object != null) {
                              method.invoke(instance, object);
                          }
                      } catch (Exception e) {
                          logger.error("Failed to inject via method " + method.getName()
                                  + " of interface " + type.getName() + ": " + e.getMessage(), e);
                      }
      
                  }
              } catch (Exception e) {
                  logger.error(e.getMessage(), e);
              }
              return instance;
          }
      
      • 第 28 行:獲得屬性值注意,此處雖然調用的是 ExtensionFactory#getExtension(type, name) 方法,實際獲取的不僅僅是拓展對象,也可以是 Spring Bean 對象。

      4.5 獲得自適應的拓展對象

      在 Dubbo 的代碼里,常常能看到如下的代碼:

      ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
      

      友情提示,胖友先看下 「6. Adaptive」 的內容再回到此處。

      Dubbo 自適應拓展的作用可以參考:SPI 自適應拓展 | Apache Dubbo

      4.5.1 getAdaptiveExtension
          @SuppressWarnings("unchecked")
          public T getAdaptiveExtension() {
              // 從緩存中,獲得自適應拓展對象
              Object instance = cachedAdaptiveInstance.get();
              if (instance == null) {
                  // 若之前創建報錯,則拋出異常 IllegalStateException
                  if (createAdaptiveInstanceError != null) {
                      throw new IllegalStateException("Failed to create adaptive instance: " +
                              createAdaptiveInstanceError.toString(),
                              createAdaptiveInstanceError);
                  }
      
                  synchronized (cachedAdaptiveInstance) {
                      instance = cachedAdaptiveInstance.get();
                      if (instance == null) {
                          try {
                              // 創建自適應拓展對象
                              instance = createAdaptiveExtension();
                              // 設置到緩存
                              cachedAdaptiveInstance.set(instance);
                          } catch (Throwable t) {
                              // 記錄異常
                              createAdaptiveInstanceError = t;
                              throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                          }
                      }
                  }
              }
      
              return (T) instance;
          }
      
      4.5.2 createAdaptiveExtension
          /**
           * 創建自適應拓展對象
           *
           * @return 拓展對象
           */
          @SuppressWarnings("unchecked")
          private T createAdaptiveExtension() {
              try {
                  // 創建自適應拓展對象,并注入屬性
                  return injectExtension((T) getAdaptiveExtensionClass().newInstance());
              } catch (Exception e) {
                  throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
              }
          }
      
      4.5.3 getAdaptiveExtensionClass

      #getAdaptiveExtensionClass() 方法,獲得自適應拓展類。代碼如下:

          /**
          * @return 自適應拓展類
          */
          private Class<?> getAdaptiveExtensionClass() {
              getExtensionClasses();
              // cachedAdaptiveClass 存在 直接返回
              if (cachedAdaptiveClass != null) {
                  return cachedAdaptiveClass;
              }
              // 自動生成自適應拓展的代碼實現,并編譯后返回該類。
              return cachedAdaptiveClass = createAdaptiveExtensionClass();
          }
      
      4.5.4 createAdaptiveExtensionClass
           /**
            * 自動生成自適應拓展的代碼實現,并編譯后返回該類。
            *
            * @return 類
            */
          private Class<?> createAdaptiveExtensionClass() {
              // 自動生成自適應拓展的代碼實現的字符串
              String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();// 第 5 行
              // 編譯代碼,并返回該類
              ClassLoader classLoader = findClassLoader();
              org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
              return compiler.compile(code, classLoader);
          }
      

      第 5 行會生成自適應拓展的代碼實現,然后會編譯字符串生成 Class。我們以 org.apache.dubbo.rpc.cluster.Cluster 接口為例,它生成的自適應拓展實現如下:

      package org.apache.dubbo.rpc.cluster;
      
      import org.apache.dubbo.common.extension.ExtensionLoader;
      
      
      public class Cluster$Adaptive implements org.apache.dubbo.rpc.cluster.Cluster {
          public org.apache.dubbo.rpc.cluster.Cluster getCluster(
              java.lang.String arg0) {
              throw new UnsupportedOperationException(
                  "The method public static org.apache.dubbo.rpc.cluster.Cluster org.apache.dubbo.rpc.cluster.Cluster.getCluster(java.lang.String) of interface org.apache.dubbo.rpc.cluster.Cluster is not adaptive method!");
          }
      
          public org.apache.dubbo.rpc.cluster.Cluster getCluster(
              java.lang.String arg0, boolean arg1) {
              throw new UnsupportedOperationException(
                  "The method public static org.apache.dubbo.rpc.cluster.Cluster org.apache.dubbo.rpc.cluster.Cluster.getCluster(java.lang.String,boolean) of interface org.apache.dubbo.rpc.cluster.Cluster is not adaptive method!");
          }
      
          public org.apache.dubbo.rpc.Invoker join(
              org.apache.dubbo.rpc.cluster.Directory arg0)
              throws org.apache.dubbo.rpc.RpcException {
              if (arg0 == null) {
                  throw new IllegalArgumentException(
                      "org.apache.dubbo.rpc.cluster.Directory argument == null");
              }
      		
              if (arg0.getUrl() == null) {
                  throw new IllegalArgumentException(
                      "org.apache.dubbo.rpc.cluster.Directory argument getUrl() == null");
              }
      		// 獲取請求的URL
              org.apache.dubbo.common.URL url = arg0.getUrl();
              // 獲取URL上的 cluster 參數,如果沒有該參數,則默認為 failover
              String extName = url.getParameter("cluster", "failover");
      
              if (extName == null) {
                  throw new IllegalStateException(
                      "Failed to get extension (org.apache.dubbo.rpc.cluster.Cluster) name from url (" +
                      url.toString() + ") use keys([cluster])");
              }
      		// 根據URL指定的集群容錯策略,加載對應的Cluster實現類,并調用對應實現的join方法
              org.apache.dubbo.rpc.cluster.Cluster extension = (org.apache.dubbo.rpc.cluster.Cluster) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.cluster.Cluster.class)
                                                                                                                     .getExtension(extName);
      
              return extension.join(arg0);
          }
      }
      
      

      生成的代碼中,就是自適應拓展實現的核心,它會根據請求URL的參數,去動態加載對應的Cluster實現,完成不同的集群容錯策略。

      4.6 獲得激活的拓展對象數組

      在 Dubbo 的代碼里,看到使用代碼如下:

      List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
      
      4.6.1 getActivateExtension

      #getActivateExtension(url, key, group) 方法,獲得符合自動激活條件的拓展對象數組。

          /**
           * This is equivalent to {@code getActivateExtension(url, url.getParameter(key).split(","), null)}
           *  獲得符合自動激活條件的拓展對象數組
           * @param url   url
           * @param key   url parameter key which used to get extension point names
           * @param group group
           * @return extension list which are activated.
           * @see #getActivateExtension(org.apache.dubbo.common.URL, String[], String)
           */
          public List<T> getActivateExtension(URL url, String key, String group) {
              // 從 Dubbo URL 獲得參數值
              String value = url.getParameter(key);
              // 獲得符合自動激活條件的拓展對象數組
              return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);
          }
      
          /**
           * Get activate extensions.
           * 獲得符合自動激活條件的拓展對象數組
           * @param url    url
           * @param values extension point names
           * @param group  group
           * @return extension list which are activated
           * @see org.apache.dubbo.common.extension.Activate
           */
          public List<T> getActivateExtension(URL url, String[] values, String group) {
              List<T> activateExtensions = new ArrayList<>();
              List<String> names = values == null ? new ArrayList<>(0) : asList(values);
              // 處理自動激活的拓展對象們
              // 判斷不存在配置 `"-name"` 。例如,<dubbo:service filter="-default" /> ,代表移除所有默認過濾器。
              if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
                  // 獲得拓展實現類數組
                  getExtensionClasses();
                  for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
                      String name = entry.getKey();
                      Object activate = entry.getValue();
      
                      String[] activateGroup, activateValue;
      
                      if (activate instanceof Activate) {
                          activateGroup = ((Activate) activate).group();
                          activateValue = ((Activate) activate).value();
                      } else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
                          activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
                          activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
                      } else {
                          continue;
                      }
                      if (isMatchGroup(group, activateGroup) // 匹配分組
                              && !names.contains(name)  // 不包含在自定義配置里。如果包含,會在下面的代碼處理。
                              && !names.contains(REMOVE_VALUE_PREFIX + name) // 判斷是否配置移除。例如 <dubbo:service filter="-monitor" />,則 MonitorFilter 會被移除
                              && isActive(activateValue, url)) { // 判斷是否激活
                          activateExtensions.add(getExtension(name));
                      }
                  }
                  // 排序
                  activateExtensions.sort(ActivateComparator.COMPARATOR);
              }
              // 處理自定義配置的拓展對象們。例如在 <dubbo:service filter="demo" /> ,代表需要加入 DemoFilter 。
              List<T> loadedExtensions = new ArrayList<>();
              for (int i = 0; i < names.size(); i++) {
                  String name = names.get(i);
                  if (!name.startsWith(REMOVE_VALUE_PREFIX)
                          && !names.contains(REMOVE_VALUE_PREFIX + name)) {
                      // 將配置的自定義在自動激活的拓展對象們前面。例如,<dubbo:service filter="demo,default,demo2" /> ,則 DemoFilter 就會放在默認的過濾器前面。
                      if (DEFAULT_KEY.equals(name)) {
                          if (!loadedExtensions.isEmpty()) {
                              activateExtensions.addAll(0, loadedExtensions);
                              loadedExtensions.clear();
                          }
                      } else {
                          // 獲得拓展對象
                          loadedExtensions.add(getExtension(name));
                      }
                  }
              }
              // 添加到結果集
              if (!loadedExtensions.isEmpty()) {
                  activateExtensions.addAll(loadedExtensions);
              }
              return activateExtensions;
          }
      

      五. @SPI

      org.apache.dubbo.common.extension.SPI,擴展點接口的標識。代碼如下:

      @Documented
      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.TYPE})
      public @interface SPI {
      
          /**
           * default extension name
           */
          String value() default "";
      
      }
      
      • value ,默認拓展實現類的名字。例如,Protocol 拓展接口,代碼如下:

        @SPI("dubbo")
        public interface Protocol {
            // ... 省略代碼
        }
        
        • 其中 "dubbo" 指的是 DubboProtocol 做為 Protocol 默認的拓展實現類。

      六. @Adaptive

      org.apache.dubbo.common.extension.Adaptive,自適應拓展信息的標記。代碼如下:

      package org.apache.dubbo.common.extension;
      
      import org.apache.dubbo.common.URL;
      
      import java.lang.annotation.Documented;
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      
      /**
       * Provide helpful information for {@link ExtensionLoader} to inject dependency extension instance.
       *
       * @see ExtensionLoader
       * @see URL
       */
      @Documented
      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.TYPE, ElementType.METHOD})
      public @interface Adaptive {
      
          /**
           * 從 {@link URL }的 Key 名,對應的 Value 作為要 Adapt 成的 Extension 名。
           * <p>
           * 如果 {@link URL} 這些 Key 都沒有 Value ,使用 缺省的擴展(注解 @SPI 設置的值)。<br>
           * 比如,@Adptive({"key1", "key2"}),表示
           * <ol>
           *      <li>先在URL上找key1的Value作為要Adapt成的Extension名;
           *      <li>key1沒有Value,則使用key2的Value作為要Adapt成的Extension名。
           *      <li>key2沒有Value,使用默認的擴展。
           *      <li>如果沒有設定缺省擴展,則方法調用會拋出{@link IllegalStateException}。
           * </ol>
           * <p>
           * 如果參數名為空,則根據接口的類名生成一個默認的參數名,其規則是 接口名稱的全小寫。
           * 例如 org.apache.dubbo.rpc.Protocol 接口,默認的參數名是:protocol
           
           * 詳細邏輯參考:org.apache.dubbo.common.extension.AdaptiveClassCodeGenerator#getMethodAdaptiveValue
           *
           * @see SPI#value()
           */
          String[] value() default {};
      
      }
      

      @Adaptive注解,可添加方法上,分別代表了兩種不同的使用方式。

      友情提示:一個拓展接口,有且僅有一個 Adaptive 拓展實現類。

      • 第一種,標記在上,代表手動實現(代碼中聲明一個類)它是一個拓展接口的 Adaptive 拓展實現類。目前 Dubbo 項目里,只有 ExtensionFactory 拓展的實現類 AdaptiveExtensionFactory 有這么用。
      • 第二種,標記在拓展接口的方法上,代表自動生成代碼實現該接口的 Adaptive 拓展實現類(參考:[「4.5.4 createAdaptiveExtensionClassCode」](# 4.5.4 createAdaptiveExtensionClass))。
        • value,從 Dubbo URL 獲取參數中,使用鍵名(Key),獲取鍵值。該值為真正的拓展名。
          • 自適應拓展實現類,會獲取拓展名對應的真正的拓展對象。通過該對象,執行真正的邏輯。
          • 可以設置多個鍵名(Key),順序獲取直到有值。若最終獲取不到,使用默認拓展名
        • 「4.5.4 createAdaptiveExtensionClassCode」 詳細解析。

      七. @Activate

      org.apache.dubbo.common.extension.Activate,自動激活條件的標記。代碼如下:

      @Documented
      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.TYPE, ElementType.METHOD})
      public @interface Activate {
          /**
           * Activate the current extension when one of the groups matches. The group passed into
           * {@link ExtensionLoader#getActivateExtension(URL, String, String)} will be used for matching.
           *
           * @return group names to match
           * @see ExtensionLoader#getActivateExtension(URL, String, String)
           */
          /**
           * Group過濾條件。
           * <br />
           * 包含{@link ExtensionLoader#getActivateExtension}的group參數給的值,則返回擴展。
           * <br />
           * 如沒有Group設置,則不過濾。
           */
          String[] group() default {};
      
          /**
           * Activate the current extension when the specified keys appear in the URL's parameters.
           * <p>
           * For example, given <code>@Activate("cache, validation")</code>, the current extension will be return only when
           * there's either <code>cache</code> or <code>validation</code> key appeared in the URL's parameters.
           * </p>
           *
           * @return URL parameter keys
           * @see ExtensionLoader#getActivateExtension(URL, String)
           * @see ExtensionLoader#getActivateExtension(URL, String, String)
           */
          /**
           * Key過濾條件。包含{@link ExtensionLoader#getActivateExtension}的URL的參數Key中有,則返回擴展。
           * <p/>
           * 示例:<br/>
           * 注解的值 <code>@Activate("cache,validatioin")</code>,
           * 則{@link ExtensionLoader#getActivateExtension}的URL的參數有<code>cache</code>Key,或是<code>validatioin</code>則返回擴展。
           * <br/>
           * 如沒有設置,則不過濾。
           */
          String[] value() default {};
      
          /**
           * Relative ordering info, optional
           * Deprecated since 2.7.0
           *
           * @return extension list which should be put before the current one
           */
          /**
           * 排序信息,可以不提供。
           */
          @Deprecated
          String[] before() default {};
      
          /**
           * Relative ordering info, optional
           * Deprecated since 2.7.0
           *
           * @return extension list which should be put after the current one
           */
          /**
           * 排序信息,可以不提供。
           */
          @Deprecated
          String[] after() default {};
      
          /**
           * Absolute ordering info, optional
           *
           * @return absolute ordering info
           */
          /**
           * 排序信息,可以不提供。
           */
          int order() default 0;
      }
      
      • 對于可以被框架中自動激活加載擴展,@Activate 用于配置擴展被自動激活加載條件。比如,Filter 擴展,有多個實現,使用 @Activate 的擴展可以根據條件被自動加載。
      • 分成過濾條件和排序信息兩類屬性,大家可以看下代碼里的注釋。
      • 在 [「4.6 獲得激活的拓展對象數組」](#4.6 獲得激活的拓展對象數組) 詳細解析。

      八. ExtensionFactory

      org.apache.dubbo.common.extension.ExtensionFactory,拓展工廠接口。代碼如下:

      /**
       * ExtensionFactory
       *
       * 拓展工廠接口
       */
      @SPI
      public interface ExtensionFactory {
      
          /**
           * Get extension.
           *
           * 獲得拓展對象
           *
           * @param type object type. 拓展接口
           * @param name object name. 拓展名
           * @return object instance. 拓展對象
           */
          <T> T getExtension(Class<T> type, String name);
      
      }
      
      • ExtensionFactory 自身也是拓展接口,基于 Dubbo SPI 加載具體拓展實現類。
      • #getExtension(type, name) 方法,在 [「4.4.3 injectExtension」](#4.4.3 injectExtension) 中,獲得拓展對象,向創建的拓展對象注入依賴屬性。在實際代碼中,我們可以看到不僅僅獲得的是拓展對象,也可以是 Spring 中的 Bean 對象。
      • ExtensionFactory 子類類圖如下:

      8.1 AdaptiveExtensionFactory

      org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory,自適應 ExtensionFactory 拓展實現類。代碼如下:

      @Adaptive
      public class AdaptiveExtensionFactory implements ExtensionFactory {
      
          /**
           * ExtensionFactory 拓展對象集合
           */
          private final List<ExtensionFactory> factories;
      
          public AdaptiveExtensionFactory() {
              // 使用 ExtensionLoader 加載拓展對象實現類。
              ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
              List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
              for (String name : loader.getSupportedExtensions()) {
                  list.add(loader.getExtension(name));
              }
              factories = Collections.unmodifiableList(list);
          }
      
          @Override
          public <T> T getExtension(Class<T> type, String name) {
              // 遍歷工廠數組,直到獲得到屬性
              for (ExtensionFactory factory : factories) {
                  T extension = factory.getExtension(type, name);
                  if (extension != null) {
                      return extension;
                  }
              }
              return null;
          }
      
      }
      
      • @Adaptive 注解,為 ExtensionFactory 的自適應拓展實現類。
      • 構造方法,使用 ExtensionLoader 加載 ExtensionFactory 拓展對象的實現類。若胖友沒自己實現 ExtensionFactory 的情況下,factories 為 SpiExtensionFactory 和 SpringExtensionFactory 。
      • #getExtension(type, name) 方法,遍歷 factories ,調用其 #getExtension(type, name) 方法,直到獲得到屬性值。

      8.2 SpiExtensionFactory

      org.apache.dubbo.common.extension.factory.SpiExtensionFactory,SPI ExtensionFactory 拓展實現類。代碼如下:

      public class SpiExtensionFactory implements ExtensionFactory {
      
          /**
           * 獲得拓展對象
           *
           * @param type object type. 拓展接口
           * @param name object name. 拓展名
           * @param <T> 泛型
           * @return 拓展對象
           */
          @Override
          public <T> T getExtension(Class<T> type, String name) {
              if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {// 校驗是 @SPI
                  // 加載拓展接口對應的 ExtensionLoader 對象
                  ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
                  // 加載拓展對象
                  if (!loader.getSupportedExtensions().isEmpty()) {
                      return loader.getAdaptiveExtension();
                  }
              }
              return null;
          }
      
      }
      

      8.3 SpringExtensionFactory

      org.apache.dubbo.config.spring.extension.SpringExtensionFactory,Spring ExtensionFactory 拓展實現類。代碼如下:

      /*
       * Licensed to the Apache Software Foundation (ASF) under one or more
       * contributor license agreements.  See the NOTICE file distributed with
       * this work for additional information regarding copyright ownership.
       * The ASF licenses this file to You under the Apache License, Version 2.0
       * (the "License"); you may not use this file except in compliance with
       * the License.  You may obtain a copy of the License at
       *
       *     http://www.apache.org/licenses/LICENSE-2.0
       *
       * Unless required by applicable law or agreed to in writing, software
       * distributed under the License is distributed on an "AS IS" BASIS,
       * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       * See the License for the specific language governing permissions and
       * limitations under the License.
       */
      package org.apache.dubbo.config.spring.extension;
      
      import org.apache.dubbo.common.extension.ExtensionFactory;
      import org.apache.dubbo.common.extension.SPI;
      import org.apache.dubbo.common.logger.Logger;
      import org.apache.dubbo.common.logger.LoggerFactory;
      import org.apache.dubbo.common.utils.ConcurrentHashSet;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.ConfigurableApplicationContext;
      
      import java.util.Set;
      
      import static org.apache.dubbo.config.spring.util.DubboBeanUtils.getOptionalBean;
      
      /**
       * SpringExtensionFactory
       */
      public class SpringExtensionFactory implements ExtensionFactory {
          private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);
      
          /**
           * Spring Context 集合
           */
          private static final Set<ApplicationContext> CONTEXTS = new ConcurrentHashSet<ApplicationContext>();
      
          public static void addApplicationContext(ApplicationContext context) {
              CONTEXTS.add(context);
              if (context instanceof ConfigurableApplicationContext) {
                  ((ConfigurableApplicationContext) context).registerShutdownHook();
              }
          }
      
          public static void removeApplicationContext(ApplicationContext context) {
              CONTEXTS.remove(context);
          }
      
          public static Set<ApplicationContext> getContexts() {
              return CONTEXTS;
          }
      
          // currently for test purpose
          public static void clearContexts() {
              CONTEXTS.clear();
          }
      
          @Override
          @SuppressWarnings("unchecked")
          public <T> T getExtension(Class<T> type, String name) {
      
              //SPI should be get from SpiExtensionFactory
              if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
                  return null;
              }
      
              for (ApplicationContext context : CONTEXTS) {
                  // 獲得屬性
                  T bean = getOptionalBean(context, name, type);
                  if (bean != null) {
                      return bean;
                  }
              }
      
              //logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());
      
              return null;
          }
      
      }
      

      例子:

      DemoFilter 是筆者實現的 Filter 拓展實現類,代碼如下:

      public class DemoFilter implements Filter {
      
          private DemoDAO demoDAO;
      
          @Override
          public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
              return invoker.invoke(invocation);
          }
      
          public DemoFilter setDemoDAO(DemoDAO demoDAO) {
              this.demoDAO = demoDAO;
              return this;
          }
      }
      
      • DemoDAO ,筆者在 Spring 中聲明對應的 Bean 對象。

        <bean id="demoDAO" class="com.alibaba.dubbo.demo.provider.DemoDAO" />
        
      • 「4.4.3 injectExtension」 中,會調用 #setDemoDAO(demo) 方法,將 DemoFilter 依賴的屬性 demoDAO 注入。

      本文參考至:

      芋道源碼

      Dubbo SPI | Apache Dubbo

      posted @ 2022-12-04 17:29  聽到微笑  閱讀(37)  評論(0)    收藏  舉報  來源
      主站蜘蛛池模板: 久久综合久中文字幕青草| 色就色偷拍综合一二三区| 久久精品国产亚洲av天海翼| 国产精品熟女孕妇一区二区| 日韩有码精品中文字幕| 一本色道国产在线观看二区| 国产国产乱老熟女视频网站97| gogogo高清在线播放免费| 2021最新国产精品网站| 久久精品久久精品久久精品| 中文字幕日韩有码一区| 2021国产成人精品久久| 被拉到野外强要好爽| 国产精品污一区二区三区| 东京热一精品无码av| 色翁荡息又大又硬又粗又视频图片| 国产超级va在线观看视频| 国产精品一区二区黄色片| 亚洲国产精品午夜福利| 欧美巨大极度另类| 久久成人 久久鬼色| 日本成熟少妇喷浆视频| 亚欧洲乱码视频在线专区| 精品福利视频一区二区三区| 亚洲精品中文字幕在线观| 日韩人妻无码精品久久| 亚洲国内精品一区二区| 虎白女粉嫩尤物福利视频| 亚洲精品中文av在线| 俄罗斯老熟妇性爽xxxx| 在线日韩一区二区| 久久夜色撩人国产综合av| 熟女丰满老熟女熟妇| 亚洲av综合色区在线观看| 久久人与动人物a级毛片| 久热综合在线亚洲精品| 亚洲综合色网一区二区三区| 欧美在线一区二区三区精品| 国产女人18毛片水真多1| 无码人妻精品一区二区三| 久久热这里只有精品最新|