Dubbo-Adaptive实现解析介
daptive的主要功能是对所有的扩展点进行封装为一个类,通过URL传入参数的时动态选择需要使用的
扩展点。其底层的实现原理就是动态代理

ExtensionLoader-getAdaptiveExtension

public T getAdaptiveExtension() {//从缓存中获取 进行Holder和加锁的方式来保证只会被创建一次Object instance = cachedAdaptiveInstance.get();if (instance == null) {//为空判断有没有错误 如果直接已经有创建并且错误的情况,则直接返回错误信息,防止重复没必要的创建if (createAdaptiveInstanceError != null) {throw new IllegalStateException("Failed to create adaptive instance: " +createAdaptiveInstanceError.toString(),createAdaptiveInstanceError);}//加锁synchronized (cachedAdaptiveInstance) {//再次从缓存中获取 instance = cachedAdaptiveInstance.get();if (instance == null) {try {//创建AdaptiveExtension  这里真实的进行创建操作instance = createAdaptiveExtension();//放入缓存cachedAdaptiveInstance.set(instance);} catch (Throwable t) {createAdaptiveInstanceError = t;throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);}}}}return (T) instance;}

createAdaptiveExtension

/*** 创建xxxAdaptive注解类的扩展* @return*/@SuppressWarnings("unchecked")private T createAdaptiveExtension() {try {//自动依赖注入injectExtension// 这里使用`getAdaptiveExtensionClass`方法进行构建类并且执行实例化// 然后和普通的其他class相同,依旧使用injectExtension进行扩展return injectExtension((T) getAdaptiveExtensionClass().newInstance());} catch (Exception e) {throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);}}

injectExtension

private T injectExtension(T instance) {//检测objectFactory字段if (objectFactory == null) {return instance;}try {//遍历其中的所有方法for (Method method : instance.getClass().getMethods()) {//方法遍历判断是否为setter方法  如果不是,忽略该方法继续下一个方法if (!isSetter(method)) {// 是否是set方法// 1. 以"set"开头// 2. 参数长度为1// 3. 是公开的方法continue;}/*** Check {@link DisableInject} to see if we need auto injection for this property*/if (method.getAnnotation(DisableInject.class) != null) {//判断是否禁止注入 如果方法上明确标注了@DisableInject注解,忽略该方法continue;}//根据setter方法的参数,确定扩展接口Class<?> pt = method.getParameterTypes()[0];//判断是否为基本类型 原始类型(boolean、char、byte、short、int、long、float、double)//如果参数为简单类型,忽略该setter方法(略)if (ReflectUtils.isPrimitives(pt)) {continue;}try {//setter方法注入 获取需要set的扩展点名称String property = getSetterProperty(method);//从扩展中获取对象 加载并实例化扩展实现类Object object = objectFactory.getExtension(pt, property);//从ExtensionLoader中加载指定的扩展点 比如有一个方法为setRandom(LoadBalance loadBalance),那么则以为着需要加载负载均衡中名为random的扩展点if (object != null) {method.invoke(instance, object);}} catch (Exception e) {logger.error("Failed to inject via method " + method.getName()+ " of interface " + type.getName() + ": " + e.getMessage(), e);}}} catch (Exception e) {logger.error(e.getMessage(), e);}return instance;}

getAdaptiveExtensionClass

private Class<?> getAdaptiveExtensionClass() {//确保已经加载了所有的扩展类信息getExtensionClasses();if (cachedAdaptiveClass != null) {//如果已经加载过了,则直接返回return cachedAdaptiveClass;}//否则进行构建操作return cachedAdaptiveClass = createAdaptiveExtensionClass();}

获取所有的扩展类信息

    private Map<String, Class<?>> getExtensionClasses() {//从缓存中获取 ExtensionLoader 加载的扩展名与扩展实现类之间的映射关系。cachedNames 集合的反向关系缓存Map<String, Class<?>> classes = cachedClasses.get();if (classes == null) {synchronized (cachedClasses) {classes = cachedClasses.get();if (classes == null) {//加载配置文件classes = loadExtensionClasses();cachedClasses.set(classes);}}}return classes;}

createAdaptiveExtensionClass

    /*** 生成一个 xxxx$Adaptive 适配器类* @return*/private Class<?> createAdaptiveExtensionClass() {//实例化一个新的Adaptive的代码生成器,并且进行代码生成String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();//获取当前类的类加载器ClassLoader classLoader = findClassLoader();//通过扩展点,寻找编译器, 目前有Java自带的编译器和Javassist的编译器org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();//编译并且生成classreturn compiler.compile(code, classLoader);}

具体通过 AdaptiveClassLoaderCodeGenerator.generate 方法来进行实现真正的代码生成

public String generate() {// no need to generate adaptive class since there's no adaptive method found.//如果没有任何方法标记为Adaptive,则不做处理if (!hasAdaptiveMethod()) {throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");}//行编写代码StringBuilder code = new StringBuilder();//生成包的信息code.append(generatePackageInfo());//生成 生成引用信息 importcode.append(generateImports());//生成类声明code.append(generateClassDeclaration());//生成每一个方法Method[] methods = type.getMethods();for (Method method : methods) {code.append(generateMethod(method));}//输出最后的一个"}"来结束当前类code.append("}");if (logger.isDebugEnabled()) {logger.debug(code.toString());}return code.toString();}

generateMethod

 private String generateMethod(Method method) {//方法返回类型String methodReturnType = method.getReturnType().getCanonicalName();//方法名称String methodName = method.getName();//生成方法内容String methodContent = generateMethodContent(method);//生成方法参数String methodArgs = generateMethodArguments(method);//生成方法异常String methodThrows = generateMethodThrows(method);//格式化为一个字符串// public %s %s(%s) %s {// %s// }return String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent);}

generateMethodContent

private String generateMethodContent(Method method) {//获取Adaptive注解,只支持含有Adaptive注解方法处理Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);StringBuilder code = new StringBuilder(512);if (adaptiveAnnotation == null) {//没有该注解,直接抛出异常return generateUnsupported(method);} else {//获取URL参数的所在位置int urlTypeIndex = getUrlTypeIndex(method);// found parameter in URL type//增加判断url不为空的代码if (urlTypeIndex != -1) {// Null Point checkcode.append(generateUrlNullCheck(urlTypeIndex));} else {// did not find parameter in URL type//获取这个方法中的所有参数列表// 寻找每个参数中是否有"get"开头的方法,并且返回值是URL的// 如果有则同样认定为找到,否则抛出异常code.append(generateUrlAssignmentIndirectly(method));}//获取扩展点的适配名称String[] value = getMethodAdaptiveValue(adaptiveAnnotation);// 判断是否有参数是Invocation类// 这里判断的主要目的在于,拥有Invocation时,则获取扩展名称的方式发生改变// 存在Invocation时,通过getMethodParameter,否则通过getParameter来执行// getMethodParameter是dubboURL中特有的,用于将"test.a"转换为"testA"的形式boolean hasInvocation = hasInvocationArgument(method);//增加有Invocation类时的不为空判断code.append(generateInvocationArgumentNullCheck(method));//生成获取扩展点名称的方法code.append(generateExtNameAssignment(value, hasInvocation));// check extName == null?//检查扩展点不能为空code.append(generateExtNameNullCheck(value));//获取扩展点实现code.append(generateExtensionAssignment());//返回扩展点中的真实调用// return statementcode.append(generateReturnAndInvocation(method));}return code.toString();}

Dubbo-Adaptive实现解析相关推荐

  1. 【dubbo源码解析】 --- dubbo spi 机制(@SPI、@Adaptive)详解

    本文对应源码地址:https://github.com/nieandsun/dubbo-study 注意:dubbo 要求SPI扩展点的实现类必须要有一个无参构造,除了Wrapper实现类之外 文章目 ...

  2. Dubbo原码解析(version:2.5.3)

    一.启动 dubbo借助spring的schemas来启动(dubbo.jar/META-INF/spring.schemas). 在dubbo.jar/META-INF/spring.handler ...

  3. dubbo源码解析(九)远程通信——Transport层

    远程通讯--Transport层 目标:介绍Transport层的相关设计和逻辑.介绍dubbo-remoting-api中的transport包内的源码解析. 前言 先预警一下,该文篇幅会很长,做好 ...

  4. dubbo源码解析(十)远程通信——Exchange层

    远程通讯--Exchange层 目标:介绍Exchange层的相关设计和逻辑.介绍dubbo-remoting-api中的exchange包内的源码解析. 前言 上一篇文章我讲的是dubbo框架设计中 ...

  5. Dubbo源码解析-Dubbo服务消费者_Dubbo协议(一)

    前言: 在介绍完Dubbo 本地模式(Injvm协议)下的服务提供与消费后,上文我们又介绍了Dubbo远程模式(dubbo协议)下的服务暴露过程,本质上就是通过Netty将dubbo协议端口暴露出去, ...

  6. Dubbo源码解析 --- DIRECTORY和ROUTER

    Dubbo源码解析 --- DIRECTORY和ROUTER 今天看一下Directory和Router. 我们直接从代码看起(一贯风格),先看后总结,对着总结再来看,相信会收获很多.我们先看com. ...

  7. dubbo源码解析-集群容错架构设计

    前言 本来是想把整个dubbo源码解析一次性弄完,再做成一个系列来发布的,但是正巧最近有位好朋友要去杭州面试,就和我交流了一下.本着对dubbo源码略有心得的心态,在交流过程中也发表了个人的一些粗劣的 ...

  8. dubbo源码解析-zookeeper创建节点

    前言 在之前dubbo源码解析-本地暴露中的前言部分提到了两道高频的面试题,其中一道dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,那发布者和订阅者还能通信吗?在上周的dubbo源码 ...

  9. dubbo源码解析(二)

    大家好,我是烤鸭: dubbo 源码解析: 1.服务导出 介绍: Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑.整个逻辑大致可分为三 ...

  10. dubbo(5) Dubbo源码解析之服务调用过程

    来源:https://juejin.im/post/5ca4a1286fb9a05e731fc042 Dubbo源码解析之服务调用过程 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与 ...

最新文章

  1. Spring Cloud Alibaba 极速运维:微服务与 DevOps
  2. 如何 判断 设备 是否 连接 上 了 wifi
  3. 卷积神经的这些坑你都踩过吗?
  4. 我应该如何道德地接近用户密码存储以便以后的明文检索?
  5. DoD模型与OSI模型的关系及其协议对应关系
  6. Tour West Australia by Motorcycle
  7. (34)SystemVerilog语言编写计数器
  8. Spring mvc 参数类型转换
  9. 经典算法题每日演练——第二十四题 梳排序
  10. 虚拟机、集群、数据中心虚拟化
  11. tf.train.Saver,和模型参数微调
  12. java 符号引用与直接引用
  13. java+junit百科_JUnit介绍
  14. VMware ESXi 6.7注入第三方RAID驱动
  15. 什么是量子加密(二)
  16. tk免费顶级域名注册及使用
  17. 【JZOJ4939】平均值 题解
  18. selenium模拟登录某宝
  19. “千山之首 大果榛品”2022年辽阳大果榛子地理标志标识推介会开幕
  20. 计算机底层:进程与线程。

热门文章

  1. Python学习——三分钟分析目前最火的电视剧
  2. 小新pro16独显版安装NVIDIA驱动
  3. 使用Hourglass网络来理解人体姿态
  4. linux cp指令:略过目录 问题解决
  5. ACCESS 中屏蔽shift键
  6. 德国地学研究中心到国家基础地理信息中心作学术交流
  7. 51单片机仿真例程-八段数码管
  8. 方舟服务器在线人数查询软件,方舟生存进化怎么查看在线人数
  9. 互联网创业者必备的十种思维
  10. jvm-虚拟机栈笔记【详细】