Dubbo扩展点注解之@Adaptive
@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相关推荐
- Dubbo扩展点注解之@Activate
@Activate称为自动激活扩展点注解,主要使用在有多个扩展点实现.需要同时根据不同条件被激活的场景中,如Filter需要多个同时激活,因为每个Filter实现的是不同的功能. @Activate的 ...
- dubbo SPI之@SPI、@Adaptive注解, 以及什么时候动态生成$Adaptive代码
本文基于dubbo2.7.7对如下三个问题分析 @SPI注解的作用 @Adaptive注解的作用,放在Type和Method上的区别和注意点 什么时候动态生成和编译xxx$Adaptive代码 @SP ...
- Dubbo源码分析系列之-深入Dubbo扩展机制
导语: 在之前的博客中分析过Java的SPI机制,其实Dubbo的扩展点加载机制也是从JDK表中的SPI(Service Provider Interface)机制中开发而来,只不过在原生的基础上 ...
- dubbo的@Reference注解作用分析
目的 看看dubbo是怎么给加了@Reference注解的属性注入invoker实例,为什么有时候加了@Reference注解的属性会是null. ReferenceAnnotationBeanPos ...
- Dubbo学习记录(八) -- Spring整合Dubbo中@Reference注解解析原理
Spring整合Dubbo中@Reference注解解析原理 @Reference: 可以用在属性或者方法, 意味着需要引用某个Dubbo服务, 那么Dubbo整合Spring后, 我很好奇怎么把这个 ...
- Dubbo的Reference注解必须先启动provider的问题
目录 现象 看源码分析原因 注解Reference第一步:用Reference注解里的参数初始化ReferenceConfig 注解Reference第二步:从配置文件里获取参数,写入Referenc ...
- Dubbo——扩展点详解
扩展点整体架构 1. RPC层扩展点 按照完整的Dubbo结构分层,RPC层可以分为四层:Config.Proxy.Registry.Cluster.由于Config属于API范畴,因此只关注Prox ...
- 扩展基于注解的spring缓存,使缓存有效期的设置支持方法级别-redis篇
2019独角兽企业重金招聘Python工程师标准>>> 这里用的spring对redis的封装spring-data-redis,主要是对RedisCacheManager做一个二次 ...
- dubbo 扩展单例的保存
2019独角兽企业重金招聘Python工程师标准>>> dubbo 版本 2.6.2 /*** Find the extension with the given name. If ...
- Spring-Boot 整合Dubbo 解决@Reference 注解为null情况
首先检查一下你的spring boot版本是多少? 如果是2.X 不用看了,spring boot 2.x 必定会出现这个问题, 改为 1.5.9 或其他1.x版本,目前生产环境建议使用1.x版本. ...
最新文章
- 2017杭州_考驾照笔记
- doc命令下查看java安装路径
- word2vec如何得到词向量
- python实验三答案_20194123 实验三《Python程序设计》实验报告
- 百度云cdn设置州五年制大专_[百度云CDN]配置过程坑点集合
- ADF:将UI类别与动态表单一起使用
- wordpress安装到虚拟服务器,将WordPress安装在虚拟主机二级目录的方法
- 2月份全球制造业PMI为55.6% 已连续8个月保持在50%以上
- python从入门到放弃表情图-Python 从入门到放弃(一)
- 单用户模式 启动 mysql_单用户模式连接以及故障排除
- LINUX命令必备技能
- mysql 合并_MySQL——合并查询结果
- 在LUA中使用异步IO的思考
- 接入交换机下pc获取不了ip问题处理
- php开发我的世界插件,[搬运插件] [服务端插件] [管理]PlotMe——地皮插件[1.2.5-1.10.2]...
- WinRAR密码破解
- python把正整数翻译成英文_python实现在线翻译
- 从零学习Fluter(八):Flutter的四种运行模式--Debug、Release、Profile和test以及命名规范...
- 网络连接失败(解决办法)
- 小白轻松10分钟搞定Ubuntu常用命令(史上最全)