Activate註解

Activate註解

被該註解修飾的接口,擴展類可能會被加載java

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 都是數組類型。用來指定這個擴展類在什麼條件下激活。app

下面以com.alibaba.dubbo.rpc.filter接口的幾個擴展來講明ide

//如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#loadClassui

/** 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,返回要激活使用的擴展類。url

/**
 * 至關於調用 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);
                //一、name不在 values 指定之列
                //二、而且沒排除name,
                //三、若是擴展類的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;
}

關於最後一個獲取擴展的方法,能夠這樣理解:code

names(=values) 是URL中指定的激活(去掉激活)的值, service.filter=-default 就去掉了全部默認的filter(包括自定義讓dubbo掃描的)server

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上 好比

    過濾器擴展類上能夠有@Activate也能夠沒有(自定義的就不要加了)

  3. 去掉某個過濾器

    在filter屬性上使用-號標識須要去掉的過濾器 好比:

相關文章
相關標籤/搜索