欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Dubbo学习-扩展点加载机制(五)[email protected]

程序员文章站 2022-06-01 17:47:21
...

@Activate

/**
 * Activate. This annotation is useful for automatically activate certain extensions with the given criteria,
 * **,这个注解 用于 自动** 特定的扩展 当满足给定条件的时候,比如在Filter应用场景中
 * for examples: <code>@Activate</code> can be used to load certain <code>Filter</code> extension when there are
 * multiple implementations.
 * <ol>
 * <li>{@link Activate#group()} specifies group criteria. Framework SPI defines the valid group values.
 * <li>{@link Activate#value()} specifies parameter key in {@link URL} criteria.
 * </ol>
 * group():特定的分组条件 在URL中
 * value():特定的参数key 在URL中
 * SPI provider can call {@link ExtensionLoader#getActivateExtension(URL, String, String)} to find out all activated
 * extensions with the given criteria.
 * SPI 提供 可以通过调用getActivateExtension方法 找出 所有 被**的 扩展 根据 给定的 条件
 *  * @see SPI
 * @see URL
 * @see ExtensionLoader
 */
@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.
     * ** 当前扩展 当 有一个group匹配的时候,group参数 传入getActivateExtension方法中
     * 可以设置多个group
     * @return group names to match
     * @see ExtensionLoader#getActivateExtension(URL, String, String)
     */
    String[] group() default {};

    /**
     * Activate the current extension when the specified keys appear in the URL's parameters.
     * ** 当前扩展 当 指定的参数key 出现在URL的参数中
     * <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)
     */
    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;
}

getActivateExtension实现原理

getActivateExtension方法可以获取 所有 自动**扩展点,参数分别是URL、URL中指定的key、URL中指定的组group
getActivateExtension 对 getExtension 的依赖比较重

主流程分为四步骤:

  1. 检查缓存,如果缓存中没有,则 初始化 所有 扩展类实现的集合
  2. 遍历整个@Activate注解集合,根据URL传入的匹配条件,得到 所有 符合 **条件的 扩展类实现,然后 根据@Activate中的before after order进行排序
  3. 遍历 所有 用户自定义扩展类名称,根据用户URL配置的顺序,调整 扩展点**顺序
  4. 返回所有自动**类集合
  5. 如果URL中参数传入了-default,则所有的 默认@Activate 都不会被**;如果传入了“-X”,则X扩展点也不会被**。
public List<T> getActivateExtension(URL url, String key, String group) {
	// 根据URL的key获取到对应的value数组
	String value = url.getParameter(key);
	return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);
}

/**
  * Get activate extensions.67
  *
  * @param url    url
  * @param values extension point names 指定自动**扩展点名数组
  * @param group  group URL中指定的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<>();
	// 下面的names就是URL中的key
	List<String> names = values == null ? new ArrayList<>(0) : asList(values);
	// 如果 URL中的key不包含 -default,则遍历 缓存中 的 默认自**扩展
	// <dubbo:service filter="-default" /> ,代表移除所有默认过滤器
	if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
		// 这里面的cacheActivateClass方法会缓存 扩展名 + 自动**类对象
		getExtensionClasses();
		// 循环 扩展名 + 自动**类对象 缓存
		for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
			// 扩展名
			String name = entry.getKey();
			// 自动**类对象
			Object activate = entry.getValue();

			String[] activateGroup, activateValue;

			// 得到@Activate注解的group和value值
			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;
			}

			// 如果 注解中的groups数组是否包含参数中的group
			// 且 指定扩展名数组names不能包含当前扩展类名称
			// 且 指定扩展名数组names不能包含'-当前扩展类名称'
			// 且 根据配置的value值,和url中参数,是否匹配
			// 该默认扩展点name不在要获取的扩展点集合names中(下面会专门处理要获取的扩展点) && 要获取的扩展点集合names 不存在 该默认扩展点name的自反 && 此扩展点的value与url匹配
			if (isMatchGroup(group, activateGroup)
				&& !names.contains(name)
				&& !names.contains(REMOVE_VALUE_PREFIX + name)
				&& isActive(activateValue, url)) {
				// 获取 指定名称name的拓展类,加入activateExtensions集合
				activateExtensions.add(getExtension(name));
			}
		}
		// 排序
		activateExtensions.sort(ActivateComparator.COMPARATOR);
	}

	// 加载扩展集合
	List<T> loadedExtensions = new ArrayList<>();
	// 针对指定的扩展名进行专门的处理
	for (int i = 0; i < names.size(); i++) {
		String name = names.get(i);
		// 如果name是没有以 '-' 作为开始,并且集合中也不包含'-name'
		// 如:既含有name,又含有-name,这样自相矛盾的不处理)
		if (!name.startsWith(REMOVE_VALUE_PREFIX)
			&& !names.contains(REMOVE_VALUE_PREFIX + name)) {
			// name=default
			if (DEFAULT_KEY.equals(name)) {
				// 已加载扩展的集合不为空
				if (!loadedExtensions.isEmpty()) {
					// 将已加载的实例集合加入到activateExtensions集合中,并清空loadedExtensions集合
					// 如果当前指定扩展点name=default,则将 loadedExtensions 转移到 activateExtensions 首位
					// 用于排序,这样default就排到后面了
					// 例如,<dubbo:service filter="demo,default,demo2" /> ,则 DemoFilter 就会放在默认的过滤器前面。
					activateExtensions.addAll(0, loadedExtensions);
					loadedExtensions.clear();
				}
			} else {
				// name!=default,根据name获取扩展类,放到loadedExtensions列表中
				loadedExtensions.add(getExtension(name));
			}
		}
	}
	// 如果循环完指定的扩展名之后loadedExtensions不为空
	// 说明loadedExtensions里面的扩展 都是 配置在default之后的
	// 添加到default排序之后
	if (!loadedExtensions.isEmpty()) {
		activateExtensions.addAll(loadedExtensions);
	}
	return activateExtensions;
}

1.看一下isMatchGroup

/**
  *
  * @param group URL中的group
  * @param groups @Activate注解中的group
  * @return boolean
  */
private boolean isMatchGroup(String group, String[] groups) {
	// 如果URL中的group为空,直接返回匹配成功
	if (StringUtils.isEmpty(group)) {
		return true;
	}
	// 否则循环@Activate注解中的group,判断是否=URL中的group
	if (groups != null && groups.length > 0) {
		for (String g : groups) {
			if (group.equals(g)) {
				return true;
			}
		}
	}
	return false;
}

2.看一下isActive

/**
  *
 * @param keys @Activate注解中的value
 * @param url URL
 * @return boolean
  */
private boolean isActive(String[] keys, URL url) {
	// 如果@Activate的value为null,则返回**
	if (keys.length == 0) {
		return true;
	}
	// 循环@Activate的value
	for (String key : keys) {
		// @Active(value="key1:value1, key2:value2")
		// 针对@Activate的value中有:的解析
		String keyValue = null;
		if (key.contains(":")) {
			String[] arr = key.split(":");
			key = arr[0];
			keyValue = arr[1];
		}

		// 循环URL的参数,进行匹配
		for (Map.Entry<String, String> entry : url.getParameters().entrySet()) {
			String k = entry.getKey();
			String v = entry.getValue();
			// URL中的[email protected]的value的=key 或 URL中的key 以 @Activate的value的=key 结尾
			// 且 (keyValue不为空 + URL中的[email protected]的value的keyValue
			// 或 keyValue为空 + URL中的value不为空)
			// 满足以上条件,认为是**状态
			if ((k.equals(key) || k.endsWith("." + key))
				&& ((keyValue != null && keyValue.equals(v)) || (keyValue == null && ConfigUtils.isNotEmpty(v)))) {
				return true;
			}
		}
	}
	return false;
}

3.ActivateComparator
ActivateComparator首先通过parseActivate解析注解信息到ActivateInfo
然后对于有配置before或after的 则根据其值 进行升序排序
否则则通过order(没有指定默认为0)来排序,大于返回1,否则返回-1

@Override
public int compare(Object o1, Object o2) {

	// .....

	// 分别获取o1 o2的Activate类对象
	ActivateInfo a1 = parseActivate(o1.getClass());
	ActivateInfo a2 = parseActivate(o2.getClass());

	// before 或 after有值 且 o1有SPI注解
	if ((a1.applicableToCompare() || a2.applicableToCompare()) && inf != null) {
		ExtensionLoader<?> extensionLoader = ExtensionLoader.getExtensionLoader(inf);
		if (a1.applicableToCompare()) {
			// 获取o2的扩展名
			String n2 = extensionLoader.getExtensionName(o2.getClass());
			// o1.before中包含o2.name,则o1<o2
			if (a1.isLess(n2)) {
				return -1;
			}

			// o1.after中包含o2.name,则o1>o2
			if (a1.isMore(n2)) {
				return 1;
			}
		}

		if (a2.applicableToCompare()) {
			// 获取o1的扩展名
			String n1 = extensionLoader.getExtensionName(o1.getClass());
			// o2.before中包含o1.name,则o1>o2
			if (a2.isLess(n1)) {
				return 1;
			}

			// o2.after中包含o1.name,则o1<o2
			if (a2.isMore(n1)) {
				return -1;
			}
		}
	}
	// never return 0 even if n1 equals n2, otherwise, o1 and o2 will override each other in collection like HashSet
	return a1.order > a2.order ? 1 : -1;
}

// 将Activate类对象信息放到ActivateInfo中
private ActivateInfo parseActivate(Class<?> clazz) {
	ActivateInfo info = new ActivateInfo();
	if (clazz.isAnnotationPresent(Activate.class)) {
		Activate activate = clazz.getAnnotation(Activate.class);
		info.before = activate.before();
		info.after = activate.after();
		info.order = activate.order();
	} else {
		com.alibaba.dubbo.common.extension.Activate activate = clazz.getAnnotation(
			com.alibaba.dubbo.common.extension.Activate.class);
		info.before = activate.before();
		info.after = activate.after();
		info.order = activate.order();
	}
	return info;
}

// 内部静态类
private static class ActivateInfo {
	// 前置扩展名数组
	private String[] before;
	// 后置扩展名数组
	private String[] after;
	private int order;

	private boolean applicableToCompare() {
		return ArrayUtils.isNotEmpty(before) || ArrayUtils.isNotEmpty(after);
	}

	private boolean isLess(String name) {
		return Arrays.asList(before).contains(name);
	}

	private boolean isMore(String name) {
		return Arrays.asList(after).contains(name);
	}
}

总结

  • 系统默认的自动**扩展

    • 筛选:如果参数中没有-default选项,则加载默认的@Activate扩展。这里得到的 所有默认@Activate扩展点,均需要 根据传入参数的group、url配置的key等 进行匹配筛选
    • 排序:默认@Activate扩展点的排序,是按照@Activate配置的before、after、order等参数进行排序
  • URL指定的自动**扩展

    • 筛选:由于扩展点名称是作为参数传递进来的,因此需要进行 扩展是否加载的逻辑判断
    • 排序:对于URL参数传入的扩展点,用户可以通过 修改URL中参数中 扩展点顺序 来调整扩展点的**顺序