Mecanismo de expansão do Dubbo SPI (2)

método getAdaptiveExtension (), obtenha o objeto de extensão adaptável:

/**
 * 缓存的自适应( 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;
  }

O método createAdaptiveExtension () cria um objeto de extensão adaptável:

/**
 * 创建自适应拓展对象
 *
 * @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);
    }
}

Método getAdaptiveExtensionClass () para obter a classe de extensão adaptável:

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

O método createAdaptiveExtensionClassCode () gera automaticamente a implementação do código de extensão adaptável e retorna essa classe após a compilação:

 /**
  * 自动生成自适应拓展的代码实现,并编译后返回该类。
  *
  * @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);
 }

Método getExtensionLoader (url, chave, grupo) para obter uma matriz de objetos de extensão que atendem às condições de ativação automática:

 /**
  * 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, o identificador da interface do ponto de extensão (valor, o nome da classe de implementação da extensão padrão.):

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

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

}

@Adaptive, a marca das informações de extensão adaptável:

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

}

Anotação @Adaptive, adicionada à classe e método, duas maneiras diferentes de usar:

  1. Lembrado na classe, significa que é uma classe de implementação de extensão adaptável que estende a interface manualmente.
  2. Marcado no método de extensão da interface, ele representa a classe de implementação de extensão adaptável que gera automaticamente código para implementar a interface.

@Activate, a marca da condição de ativação automática:

@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, interface do factory de extensão (o ExtensionFactory em si também é uma interface de extensão, baseada no Dubbo SPI que carrega a classe de implementação de extensão específica):

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

}

Classe de implementação estendida AdaptiveExtensionFactory Adaptive 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);
     }
 
     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, classe de implementação da extensão SPI ExtensionFactory:

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, classe de implementação estendida Spring ExtensionFactory:

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

}
Publicado 46 artigos originais · ganhou elogios 6 · vista 3847

Acho que você gosta

Origin blog.csdn.net/weixin_43257196/article/details/105392607
Recomendado
Clasificación