@Adaptive称为自适应扩展点注解。

在实际应用场景中,一个扩展接口往往会有多种实现类,因为Dubbo是基于URL驱动,所以在运行时,通过传入URL中的某些参数来动态控制具体实现,这便是Dubbo的扩展点自适应特性。

在Dubbo中,@Adaptive一般用来修饰类和接口方法,在整个Dubbo框架中,只有少数几个地方使用在类级别上,如AdaptiveExtensionFactory和AdaptiveCompiler,其余都标注在方法上。

修饰方法级别

当扩展点的方法被@Adaptive修饰时,在Dubbo初始化扩展点时会自动生成和编译一个动态的Adaptive类。

以Protocol接口为例:

@SPI("dubbo")
public interface Protocol {int getDefaultPort();@Adaptive<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;@Adaptive<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;void destroy();
}

export和refer方法都被@Adaptive修饰,Dubbo在初始化扩展点时,会生成一个Protocol$Adaptive类,里面会实现这两个方法,生成的代码如下:

public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {public void destroy() {throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");}public int getDefaultPort() {throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");}public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");if (arg0.getUrl() == null)throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");org.apache.dubbo.common.URL url = arg0.getUrl();String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());if (extName == null)throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);return extension.export(arg0);}public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {if (arg1 == null) throw new IllegalArgumentException("url == null");org.apache.dubbo.common.URL url = arg1;String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());if (extName == null)throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);return extension.refer(arg0, arg1);}
}

方法里会有一些抽象的通用逻辑,根据解析URL得到的信息,找到并调用真正的实现类,这显然是一种动态代理模式。

修饰类级别

以AdaptiveCompiler类为例,它作为Compiler扩展点的实现类,被@Adaptive在类级别修饰。

@Adaptive
public class AdaptiveCompiler implements Compiler {private static volatile String DEFAULT_COMPILER;public static void setDefaultCompiler(String compiler) {DEFAULT_COMPILER = compiler;}@Overridepublic Class<?> compile(String code, ClassLoader classLoader) {Compiler compiler;ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);String name = DEFAULT_COMPILER; // copy referenceif (name != null && name.length() > 0) {compiler = loader.getExtension(name);} else {compiler = loader.getDefaultExtension();}return compiler.compile(code, classLoader);}}

在类所在工程的resource/META-INF/dubbo/internal路径下可以找到扩展点配置文件org.apache.dubbo.common.compiler.Compiler

adaptive=org.apache.dubbo.common.compiler.support.AdaptiveCompiler
jdk=org.apache.dubbo.common.compiler.support.JdkCompiler
javassist=org.apache.dubbo.common.compiler.support.JavassistCompiler

这样在Dubbo加载扩展点时便可以根据adaptive属性找到AdaptiveComiler实现类,再通过compiler方法决定是调用默认实现,还是指定的实现,默认实现由扩展点接口上的@SPI注解指定。

@SPI("javassist")
public interface Compiler {/*** Compile java source code.** @param code        Java source code* @param classLoader classloader* @return Compiled class*/Class<?> compile(String code, ClassLoader classLoader);}

对比方法级别,类级别省略了生成动态代理类的过程,由指定类决定具体实现,另外对于同一个扩展点,类级别的Adaptive只能有一个。

Dubbo扩展点注解之@Adaptive相关推荐

  1. Dubbo扩展点注解之@Activate

    @Activate称为自动激活扩展点注解,主要使用在有多个扩展点实现.需要同时根据不同条件被激活的场景中,如Filter需要多个同时激活,因为每个Filter实现的是不同的功能. @Activate的 ...

  2. dubbo SPI之@SPI、@Adaptive注解, 以及什么时候动态生成$Adaptive代码

    本文基于dubbo2.7.7对如下三个问题分析 @SPI注解的作用 @Adaptive注解的作用,放在Type和Method上的区别和注意点 什么时候动态生成和编译xxx$Adaptive代码 @SP ...

  3. Dubbo源码分析系列之-深入Dubbo扩展机制

    导语:   在之前的博客中分析过Java的SPI机制,其实Dubbo的扩展点加载机制也是从JDK表中的SPI(Service Provider Interface)机制中开发而来,只不过在原生的基础上 ...

  4. dubbo的@Reference注解作用分析

    目的 看看dubbo是怎么给加了@Reference注解的属性注入invoker实例,为什么有时候加了@Reference注解的属性会是null. ReferenceAnnotationBeanPos ...

  5. Dubbo学习记录(八) -- Spring整合Dubbo中@Reference注解解析原理

    Spring整合Dubbo中@Reference注解解析原理 @Reference: 可以用在属性或者方法, 意味着需要引用某个Dubbo服务, 那么Dubbo整合Spring后, 我很好奇怎么把这个 ...

  6. Dubbo的Reference注解必须先启动provider的问题

    目录 现象 看源码分析原因 注解Reference第一步:用Reference注解里的参数初始化ReferenceConfig 注解Reference第二步:从配置文件里获取参数,写入Referenc ...

  7. Dubbo——扩展点详解

    扩展点整体架构 1. RPC层扩展点 按照完整的Dubbo结构分层,RPC层可以分为四层:Config.Proxy.Registry.Cluster.由于Config属于API范畴,因此只关注Prox ...

  8. 扩展基于注解的spring缓存,使缓存有效期的设置支持方法级别-redis篇

    2019独角兽企业重金招聘Python工程师标准>>> 这里用的spring对redis的封装spring-data-redis,主要是对RedisCacheManager做一个二次 ...

  9. dubbo 扩展单例的保存

    2019独角兽企业重金招聘Python工程师标准>>> dubbo 版本 2.6.2 /*** Find the extension with the given name. If ...

  10. Spring-Boot 整合Dubbo 解决@Reference 注解为null情况

    首先检查一下你的spring boot版本是多少? 如果是2.X 不用看了,spring boot 2.x 必定会出现这个问题, 改为 1.5.9 或其他1.x版本,目前生产环境建议使用1.x版本. ...

最新文章

  1. 2017杭州_考驾照笔记
  2. doc命令下查看java安装路径
  3. word2vec如何得到词向量
  4. python实验三答案_20194123 实验三《Python程序设计》实验报告
  5. 百度云cdn设置州五年制大专_[百度云CDN]配置过程坑点集合
  6. ADF:将UI类别与动态表单一起使用
  7. wordpress安装到虚拟服务器,将WordPress安装在虚拟主机二级目录的方法
  8. 2月份全球制造业PMI为55.6% 已连续8个月保持在50%以上
  9. python从入门到放弃表情图-Python 从入门到放弃(一)
  10. 单用户模式 启动 mysql_单用户模式连接以及故障排除
  11. LINUX命令必备技能
  12. mysql 合并_MySQL——合并查询结果
  13. 在LUA中使用异步IO的思考
  14. 接入交换机下pc获取不了ip问题处理
  15. php开发我的世界插件,[搬运插件] [服务端插件] [管理]PlotMe——地皮插件[1.2.5-1.10.2]...
  16. WinRAR密码破解
  17. python把正整数翻译成英文_python实现在线翻译
  18. 从零学习Fluter(八):Flutter的四种运行模式--Debug、Release、Profile和test以及命名规范...
  19. 网络连接失败(解决办法)
  20. 小白轻松10分钟搞定Ubuntu常用命令(史上最全)

热门文章

  1. 8/30 Hourglass网络原理
  2. 解决JSONNull导致的JSONObject序列化问题
  3. 啥是map啥是reduce
  4. Python 实现三维建模工具(上)
  5. Matlab save colormap
  6. 【Web技术】441- 蚂蚁前端研发最佳实践
  7. 暴躁的一天从Ubuntu搜狗拼音开始
  8. poi-tl导出word出错
  9. s5p4418的uboot网络无法使用问题解决
  10. java中直线距离的计算_java计算两点间的距离方法总结