• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

dubbo SPI:@Activate注解

武飞扬头像
brucelwl
帮助1

本文基于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;
}
  1. order 用于多个SPI实现类之间排序, beforeafter 也用是用于排序但是被标记为过期,不建议使用. 只用order属性,这样逻辑也简单一点.

  2. group 数组类型,用于指明该Filter作用于provider或是consumer端,可以指明该SPI实现类providerconsumer端同时生效. 但建议不要将provider端和consumer端的逻辑混到同一个SPI实现类

  3. 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实现默认是生效的, 如何默认不生效??

  1. 除了通过value属性指定生效条件外,(推荐使用该方式)
  2. 不使用@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之前

注意:

  1. 这些SPI实现类必须要配置到dubbo的SPI配置文件里, 否则无法被加载
  2. 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
系列文章
更多 icon
同类精品
更多 icon
继续加载