@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. vue结合element实现自定义上传图片、文件

    参考了很多文献,感谢各位帖子,所以也想把自己遇到不会的东西分享出来,菜鸟一枚大家一进步!

  2. apache启动失败,提示80端口被占用

    首先检查80端口被什么程序占用,方法:cmd进DOS,输入netstat -ano 80端口被为4的进程占用,有两种可能:一种情况是本机中安装了sqlserver 2008,80端口被SqlServe ...

  3. Matlab高级教程_第二篇:MATLAB和C#一些常用的矩阵运算方法的转换

    1.相关方法已经生产引用,直接调用的结果如下: 2. 相关调用代码如下: using System; using System.Collections.Generic; using System.Li ...

  4. SAP PM:设备主数据常用BAPI

    如下参考: STATUS_CHANGE_EXTERN BAPI_EQMT_MODIFY BAPI_EQUI_CHANGE PM BAPI: Change Equipment BAPI_EQUI_CRE ...

  5. svn http

    yum install -y httpd subversion mod_dav_svn mkdir -p /var/lib/svn cd /var/lib/svn svnadmin create de ...

  6. 1)public,provite和protect不能放在函数函数头

    今天我才知道,原来这三个修饰的东西,只是用在类里面方法,怪不得一个叫方法,一个叫函数了,原来就是区分他们,哎, 今天遇到这么一个问题: <?php //header('Content-type: ...

  7. CMOS

    CMOS是Complementary Metal Oxide Semiconductor(互补金属氧化物半导体)的缩写.它是指制造大规模集成电路芯片用的一种技术或用这种技术制造出来的芯片,是电脑主板上 ...

  8. json转换为go类文件,js脚本,nodejs执行

    js写的代码生成脚本,json生成对应的go type对象 作json转换用 js脚本无甚何依赖,可以直接运行 执行前,按需更改文件 示例 var topname="Data"; ...

  9. 学习python-20191108(2)REST接口相关

    一.客户登录验证 在使用接口前,需要对客户进行登录验证 enums.py文件代码: #定义枚举,客户端登录的方式有很多种形式:邮箱登录.手机登录.微信小程序登录.微信公众号登录 class Clien ...

  10. django框架进阶-admin-长期维护

    ###############    django--admin的使用    ################ # django后台管理: # 第一步: # 在settings文件中修改语言和时区 L ...