wangyangsoftware 2020-01-29
在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Adaptive { String[] value() default {}; }
@Adaptive注解可以加载实现类的类上或方法上。下面可以通过源码去分析,先放结论:
T getAdaptiveExtension() //在cachedAdaptiveInstance缓存中获取,获取不到则进入下一步创建 -> T createAdaptiveExtension() -> getAdaptiveExtensionClass() //加载完配置文件后,会在cachedAdaptiveClass缓存中获取,获取不到则创建 -> getExtensionClasses() //如果第一次,则加载配置文件 -> createAdaptiveExtensionClass() -> createAdaptiveExtensionClassCode() //动态生成代码 -> Compiler.compile(String code, ClassLoader classLoader) //编译动态生成的代码 -> injectExtension(T instance) //注入
cachedAdaptiveClass缓存是@Adaptive注解在类上的缓存,所以上述代码的大致就是:
动态生成的代码比较长,但是主要的逻辑就是通过Adaptive注解的value属性去设置该接口的Adaptive的规则,Dubbo中的服务调用的所有数据均可以从URL获取(Dubbo的URL总线模式),那么需要Dubbo帮我们动态生成adaptive的扩展接口的方法入参必须包含URL,这样才能根据运行状态动态选择具体实现。一个简单的生成类如下代码:
@Adaptive({"key1", "key2"}) String yell(URL url, String s);
public String yell(URL arg0, String arg1) { if (arg0 == null) { throw new IllegalArgumentException("url == null"); } URL url = arg0; String extName = url.getParameter("key1", url.getParameter("key2", "impl1")); if(extName == null) { throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt) name from url(" + url.toString() + ") use keys([key1, key2])"); } SimpleExt extension = (SimpleExt)ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension(extName); return extension.yell(arg0, arg1); }
可以看到ExtesionLoader中还有一些与@Active注解相关的方法。
可以看出,这些方法都是根据url的某些条件获取一个实现类的列表。@Activate注解主要用处是标注在插件接口实现类上,用来配置该扩展实现类激活条件。在Dubbo框架里面的Filter的各种实现类都通过Activate标注,用来描述该Filter什么时候生效。下面是一些例子:
代码很简单,就做了下简单的注释。
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)) { //"-default" getExtensionClasses(); //未加载配置文件的加载一遍 for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) { String name = entry.getKey(); Activate activate = entry.getValue(); if (isMatchGroup(group, activate.group())) { //如果符合指定的group 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)) { 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; }