dubbo SPI:@Activate注解
本文基于dubbo 2.7.22分析:dubbo SPI之@Activate
注解
@Activate
用于指明该SPI实现类在什么条件下生效,
下面看下@org.apache.dubbo.common.extension.Activate
注解中各个属性的含义
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Activate {
String[] group() default {};
String[] value() default {};
@Deprecated
String[] before() default {};
@Deprecated
String[] after() default {};
int order() default 0;
}
-
order
用于多个SPI
实现类之间排序,before
和after
也用是用于排序但是被标记为过期,不建议使用. 只用order
属性,这样逻辑也简单一点. -
group
数组类型,用于指明该Filter作用于provider
或是consumer
端,可以指明该SPI实现类
在provider
和consumer
端同时生效. 但建议不要将provider端和consumer端的逻辑混到同一个SPI实现类
中 -
value
数组类型,用于指明该SPI实现类
生效的条件, 可以指定多个条件, 只要有一个满足该SPI实现类
就生效;
如果不指定value,则默认生效
。value的格式有如下几种, (以Dubbo Filter SPI实现类为例):@Activate(group = {CONSUMER}) value属性不填写, 默认生效
@Activate(group = {CONSUMER}, value = "filter_enable:true") 当url参数中存在参数filter_enable且参数值是true时该Filter生效, 如果写了冒号,那后面一定要有值,否则报错
@Activate(group = {PROVIDER}, value = "filter_enable") 当url参数中存在参数filter_enable且参数值任意不为null时该Filter生效
@Activate(group = {PROVIDER}, value = {"param1:yes","param2:ok"}) 多个参数支持, 当url参数中存在参数param1且参数值为yes, 或者url参数中存在参数param2且参数值为ok时该Filter生效
@Activate如果不写value属性值, SPI实现默认是生效的, 如何默认不生效??
- 除了通过value属性指定生效条件外,(推荐使用该方式)
- 不使用
@Activate
注解,则默认不会生效,当期望SPI实现生效时,可以通过如下配置指定
dubbo.provider.filter=providerFilter2,-providerFilter1 #设置provider段Filter
dubbo.consumer.filter=-monitor #禁用consumer端的monitor Filter
示例为: 启用名称为providerFilter2的Filter实现, -
表示禁用, -providerFilter1
表示禁用名称为providerFilter1的Filter实现
dubbo.provider.filter=providerFilter2,-default
示例为: 关闭默认启用的provider端Filter, 只开启了providerFilter2
dubbo.provider.filter=providerFilter2,providerFilter1,default
示例为: providerFilter2,providerFilter1两个Filter放在default Filter之前
注意:
- 这些SPI实现类必须要配置到dubbo的SPI配置文件里, 否则无法被加载
default
代表的是多个默认启用的SPI实现,并不是具体的一个实现类
踩坑点:
如果@Activate
注解value属性写的filter.test
, 但配置的参数是my.filter.test
, 多了一个my
,该SPI实现类也会生效. 完整示例如下:
dubbo.provider.parameters.my.filter.test=aa
或者
dubbo.application.parameters.my.filter.test=aa
原因是源码内部还会通过java.lang.String#endsWith
方法去匹配. 具体见:ExtensionLoader#isActive
源码:
源码分析
ExtensionLoader#getActivateExtension(URL url, String[] values, String group)
源码分析:
该方法用于根据Url中的参数,获取(激活的)符合条件SPI实现类.
参数values
的值部分可由用户设置,最常用的可能是对于dubbo filter的加载控制,但不仅仅局限于此, 还可以对dubbo.consumer.listener
, dubbo.provider.listener
的控制, 有些则是dubbo内部源码传固定值
public List<T> getActivateExtension(URL url, String[] values, String group) {
List<T> activateExtensions = new ArrayList<>();
// TreeMap传入比较器,用于多个实现类之间自动根据Activate#order的值排序
TreeMap<Class, T> activateExtensionsMap = new TreeMap<>(ActivateComparator.COMPARATOR);
Set<String> loadedNames = new HashSet<>();
Set<String> names = CollectionUtils.ofSet(values);
// 如果参数传入-default则表示关闭默认启用的SPI实现,其实就是对Filter处理
// 例如: dubbo.provider.filter=providerFilter2,-default
// 则表示关闭默认启用的provider端Filter, 只开启了providerFilter2
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;
}
// 匹配group, 就是获取作用在provider端还是consumer端的实现
// 如果values已经指定了加载某个名称的SPI实现,则此时不加载, 等默认的加载完成在加载
// -开的表示禁用某个SPI实现
// isActive方法根据@Activate注解的value值和url中的参数判断,是否符合条件
if (isMatchGroup(group, activateGroup)
&& !names.contains(name)
&& !names.contains(REMOVE_VALUE_PREFIX name)
&& isActive(activateValue, url)
&& !loadedNames.contains(name)) {
activateExtensionsMap.put(getExtensionClass(name), getExtension(name));
loadedNames.add(name);
}
}
if (!activateExtensionsMap.isEmpty()) {
activateExtensions.addAll(activateExtensionsMap.values());
}
}
List<T> loadedExtensions = new ArrayList<>();
for (String name : names) {
// 加载names中指定的SPI实现, 如果name是default字符串, 说明循环之前加载的SPI实现都排在默认的之前
//例如 filter1, filter2, default, filter3
//default代表的是多个默认的启用的SPI实现,并不是具体的SPI实现
if (!name.startsWith(REMOVE_VALUE_PREFIX)
&& !names.contains(REMOVE_VALUE_PREFIX name)) {
if (!loadedNames.contains(name)) {
if (DEFAULT_KEY.equals(name)) {
if (!loadedExtensions.isEmpty()) {
activateExtensions.addAll(0, loadedExtensions);
loadedExtensions.clear();
}
} else {
loadedExtensions.add(getExtension(name));
}
loadedNames.add(name);
} else {
// If getExtension(name) exists, getExtensionClass(name) must exist, so there is no null pointer processing here.
String simpleName = getExtensionClass(name).getSimpleName();
logger.warn("Catch duplicated filter, ExtensionLoader will ignore one of them. Please check. Filter Name: " name
". Ignored Class Name: " simpleName);
}
}
}
if (!loadedExtensions.isEmpty()) {
activateExtensions.addAll(loadedExtensions);
}
return activateExtensions;
}
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfjhfag
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13