@Adaptive注解

在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Adaptive {
String[] value() default {};
}

@Adaptive注解可以加载实现类的类上或方法上。下面可以通过源码去分析,先放结论:

  • 注解在实现类上时,提供一种标识表名此实现类并不提供具体的业务实现,而是一个该接口的适配器。例如AdaptiveCompiler、AdaptiveExtensionFactory。
  • 注解在接口方法上时,根据某种规则动态生成代码,动态适配。例如Protocol接口

主要方法

T getAdaptiveExtension()

调用流程

T getAdaptiveExtension()         //在cachedAdaptiveInstance缓存中获取,获取不到则进入下一步创建
-> T createAdaptiveExtension()
-> getAdaptiveExtensionClass() //加载完配置文件后,会在cachedAdaptiveClass缓存中获取,获取不到则创建
-> getExtensionClasses() //如果第一次,则加载配置文件
-> createAdaptiveExtensionClass()
-> createAdaptiveExtensionClassCode() //动态生成代码
-> Compiler.compile(String code, ClassLoader classLoader) //编译动态生成的代码
-> injectExtension(T instance) //注入

cachedAdaptiveClass缓存是@Adaptive注解在类上的缓存,所以上述代码的大致就是:

  • 如果@Adaptive注解在类上,则直接返回这个类的实例
  • 如果@Adaptive注解在方法上,则动态生成一个类。

createAdaptiveExtensionClassCode()

动态生成的代码比较长,但是主要的逻辑就是通过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);
}

@Ac 大专栏  Dubbo源码学习(二)tivate注解

可以看到ExtesionLoader中还有一些与@Active注解相关的方法。

  • List getActivateExtension(URL url, String key)
  • List getActivateExtension(URL url, String key, String group)
  • List getActivateExtension(URL url, String[] values, String group)

可以看出,这些方法都是根据url的某些条件获取一个实现类的列表。@Activate注解主要用处是标注在插件接口实现类上,用来配置该扩展实现类激活条件。
在Dubbo框架里面的Filter的各种实现类都通过Activate标注,用来描述该Filter什么时候生效。下面是一些例子:

  • MonitorFilter( @Activate(group = {Constants.PROVIDER, Constants.CONSUMER}) ) 用来告诉Dubbo框架这个Filter是在服务提供端和消费端会生效的;
  • TimeoutFilter( @Activate(group = Constants.PROVIDER) )则是只在服务提供端生效,消费端是不会调用该Filter;
  • ValidationFilte( @Activate(group = { Constants.CONSUMER, Constants.PROVIDER }, value = Constants.VALIDATION_KEY, order = 10000) )
    要激活的条件除了在消费端和服务提供端激活,value 表明了URL参数中必须包含validation才会被激活。order 即激活顺序。

getActivateExtension的实现

代码很简单,就做了下简单的注释。

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;
}

Dubbo源码学习(二)的更多相关文章

  1. dubbo源码学习(二) : spring 自定义标签

    做dubbo的配置时很容易发现,dubbo有一套自己的标签,提供给开发者配置,其实每一个标签对应着一个 实体,在容器启动的时候,dubbo会对所有的配置进行解析然后将解析后的内容设置到实体里,最终du ...

  2. Dubbo源码学习--服务是如何引用的

    ReferenceBean 跟服务引用一样,Dubbo的reference配置会被转成ReferenceBean类,ReferenceBean实现了InitializingBean接口,直接看afte ...

  3. Dubbo源码学习--注册中心分析

    相关文章: Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 注册中心 关于注册中心,Dubbo提供了多个实现方式,有比较成熟的使用zookeeper 和 redis 的 ...

  4. Dubbo源码学习--服务是如何发布的

    相关文章: Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 ServiceBean ServiceBean 实现ApplicationListener接口监听Conte ...

  5. Dubbo源码学习--集群负载均衡算法的实现

    相关文章: Dubbo源码学习文章目录 前言 Dubbo 的定位是分布式服务框架,为了避免单点压力过大,服务的提供者通常部署多台,如何从服务提供者集群中选取一个进行调用, 就依赖Dubbo的负载均衡策 ...

  6. Dubbo源码学习文章目录

    目录 Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 Dubbo源码学习--注册中心分析 Dubbo源码学习--集群负载均衡算法的实现

  7. Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题

    Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题 相关文章: Dubbo源码学习文章目录 前言 主要是前一阵子换了工作,第一个任务就是解决目前团队在 Dubbo 停机时产生的问题 ...

  8. dubbo源码学习(二)dubbo容器启动流程简略分析

    dubbo版本2.6.3 继续之前的dubbo源码阅读,从com.alibaba.dubbo.container.Main.main(String[] args)作为入口 简单的数据一下启动的流程 1 ...

  9. Dubbo源码学习之-Adaptive自适应扩展

    前言 最近三周基本处于9-10-6与9-10-7之间,忙碌的节奏机会丢失了自己.除了之前干施工的那段经历,只看参加软件开发以来,前段时间是最繁忙的了.忙的原因,不是要完成的工作量大,而是各种环境问题, ...

随机推荐

  1. eureka学习之二:自我保护机制

    提供者和消费者:消费者通过注册服务名称,找rpc远程地址,调用提供者的接口 Eureka的自我保护机制:

  2. 1年6亿美元!Uber小费功能或引行业变革

    当一个行业由稚嫩走向成熟,必然要在大方向上面对两个选择--一是继续在行业内深挖,二是不断向外围扩张.就像电商行业原本只是纯粹的交易中介形态,现在既不断深挖垂直电商新模式,又继续拓展新业务试图玩转跨界. ...

  3. Git log 中文乱码

    以下三条命令搞定(系统是centos  7.4) git config --global i18n.commitencoding utf-8 git config --global i18n.logo ...

  4. python-django电商项目-需求分析架构设计数据库设计_20191115

    python-django电商项目需求分析 1.用户模块 1)注册页 注册时校验用户名是否已被注册. 完成用户信息的注册. 给用户的注册邮箱发送邮件,用户点击邮件中的激活链接完成用户账户的激活. 2) ...

  5. VLC查看日志的方法

    最近使用VLC去播放rtsp网络串流总是失败,显示要查看日志,查看的方法: 进入VLC的GUI,点击视图,添加界面,添加调试窗口: 添加调试窗口,会弹出界面: 上面会有报错的提示. 大佬如果有其他的办 ...

  6. Skype for Business

    Skype for Business提供在线会议.即时消息.视频会议等功能 一.界面介绍 1.登陆主界面,选择当前在线状态 2.添加联系人 在搜索框中输入想要寻找用户的姓名.电子邮件地址或电话号码-& ...

  7. iOS炫酷动画图案、多种选择器、网络测速、滑动卡片效果等源码

    iOS精选源码 对网络进行测速 自实现大标题,配合原生骨架屏demo 简单方便的pickerVIew记录数据 LZPickerView 科技风绘制组件,简单快速"画"出炫酷图案 R ...

  8. 《C Prime Plus》第十节笔记

    数组和指针 10.1 数组 10.1.1 初始化数组 标量变量:只储存单个值的变量 创建只读数组,应该用const声明和初始化数组 const int days[] = {1,2,3,5}; 省略方括 ...

  9. jenkins-自定义工作空间目录

  10. MySQL性能优化的21条最佳经验

    英文原文:<Top 20+ MySQL Best Practices>,编译:陈皓 今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只 ...