zoukankan      html  css  js  c++  java
  • Activate注解

    Activate注解

    被该注解修饰的接口,扩展类可能会被加载

    ProtocolFilterWrapper.buildInvokerChain

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    public @interface Activate {
        /**
         * 激活当前扩展类的条件之一, 该group参数将会与ExtensionLoader#getActivateExtension方法传入的gruop参数进行匹配
         * @return 要匹配的组名
         * @see ExtensionLoader#getActivateExtension(URL, String, String)
         */
        String[] group() default {};
    
        /**
           当URL中出现该value值时激活扩展类
           例如:@Activate("cache, validation")注释在一个接口上,当URL中有cache或者validation参数时激活
         * @return URL对应的参数的keys
         * @see ExtensionLoader#getActivateExtension(URL, String)
         * @see ExtensionLoader#getActivateExtension(URL, String, String)
         */
        String[] value() default {};
    
        /**
         * 排序信息,可选
         * @return 在当前扩展类执行之前的扩展类
         */
        String[] before() default {};
    
        /**
         * 排序信息,可选
         * @return 在当前扩展类执行之后的扩展类
         */
        String[] after() default {};
    
        /**
         * 当前类执行的权重,越小越先执行
         */
        int order() default 0;
    }
    

    它有两个设置的过滤条件,group,value 都是数组类型。用来指定这个扩展类在什么条件下激活。

    下面以com.alibaba.dubbo.rpc.filter接口的几个扩展来说明

    //如MonitorFilter  这个类是在下下面第四个方法的第一部分解析的
    @Activate(group = {Constants.PROVIDER, Constants.CONSUMER})
    public class MonitorFilter implements Filter {
    }
    表示如果过滤器使用方(通过group指定)传递了group = Constants.PROVIDER 或者Constants.CONSUMER则该Filter激活
    
    //再看这个扩展  这个类是在下下面第四个方法的第一部分解析的
    @Activate(group = Constants.PROVIDER, value = Constants.TOKEN_KEY)
    public class TokenFilter implements Filter {
    }
    如果过滤器使用方(通过group指定)指定group=Constants.PROVIDER并且URL中有参数Constants.TOKEN_KEY,那么激活这个Filter
    

    ​ dubbo中在加载配置文件时会将@Activate修饰的类(实现类)添加到cachedActivates中,在这儿ExtensionLoader#loadClass

    /** key: 扩展名, value: 具体扩展对象 */
    private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
    
    Activate activate = clazz.getAnnotation(Activate.class);
    if (activate != null) {
      // param1: 扩展名 param2: 具体的实现类
    	cachedActivates.put(names[0], activate);
    }
    

    然后ExtensionLoader提供了4个方法来具体使用cachedActivates,返回要激活使用的扩展类。

     /**
     * 相当于调用 getActivateExtension(url, key, null);
     * 从URL中获取扩展点的名字,然后在所有的激活中(@Activate修饰的类),获取扩展对象
     * @param url url
     * @param key  用于从URL中获取扩展点的名字(即:扩展点名字的key)
     * @return 激活的扩展集合
     * @see #getActivateExtension(com.alibaba.dubbo.common.URL, String, String)
     */
    public List<T> getActivateExtension(URL url, String key)
    
      /**
     *   相当于调用  getActivateExtension(url, values, null);
     * 在所有的激活中 values指定的扩展
     * @param url    url
     * @param values 扩展点名字数组
     * @return extension list which are activated
     * @see #getActivateExtension(com.alibaba.dubbo.common.URL, String[], String)
     */
    public List<T> getActivateExtension(URL url, String[] values)
      
      /**
     * 
     * 相当于调用 getActivateExtension(url, url.getParameter(key).split(","), null); 不是有group?为什么相当于这个方法??
     * </pre>
     * 在所有的激活中,@Activate的group参数等于这个参数group
     * @param url   url
     * @param key   扩展点的名字
     * @param group 指定的gruop
     * @return 激活的扩展集合
     * @see #getActivateExtension(com.alibaba.dubbo.common.URL, String[], String)
     */
    public List<T> getActivateExtension(URL url, String key, String group)
    
    /**
     * 获取激活扩展
     * @param url    url
     * @param values 扩展点的名字数组
     * @param group  group
     * @return 满足条件的扩展集合
     * @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);
        // URL中没有server.filter=-default(这代表去掉所有默认过滤器)
        if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
            getExtensionClasses();
            //cachedActivates里放的map结构 接口实现扩展名:其上的Activate对象
            //遍历所有Activate注解对象
            for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
                //spi 扩展类在配置文件中的key
                String name = entry.getKey();
                Activate activate = entry.getValue();
              	//如果有group匹配
                if (isMatchGroup(group, activate.group())) {
                    //获取扩展类
                    T ext = getExtension(name);
                    //1、name不在 values 指定之列
                  	//2、并且没排除name,
                  	//3、如果扩展类的Activate有value值,并且activate的value 在url有对应参数
                    if (!names.contains(name)
                            && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
                            && isActive(activate, url)) {
                        exts.add(ext);
                    }
                }
            }
            //排序Activate 具体实现在ActivateComparator里,实现了Comparator 接口compare方法
            Collections.sort(exts, ActivateComparator.COMPARATOR);
        }
      
        //下面这部分是直接获取values扩展名中对应的扩展类
        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)) {
                //如果name为default,则将默认的过滤器添加到集合的开始
                if (Constants.DEFAULT_KEY.equals(name)) {
                    if (usrs.size() > 0) {
                        exts.addAll(0, usrs);
                        usrs.clear();
                    }
                } else {
                    //通过扩展名,加载扩展添加到结果集
                    T ext = getExtension(name);
                    usrs.add(ext);
                }
            }
        }
        if (usrs.size() > 0) {
            exts.addAll(usrs);
        }
    //返回符合条件的激活扩展
        return exts;
    }
    

    关于最后一个获取扩展的方法,可以这样理解:

    names(=values) 是URL中指定的激活(去掉激活)的值, service.filter=-default 就去掉了所有默认的filter(包括自定义让dubbo扫描的)

    registry://192.168.1.7:9090/com.alibaba.service1?server.filter=-defalut,value1 去掉默认的,添加value1
    registry://192.168.1.7:9090/com.alibaba.service1?server.filter=value1,-value2 去掉value2,添加value1
    

    关于激活的过滤器我们总结一下:

    都需要在扩展类的配置文件中标识 过滤器名=xxx.xxx.xxx.xxxFilter

    1. 默认过滤器

      需要被@Activate标识

      如果需要在服务暴露时装载,那么group="provider"

      如果需要在服务引用的时候装载,那么group="consumer"

      如果想被暴露和引用时同时被装载,那么group={"consumer", "provider"}

      如果需要url中有某个特定的值才被加载,那么value={"token", "bb"}

      ​ 那么就需要配置一个token, value数组与URL中的某一个属性相同就行了

    2. 普通自定义过滤器

      需要配置在url上 比如 <dubbo:provider filter="myFilter" />

      过滤器扩展类上可以有@Activate也可以没有(自定义的就不要加了)

    3. 去掉某个过滤器

      在filter属性上使用-号标识需要去掉的过滤器 比如:<dubbo:provider filter="-monitor" />

  • 相关阅读:
    powershel学习(1)
    JS作用域链(转载)
    C# 对QuotedPrintable进行解码的方法
    SortedList、SortedSet、HashSet、Hashtable、Dictionary、SortedDictionary 排序/可重复排序/过滤重复排序等简单对比
    .net windows 服务中返回服务的安装目录
    c# 中图像的简单二值化处理
    windows下开多个CMD窗口多个进程输出
    生命游戏
    PowerDesigner工具简介
    七大面向对象设计原则(转)
  • 原文地址:https://www.cnblogs.com/qiaozhuangshi/p/11007032.html
Copyright © 2011-2022 走看看