一、用法
Activate注解表示一个扩展是否被激活(使用),可以放在类定义和方法上,dubbo用它在spi扩展类定义上,表示这个扩展实现激活条件和时机。
@Activate(group = Constants.PROVIDER) public class DrpcServerInterceptor implements Filter{private final ServerRequestInterceptor serverRequestInterceptor;private final ServerResponseInterceptor serverResponseInterceptor;public DrpcServerInterceptor() { String sendUrl = ZipkinConfig.getProperty(ZipkinConstants.SEND_ADDRESS);Sender sender = OkHttpSender.create(sendUrl);Reporter<zipkin.Span> reporter = AsyncReporter.builder(sender).build();String application = ZipkinConfig.getProperty(ZipkinConstants.BRAVE_NAME);//RpcContext.getContext().getUrl().getParameter("application");Brave brave = new Brave.Builder(application).reporter(reporter).build();this.serverRequestInterceptor = brave.serverRequestInterceptor();this.serverResponseInterceptor = brave.serverResponseInterceptor();} 。。。。 }
表示该类只在生产者生效。
二、源码解析
先看下接口定义:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Activate {/*** Group过滤条件。* <br />* 包含{@link ExtensionLoader#getActivateExtension}的group参数给的值,则返回扩展。* <br />* 如没有Group设置,则不过滤。*/String[] group() default {};/*** Key过滤条件。包含{@link ExtensionLoader#getActivateExtension}的URL的参数Key中有,则返回扩展。* <p/>* 示例:<br/>* 注解的值 <code>@Activate("cache,validatioin")</code>,* 则{@link ExtensionLoader#getActivateExtension}的URL的参数有<code>cache</code>Key,或是<code>validatioin</code>则返回扩展。* <br/>* 如没有设置,则不过滤。*/String[] value() default {};/*** 排序信息,可以不提供。*/String[] before() default {};/*** 排序信息,可以不提供。*/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指定)属于Constants.PROVIDER(服务提供方)或者Constants.CONSUMER(服务消费方)就激活使用这个过滤器。
//再看这个扩展 @Activate(group = Constants.PROVIDER, value = Constants.TOKEN_KEY) public class TokenFilter implements Filter { }
表示如果过滤器使用方(通过group指定)属于Constants.PROVIDER(服务提供方)并且 URL中有参数 Constants.TOKEN_KEY(token)时就激活使用这个过滤器。
再看下具体实现:
dubbo在ExtensionLoader类,解析某个接口扩展实现类时,会把所有实现类中有Activate注解的,都先放到一个全局map中。
Activate activate = clazz.getAnnotation(Activate.class); if (activate != null) {//如果有,加入,cachedActivates map 扩展名:实现类class,形式cachedActivates.put(names[0], activate); }
然后提供了4个方法来具体使用cachedActivates,返回要激活使用的扩展。
/*** This is equivalent to <pre>* getActivateExtension(url, key, null);* </pre>* 在所有的激活中,要使用key 指定的扩展* @param url url* @param key url parameter key which used to get extension point names* @return extension list which are activated.* @see #getActivateExtension(com.alibaba.dubbo.common.URL, String, String)*/public List<T> getActivateExtension(URL url, String key)/*** This is equivalent to <pre>* getActivateExtension(url, url.getParameter(key).split(","), null);* </pre>* 在所有的激活中,要指定的group 外加 使用key 指定的扩展* @param url url* @param key url parameter key which used to get extension point names* @param group group* @return extension list which are activated.* @see #getActivateExtension(com.alibaba.dubbo.common.URL, String[], String)*/public List<T> getActivateExtension(URL url, String key, String group)/*** This is equivalent to <pre>* getActivateExtension(url, values, null);* </pre>* 在所有的激活中 values指定的扩展* @param url url* @param values extension point names* @return extension list which are activated* @see #getActivateExtension(com.alibaba.dubbo.common.URL, String[], String)*/public List<T> getActivateExtension(URL url, String[] values)//最后其实都有下面方法实现/*** Get activate extensions.* 加载active扩展* @param url url* @param values extension point names* @param group group* @return extension list which are activated* @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);if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {getExtensionClasses();//cachedActivates里放的map结构 接口实现扩展名:其上的Activate对象for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {//遍历所有Activate注解对象String name = entry.getKey();//spi 扩展名Activate activate = entry.getValue();if (isMatchGroup(group, activate.group())) {//如果有group匹配T ext = getExtension(name);//加在扩展类//name不在 values 指定之列,并且没排除name,并且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);}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)) {//遍历所有没有排除的扩展名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;}