Dubbo's expansion mechanism SPI (2)

getAdaptiveExtension () method, get adaptive extension object:

/**
 * 缓存的自适应( Adaptive )拓展对象
 */
private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();

/**
 * 创建 {@link #cachedAdaptiveInstance} 时发生的异常。
 *
 * 发生异常后,不再创建,参见 {@link #createAdaptiveExtension()}
 */
private volatile Throwable createAdaptiveInstanceError;

  /**
   * 获得自适应拓展对象
   *
   * @return 拓展对象
   */
  @SuppressWarnings("unchecked")
  public T getAdaptiveExtension() {
      // 从缓存中,获得自适应拓展对象
      Object instance = cachedAdaptiveInstance.get();
      if (instance == null) {
          // 若之前未创建报错,
          if (createAdaptiveInstanceError == null) {
              synchronized (cachedAdaptiveInstance) {
                 instance = cachedAdaptiveInstance.get();
                  if (instance == null) {
                      try {
                          // 创建自适应拓展对象
                          instance = createAdaptiveExtension();
                          // 设置到缓存
                          cachedAdaptiveInstance.set(instance);
                      } catch (Throwable t) {
                          // 记录异常
                          createAdaptiveInstanceError = t;
                          throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
                      }
                  }
              }
          // 若之前创建报错,则抛出异常 IllegalStateException
          } else {
              throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
          }
      }
      return (T) instance;
  }

The createAdaptiveExtension () method creates an adaptive extension object:

/**
 * 创建自适应拓展对象
 *
 * @return 拓展对象
 */
@SuppressWarnings("unchecked")
private T createAdaptiveExtension() {
    try {
        return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
        throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
    }
}

getAdaptiveExtensionClass () method to get adaptive extension class:

 /**
  * @return 自适应拓展类
  */
 private Class<?> getAdaptiveExtensionClass() {
    getExtensionClasses();
     if (cachedAdaptiveClass != null) {
         return cachedAdaptiveClass;
     }
     return cachedAdaptiveClass = createAdaptiveExtensionClass();
 }

The createAdaptiveExtensionClassCode () method automatically generates adaptive extension code implementation and returns this class after compilation:

 /**
  * 自动生成自适应拓展的代码实现,并编译后返回该类。
  *
  * @return 类
  */
 private Class<?> createAdaptiveExtensionClass() {
     // 自动生成自适应拓展的代码实现的字符串
     String code = createAdaptiveExtensionClassCode();
     // 编译代码,并返回该类
     ClassLoader classLoader = findClassLoader();
     com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
     return compiler.compile(code, classLoader);
 }

getExtensionLoader (url, key, group) method to obtain an array of extension objects that meet the conditions of automatic activation:

 /**
  * 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
  *              Dubbo URL 参数名
  * @param group group
  *              过滤分组名
  * @return extension list which are activated.
  * @see #getActivateExtension(com.alibaba.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, value == null || value.length() == 0 ? null : Constants.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 com.alibaba.dubbo.common.extension.Activate
  */
 public List<T> getActivateExtension(URL url, String[] values, String group) {
     List<T> exts = new ArrayList<T>();
     List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
     // 处理自动激活的拓展对象们
     // 判断不存在配置 `"-name"` 。例如,<dubbo:service filter="-default" /> ,代表移除所有默认过滤器。
     if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
         // 获得拓展实现类数组
         getExtensionClasses();
         // 循环
         for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
             String name = entry.getKey();
            Activate activate = entry.getValue();
             if (isMatchGroup(group, activate.group())) { // 匹配分组
                 // 获得拓展对象
                 T ext = getExtension(name);
                 if (!names.contains(name) // 不包含在自定义配置里。如果包含,会在下面的代码处理。
                         && !names.contains(Constants.REMOVE_VALUE_PREFIX + name) // 判断是否配置移除。例如 <dubbo:service filter="-monitor" />,则 MonitorFilter 会被移除
                         && isActive(activate, url)) { // 判断是否激活
                    exts.add(ext);
                 }
             }
        }
        // 排序
         Collections.sort(exts, ActivateComparator.COMPARATOR);
     }
     // 处理自定义配置的拓展对象们。例如在 <dubbo:service filter="demo" /> ,代表需要加入 DemoFilter (这个是笔者自定义的)。
     List<T> usrs = new ArrayList<T>();
     for (int i = 0; i < names.size(); i++) {
         String name = names.get(i);
         if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX) && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) { // 判断非移除的
             // 将配置的自定义在自动激活的拓展对象们前面。例如,<dubbo:service filter="demo,default,demo2" /> ,则 DemoFilter 就会放在默认的过滤器前面。
             if (Constants.DEFAULT_KEY.equals(name)) {
                 if (!usrs.isEmpty()) {
                     exts.addAll(0, usrs);
                     usrs.clear();
                 }
             } else {
                 // 获得拓展对象
                 T ext = getExtension(name);
                usrs.add(ext);
             }
         }
     }
     // 添加到结果集
     if (!usrs.isEmpty()) {
         exts.addAll(usrs);
     }
     return exts;
 }

com.alibaba.dubbo.common.extension. @ SPI, the identifier of the extension point interface (value, the name of the default extension implementation class.):

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {

    /**
     * default extension name
     */
    String value() default "";

}

@Adaptive, the mark of adaptive extension information:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Adaptive {

    /**
     * Decide which target extension to be injected. The name of the target extension is decided by the parameter passed
     * in the URL, and the parameter names are given by this method.
     * <p>
     * If the specified parameters are not found from {@link URL}, then the default extension will be used for
     * dependency injection (specified in its interface's {@link SPI}).
     * <p>
     * For examples, given <code>String[] {"key1", "key2"}</code>:
     * <ol>
     * <li>find parameter 'key1' in URL, use its value as the extension's name</li>
     * <li>try 'key2' for extension's name if 'key1' is not found (or its value is empty) in URL</li>
     * <li>use default extension if 'key2' doesn't appear either</li>
     * <li>otherwise, throw {@link IllegalStateException}</li>
     * </ol>
     * If default extension's name is not give on interface's {@link SPI}, then a name is generated from interface's
     * class name with the rule: divide classname from capital char into several parts, and separate the parts with
     * dot '.', for example: for {@code com.alibaba.dubbo.xxx.YyyInvokerWrapper}, its default name is
     * <code>String[] {"yyy.invoker.wrapper"}</code>. This name will be used to search for parameter from URL.
     *
     * @return parameter key names in URL
     */
    /**
     * 从 {@link URL }的 Key 名,对应的 Value 作为要 Adapt 成的 Extension 名。
     * <p>
     * 如果 {@link URL} 这些 Key 都没有 Value ,使用 缺省的扩展(在接口的{@link SPI}中设定的值)。<br>
     * 比如,<code>String[] {"key1", "key2"}</code>,表示
     * <ol>
     *      <li>先在URL上找key1的Value作为要Adapt成的Extension名;
     *      <li>key1没有Value,则使用key2的Value作为要Adapt成的Extension名。
     *      <li>key2没有Value,使用缺省的扩展。
     *      <li>如果没有设定缺省扩展,则方法调用会抛出{@link IllegalStateException}。
     * </ol>
     * <p>
     * 如果不设置则缺省使用Extension接口类名的点分隔小写字串。<br>
     * 即对于Extension接口 {@code com.alibaba.dubbo.xxx.YyyInvokerWrapper} 的缺省值为 <code>String[] {"yyy.invoker.wrapper"}</code>
     *
     * @see SPI#value()
     */
    String[] value() default {};

}

@Adaptive annotation, added to the class and method, two different ways of using:

  1. Remembered on the class, it means that it is an Adaptive extension implementation class that extends the interface manually.
  2. Marked on the method of extending the interface, it represents the Adaptive extension implementation class that automatically generates code to implement the interface.

@Activate, the mark of automatic activation condition:

@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
     *
     * @return extension list which should be put before the current one
     */
    /**
     * 排序信息,可以不提供。
     */
    String[] before() default {};

    /**
     * Relative ordering info, optional
     *
     * @return extension list which should be put after the current one
     */
    /**
     * 排序信息,可以不提供。
     */
    String[] after() default {};

    /**
     * Absolute ordering info, optional
     *
     * @return absolute ordering info
     */
    /**
     * 排序信息,可以不提供。
     */
    int order() default 0;
}

ExtensionFactory, extension factory interface (ExtensionFactory itself is also an extension interface, based on Dubbo SPI loading specific extension implementation class):

/**
 * 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);

}

AdaptiveExtensionFactory Adaptive ExtensionFactory extended implementation class:

 @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);
     }
 
     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;
     }
 
 }

SpiExtensionFactory, SPI ExtensionFactory extension implementation class:

public class SpiExtensionFactory implements ExtensionFactory {

    /**
     * 获得拓展对象
     *
     * @param type object type. 拓展接口
     * @param name object name. 拓展名
     * @param <T> 泛型
     * @return 拓展对象
     */
    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;
    }

}

SpringExtensionFactory, Spring ExtensionFactory extended implementation class:

public class SpringExtensionFactory implements ExtensionFactory {

    /**
     * Spring Context 集合
     */
    private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();

    public static void addApplicationContext(ApplicationContext context) {
        contexts.add(context);
    }

    public static void removeApplicationContext(ApplicationContext context) {
        contexts.remove(context);
    }

    @Override
    @SuppressWarnings("unchecked")
    //getExtension(type, name) 方法,遍历 contexts ,调用其 ApplicationContext的getBean(name) 方法,获得 Bean 对象,直到成功并且值类型正确。
    public <T> T getExtension(Class<T> type, String name) {
        for (ApplicationContext context : contexts) {
            if (context.containsBean(name)) {
                // 获得属性
                Object bean = context.getBean(name);
                // 判断类型
                if (type.isInstance(bean)) {
                    return (T) bean;
                }
            }
        }
        return null;
    }

}
Published 46 original articles · won praise 6 · views 3847

Guess you like

Origin blog.csdn.net/weixin_43257196/article/details/105392607