被該註解修飾的接口,擴展類可能會被加載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排序
默認過濾器
須要被@Activate標識
若是須要在服務暴露時裝載,那麼group="provider"
若是須要在服務引用的時候裝載,那麼group="consumer"
若是想被暴露和引用時同時被裝載,那麼group={"consumer", "provider"}
若是須要url中有某個特定的值才被加載,那麼value={"token", "bb"}
那麼就須要配置一個token, value數組與URL中的某一個屬性相同就好了
普通自定義過濾器
須要配置在url上 好比
過濾器擴展類上能夠有@Activate也能夠沒有(自定義的就不要加了)
去掉某個過濾器
在filter屬性上使用-號標識須要去掉的過濾器 好比: