大家好,我是烤鸭:

今天和大家分享dubbo的源码解析。

1.SPI

http://dubbo.apache.org/zh-cn/docs/source_code_guide/dubbo-spi.html

介绍:
SPI 全称为 Service Provider Interface,是一种服务发现机制。
SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。
Dubbo重写了Java原生的SPI。Dubbo SPI 是通过键值对的方式进行配置,按需加载指定的实现类。
源码:
com.alibaba.dubbo.common.extension.ExtensionLoader 
getExtension:
获取拓展类对象。

createExtension:
1. 通过 getExtensionClasses 获取所有的拓展类
2. 通过反射创建拓展对象
3. 向拓展对象中注入依赖 (injectExtension)
4. 将拓展对象包裹在相应的 Wrapper 对象中

将产生的wrapper对象放到 objectFactory 。
objectFactory 变量的类型为 AdaptiveExtensionFactory,AdaptiveExtensionFactory 内部维护了一个 ExtensionFactory 列表,用于存储其他类型的 ExtensionFactory。Dubbo 目前提供了两种 ExtensionFactory,分别是 SpiExtensionFactory 和 SpringExtensionFactory。前者用于创建自适应的拓展,后者是用于从 Spring 的 IOC 容器中获取所需的拓展。 
Dubbo IOC 目前仅支持 setter 方式注入。

2.动态加载

http://dubbo.apache.org/zh-cn/docs/source_code_guide/adaptive-extension.html
介绍:
拓展方法被调用时,根据运行时参数进行加载。 Dubbo 会为拓展接口生成具有代理功能的代码。然后通过 javassist 或 jdk 编译这段代码,得到 Class 类。最后再通过反射创建代理类,整个过程比较复杂。
源码:
@Adaptive 
当 Adaptive 注解在类上时,Dubbo 不会为该类生成代理类。注解在方法(接口方法)上时,Dubbo 则会为该方法生成代理逻辑。

com.alibaba.dubbo.common.extension.ExtensionLoader 
getAdaptiveExtension:
创建自适应拓展。
createAdaptiveExtension:
1. 调用 getAdaptiveExtensionClass 方法获取自适应拓展 Class 对象
2. 通过反射进行实例化
3. 调用 injectExtension 方法向拓展实例中注入依赖

getAdaptiveExtensionClass:
1. 调用 getExtensionClasses 获取所有的拓展类
2. 检查缓存,若缓存不为空,则返回缓存
3. 若缓存为空,则调用 createAdaptiveExtensionClass 创建自适应拓展类动态生成代码(类):
代码生成的顺序与 Java 文件内容顺序一致,首先会生成 package 语句,然后生成 import 语句,紧接着生成类名等代码。

// 生成 package 代码:package + type 所在包
codeBuilder.append("package ").append(type.getPackage().getName()).append(";");
// 生成 import 代码:import + ExtensionLoader 全限定名
codeBuilder.append("\nimport ").append(ExtensionLoader.class.getName()).append(";");
// 生成类代码:public class + type简单名称 + $Adaptive + implements + type全限定名 + {
codeBuilder.append("\npublic class ").append(type.getSimpleName()).append("$Adaptive").append(" implements ").append(type.getCanonicalName()).append(" {");// ${生成方法}codeBuilder.append("\n}");

动态生成代码(方法):
Dubbo 不会为没有标注 Adaptive 注解的方法生成代理逻辑,对于该种类型的方法,仅会生成一句抛出异常的代码。

for (Method method : methods) {// 省略无关逻辑Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);StringBuilder code = new StringBuilder(512);// 如果方法上无 Adaptive 注解,则生成 throw new UnsupportedOperationException(...) 代码if (adaptiveAnnotation == null) {// 生成的代码格式如下:// throw new UnsupportedOperationException(//     "method " + 方法签名 + of interface + 全限定接口名 + is not adaptive method!”)code.append("throw new UnsupportedOperationException(\"method ").append(method.toString()).append(" of interface ").append(type.getName()).append(" is not adaptive method!\");");} else {// 省略无关逻辑}// 省略无关逻辑
}

 获取 URL 数据:
 要为 Protocol 接口的 refer 和 export 方法生成代理逻辑。
 通过遍历 refer 的参数列表即可获取 URL 数据,export 参数列表中没有 URL 参数,因此需要从 Invoker 参数中获取 URL 数据。获取方式是调用 Invoker 中可返回 URL 的 getter 方法,如果 Invoker 中无相关 getter 方法,此时则会抛出异常。
 生成后如下:

 refer:
if (arg1 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;export:
if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();

获取 Adaptive 注解值:
Adaptive 注解值 value 类型为 String[],可填写多个值,默认情况下为空数组。若 value 为非空数组,直接获取数组内容即可。若 value 为空数组,则需进行额外处理。比如 LoadBalance 经过处理后,得到 load.balance。

检测 Invocation 参数:
检测方法列表中是否存在 Invocation 类型的参数,若存在,则为其生成判空代码和其他一些代码。

生成拓展名获取逻辑:
本段逻辑用于根据 SPI 和 Adaptive 注解值生成“获取拓展名逻辑”,同时生成逻辑也受 Invocation 类型参数影响,综合因素导致本段逻辑相对复杂。本段逻辑可以会生成但不限于下面的代码:

String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
//或String extName = url.getMethodParameter(methodName, "loadbalance", "random");
//亦或是String extName = url.getParameter("client", url.getParameter("transporter", "netty"));

生成拓展加载与目标方法调用逻辑:
本段代码逻辑用于根据拓展名加载拓展实例,并调用拓展实例的目标方法。
以 Protocol 接口举例说明,上面代码生成的内容如下:

com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);

生成完整的方法:
以 Protocol 的 refer 方法为例,上面代码生成的内容如下:

public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) {// 方法体
}

dubbo源码解析(一)相关推荐

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

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

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

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

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

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

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

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

  5. dubbo源码解析(二)

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

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

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

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

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

  8. dubbo源码解析-逻辑层设计之服务降级

    Dubbo源码解析系列文章均来自肥朝简书 前言 在dubbo服务暴露系列完结之后,按计划来说是应该要开启dubbo服务引用的讲解.但是现在到了年尾,一些朋友也和我谈起了明年跳槽的事.跳槽这件事,无非也 ...

  9. dubbo源码解析之框架粗谈

    dubbo框架设计 一.dubbo框架整体设计 二.各层说明 三.dubbo工程模块分包 四.依赖关系 五.调用链 文章系列 [一.dubbo源码解析之框架粗谈] [二.dubbo源码解析之dubbo ...

  10. Dubbo源码解析 —— Router

    作者:肥朝 原文地址:http://www.jianshu.com/p/278e782eef85 友情提示:欢迎关注公众号[芋道源码].????关注后,拉你进[源码圈]微信群和[肥朝]搞基嗨皮. 友情 ...

最新文章

  1. Android预安装可卸载程序
  2. 一文览尽LiDAR点云目标检测方法
  3. 00.fabric的swarm集群布署:fabric相关的centos软件安装
  4. RCNN 目标识别基本原理
  5. vue-cli 各文件夹的用途
  6. jquery ajax设置头部,jQuery Ajax 设置请求头
  7. Qt5中用QLCDNumber显示时间
  8. docker容器mysql头文件_在Docker容器中使用MySQL数据库
  9. CentOS7+CDH5.14.0安装全流程记录,图文详解全程实测-8CDH5安装和集群配置
  10. 自己java_一些自己用的java类
  11. 《统计学基本概念和方法》读书笔记+读后感(1)
  12. PHPnow中ZendDebugger与ZendOptimizer 共存
  13. PHP视频网站源码 带APP源代码 支持FFMPEG
  14. 多线程编程 -wait(),notify()/notityAll()方法
  15. matlab中if语句的条件,matlabif条件语句
  16. linux用for循环写九九乘法表,写一个方法,用一个for循环打印九九乘法表
  17. [视频]K8软件破解脱壳入门教程
  18. 一封来自 1985 年程序员的辞职信
  19. 那些好玩的生成器网站(二)
  20. edp和edt哪个好_香水edt和edp的区别

热门文章

  1. 前端学习(3038):vue+element今日头条管理-使用请求拦截器
  2. [html] 举例说明Shadow DOM的应用场景有哪些?
  3. [html] 你对标签语义化的理解是什么?
  4. 工作128:element上传组件时候的钩子--event里面有数据参数
  5. 前端学习(2562):v-loading
  6. 前端学习(1946)vue之电商管理系统电商系统之初步使用vue-table-with-tree
  7. “睡服”面试官系列第五篇之proxy(建议收藏学习)
  8. 前端学习(1330):数据库相关概念
  9. 前端学习(731):函数的使用
  10. 前端学习(220):伪元素选择器