@SPI public interface ActivateExt { String echo(String msg); }
@Activate(group = {"default"}) public class ActivateExtImpl1 implements ActivateExt { @Override public String echo(String msg) { return msg; } } @Activate(group = {"group1", "group2"}) public class GroupActivateExtImpl implements ActivateExt { @Override public String echo(String msg) { return msg; } }
@Activate(order = 2, group = {"order"}) public class OrderActivateExtImpl1 implements ActivateExt { @Override public String echo(String msg) { return msg; } } @Activate(order = 1, group = {"order"}) public class OrderActivateExtImpl2 implements ActivateExt { @Override public String echo(String msg) { return msg; } }
@Activate(value = {"value"}, group = {"group"}) public class ValueActivateExtImpl implements ActivateExt { @Override public String echo(String msg) { return msg; } }
在resources下新建META-INF/dubbo/internal文件夹,新建com.alibaba.dubbo.demo.provider.activate.ActivateExt,即接口的全限定名
,文件内容为:segmentfault
group=com.alibaba.dubbo.demo.provider.activate.impl.GroupActivateExtImpl key=com.alibaba.dubbo.demo.provider.activate.impl.ValueActivateExtImpl order1=com.alibaba.dubbo.demo.provider.activate.impl.OrderActivateExtImpl1 order2=com.alibaba.dubbo.demo.provider.activate.impl.OrderActivateExtImpl2 com.alibaba.dubbo.demo.provider.activate.impl.ActivateExtImpl1
下面是几个单元测试及其测试结果,观察测试结果咱们能够得出如下结论:
1) 若是loader.getActivateExtension(URL url, String[] values, String group)中的group参数可以匹配到,就是咱们要选择的,test1中根据group=default匹配到了ActivateExtImpl1,它也是在此条件下须要激活的
2) @Activate中的value是第二层校验参数,第一层是group,在group校验经过的状况下,若是URL中的key参数与类@Activate注解中的value参数一致且key参数对应的值不为空
,则才会被选中
3) order越小,优先级越高ide
/** * 1 * class com.alibaba.dubbo.demo.provider.activate.impl.ActivateExtImpl1 */ @Test public void test1(){ ExtensionLoader<ActivateExt> loader = ExtensionLoader.getExtensionLoader(ActivateExt.class); URL url = URL.valueOf("test://localhost/test"); List<ActivateExt> list = loader.getActivateExtension(url, new String[]{}, "default"); System.out.println(list.size()); list.forEach(item -> System.out.println(item.getClass())); }
/** * 1 * class com.alibaba.dubbo.demo.provider.activate.impl.GroupActivateExtImpl */ @Test public void test2(){ ExtensionLoader<ActivateExt> loader = ExtensionLoader.getExtensionLoader(ActivateExt.class); URL url = URL.valueOf("test://localhost/test"); List<ActivateExt> list = loader.getActivateExtension(url, new String[]{}, "group1"); System.out.println(list.size()); list.forEach(item -> System.out.println(item.getClass())); }
/** * 2 * class com.alibaba.dubbo.demo.provider.activate.impl.OrderActivateExtImpl1 * class com.alibaba.dubbo.demo.provider.activate.impl.ValueActivateExtImpl */ @Test public void test3(){ ExtensionLoader<ActivateExt> loader = ExtensionLoader.getExtensionLoader(ActivateExt.class); URL url = URL.valueOf("test://localhost/test"); // 注意这里要使用url接收,不能直接url.addParameter() url = url.addParameter("value", "test"); List<ActivateExt> list = loader.getActivateExtension(url, new String[]{"order1", "default"}, "group"); System.out.println(list.size()); list.forEach(item -> System.out.println(item.getClass())); }
/** * 2 * class com.alibaba.dubbo.demo.provider.activate.impl.OrderActivateExtImpl2 * class com.alibaba.dubbo.demo.provider.activate.impl.OrderActivateExtImpl1 */ @Test public void test4(){ ExtensionLoader<ActivateExt> loader = ExtensionLoader.getExtensionLoader(ActivateExt.class); URL url = URL.valueOf("test://localhost/test"); List<ActivateExt> list = loader.getActivateExtension(url, new String[]{}, "order"); System.out.println(list.size()); list.forEach(item -> System.out.println(item.getClass())); }
public void test3(){ ExtensionLoader<ActivateExt> loader = ExtensionLoader.getExtensionLoader(ActivateExt.class); URL url = URL.valueOf("test://localhost/test"); // 注意这里要使用url接收,不能直接url.addParameter() url = url.addParameter("value", "test"); List<ActivateExt> list = loader.getActivateExtension(url, new String[]{"order1", "default"}, "group"); System.out.println(list.size()); list.forEach(item -> System.out.println(item.getClass())); }
public List<T> getActivateExtension(URL url, String[] values, String group) { List<T> exts = new ArrayList<T>(); // 将传递进来的values包装成List类型的names List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values); // 包装好的数据中不含"-default" if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { // 获取这个类型的数据的全部扩展信息 getExtensionClasses(); for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) { // 获取拓展的名称,在配置文件中配置的key=value中的key值 String name = entry.getKey(); // 获取注解 Activate activate = entry.getValue();
// 判断group是否匹配,group是程序传进来的值,若是没有设定则返回true表示匹配, // 若是设定了须要进行比较匹配 if (isMatchGroup(group, activate.group())) { // 获取key值即name对应的实例 T ext = getExtension(name); if (!names.contains(name) && !names.contains(Constants.REMOVE_VALUE_PREFIX + name) && isActive(activate, url)) { exts.add(ext); } } } // 排序 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)) { // 若是name是default,就将usrs加入exts头部并清空usrs if (!usrs.isEmpty()) { exts.addAll(0, usrs); usrs.clear(); } } else { // 获取name对应的拓展并加入usrs T ext = getExtension(name); usrs.add(ext); } } } if (!usrs.isEmpty()) { exts.addAll(usrs); } return exts; }
上述代码中用到的cachedActivates是在getExtensionClasses()方法中赋值的,具体能够参考:Dubbo的SPI机制分析1-SPI加载class源码分析
Activate activate = clazz.getAnnotation(Activate.class); if (activate != null) { cachedActivates.put(names[0], activate); }
// 判断group是否匹配,很好理解 private boolean isMatchGroup(String group, String[] groups) { if (group == null || group.length() == 0) { return true; } if (groups != null && groups.length > 0) { for (String g : groups) { if (group.equals(g)) { return true; } } } return false; }
// 将url中的键key与Activate注解中的value值作匹配,而且key所对应的value值不能为空 private boolean isActive(Activate activate, URL url) { String[] keys = activate.value(); if (keys.length == 0) { return true; } for (String key : keys) { for (Map.Entry<String, String> entry : url.getParameters().entrySet()) { String k = entry.getKey(); String v = entry.getValue(); if ((k.equals(key) || k.endsWith("." + key)) && ConfigUtils.isNotEmpty(v)) { return true; } } } return false; }
注意,若是是如下这种形式,传入的values中有-default,则全部的匹配能够经过的@Activate都不会被激活,只有values中指定的能够被激活。若是传入了“-”符合开头的扩展类名,则该扩展点也不会被激活。单元测试
// 输出class com.alibaba.dubbo.demo.provider.activate.impl.OrderActivateExtImpl1 ExtensionLoader<ActivateExt> loader = ExtensionLoader.getExtensionLoader(ActivateExt.class); URL url = URL.valueOf("test://localhost/test"); // 注意这里要使用url接收,不能直接url.addParameter() url = url.addParameter("value", "test"); List<ActivateExt> list = loader.getActivateExtension(url, new String[]{"order1", "-default"}, "group"); System.out.println(list.size()); list.forEach(item -> System.out.println(item.getClass()));