被该注解修饰的接口,扩展类可能会被加载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属性上使用-号标识须要去掉的过滤器 好比: