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
-
默認過濾器
需要被@Activate標識
如果需要在服務暴露時裝載,那么group="provider"
如果需要在服務引用的時候裝載,那么group="consumer"
如果想被暴露和引用時同時被裝載,那么group={"consumer", "provider"}
如果需要url中有某個特定的值才被加載,那么value={"token", "bb"}
那么就需要配置一個token, value數組與URL中的某一個屬性相同就行了
-
普通自定義過濾器
需要配置在url上 比如 <dubbo:provider filter="myFilter" />
過濾器擴展類上可以有@Activate也可以沒有(自定義的就不要加了)
-
去掉某個過濾器
在filter屬性上使用-號標識需要去掉的過濾器 比如:<dubbo:provider filter="-monitor" />