Dubbo学习-扩展点加载机制(五)[email protected]
程序员文章站
2022-06-01 17:47:21
...
@Activate注解
@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 的依赖比较重
主流程分为四步骤:
- 检查缓存,如果缓存中没有,则 初始化 所有 扩展类实现的集合
- 遍历整个@Activate注解集合,根据URL传入的匹配条件,得到 所有 符合 **条件的 扩展类实现,然后 根据@Activate中的before after order进行排序
- 遍历 所有 用户自定义扩展类名称,根据用户URL配置的顺序,调整 扩展点**顺序
- 返回所有自动**类集合
- 如果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中参数中 扩展点顺序 来调整扩展点的**顺序
上一篇: LeetCode精选题之数学