*:first-child {
margin-top: 0 !important;
}

body>*:last-child {
margin-bottom: 0 !important;
}

/* BLOCKS
=============================================================================*/

p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}

/* HEADERS
=============================================================================*/

h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}

h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
font-size: inherit;
}

h1 {
font-size: 28px;
color: #000;
}

h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color: #000;
}

h3 {
font-size: 18px;
}

h4 {
font-size: 16px;
}

h5 {
font-size: 14px;
}

h6 {
color: #777;
font-size: 14px;
}

body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}

h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}

/* LINKS
=============================================================================*/

a {
color: #4183C4;
text-decoration: none;
}

a:hover {
text-decoration: underline;
}

/* LISTS
=============================================================================*/

ul, ol {
padding-left: 30px;
}

ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}

ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}

dl {
padding: 0;
}

dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}

dl dt:first-child {
padding: 0;
}

dl dt>:first-child {
margin-top: 0px;
}

dl dt>:last-child {
margin-bottom: 0px;
}

dl dd {
margin: 0 0 15px;
padding: 0 15px;
}

dl dd>:first-child {
margin-top: 0px;
}

dl dd>:last-child {
margin-bottom: 0px;
}

/* CODE
=============================================================================*/

pre, code, tt {
font-size: 12px;
font-family: Consolas, "Liberation Mono", Courier, monospace;
}

code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}

pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}

pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}

pre code, pre tt {
background-color: transparent;
border: none;
}

kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #DDDDDD;
background-image: linear-gradient(#F1F1F1, #DDDDDD);
background-repeat: repeat-x;
border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
line-height: 10px;
padding: 1px 4px;
}

/* QUOTES
=============================================================================*/

blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}

blockquote>:first-child {
margin-top: 0px;
}

blockquote>:last-child {
margin-bottom: 0px;
}

/* HORIZONTAL RULES
=============================================================================*/

hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}

/* IMAGES
=============================================================================*/

img {
max-width: 100%
}
-->

阅读源码的作用

  • 提取设计思路,增强设计能力
  • 理解运行机制,便于快速解决问题以及功能扩展

常见有关dubbo的问题

  • dubbo的负载均衡是在哪个组件中处理的?
  • dubbo默认的负载均衡算法是什么?
  • 如果注册中心挂掉了客户端是否能够继续调用dubbo?
  • 一个请求从调用端到服务端的处理流程是什么?

如果你有仔细的研读dubbo的开发文档,大部分问题都是有答案的,为了进一步了解细节就有必要对源码进行了解。

源码分析计划

使用dubbo时间也有快两年时间了,虽然官方的dubbo已经停止维护,但也有其它组织在继续维护:

  • dubbox,是当当维护的
  • 还有一个是基于jdk8版本的

一直想看看dubbo的源码,但没有集中时间来学习。最近利用了一部分时间所以将我的学习经历记录下来,主要从这几步来展开,只想搞清楚大体流程,对于其它一些细节我目前并不太关注,比如序列化,线程池,集群,上下文,异步回调等。

  • RPC框架的简易结构
  • dubbo客户端的初始化
  • dubbo服务端的初始化
  • dubbo客户端处理请求流程
  • dubbo服务端处理请求流程

RPC简易结构

为了更加清楚的看清楚RPC的结构,主要看以下几个核心组件即可,其余的组件都是围绕它们来完成。

  • 序列化组件,因为需要远程调用,所以需要将参数以二进制流的形式进行编码操作
  • 发送组件,将二进制流发送到服务端
  • 接收组件,接收调用端发送的二进制流以及接收服务端返回的二进制流

dubbo客户端的初始化

从这开始来实际看下dubbo的工作流程。RPC的亮点在于将远程调用的细节隐藏起来,使得调用远程服务像调用本地服务一样简单,而实现上面的功能就是代理。

代理的作用

RPC框架隐藏了具体的实现细节,客户端通过调用特定的代理类来访问远程服务,下面是一个dubbo远程接口的本地引用。

<dubbo:reference check="false"
timeout="200000"
interface="com.product.core.service.ProductFacadeService"
id="productFacadeService">

ReferenceConfig这个类的createProxy是用来生成远程服务的本地代理,最终交给RegistryProtocol来处理。两处核心代码:

  • refprotocol.refer,与注册中心相关
  • proxyFactory.getProxy,获取代理
private T createProxy(Map<String, String> map) {
//... if (isJvmRefer) {
//...
} else {
//... if (urls.size() == 1) {
invoker = refprotocol.refer(interfaceClass, urls.get(0));
} else {
//...
}
} //...
// 创建服务代理
return (T) proxyFactory.getProxy(invoker);
}

本地直连不走上面的逻辑

注册中心

由于服务注册到ZK,所以调用端要想调用服务端需要取得服务的注册信息然后建立网络连接。

 private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
RegistryDirectory directory = new RegistryDirectory(type, url);
directory.setRegistry(registry);
directory.setProtocol(this.protocol);
URL subscribeUrl = new URL("consumer", NetUtils.getLocalHost(), 0, type.getName(), directory.getUrl().getParameters());
if(!"*".equals(url.getServiceInterface()) && url.getParameter("register", true)) {
registry.register(subscribeUrl.addParameters(new String[]{"category", "consumers", "check", String.valueOf(false)}));
} directory.subscribe(subscribeUrl.addParameter("category", "providers,configurators,routers"));
return cluster.join(directory);
}

上面代码两个作用:

  • 将调用端以消费者的身份进行信息注册
  • 监听注册中心的信息变化以刷新本地对服务注册信息的缓存

由于有服务端信息的本地缓存,所以当注册中心挂掉后调用端依然能够工作,也就是说调用端不是强依赖服务端。

连接服务端

上面的subscribe方法会监听注册中心的变化,当获取到服务注册信息后会触发ProtocolListenerWrapper的refer方法:

 public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
return (Invoker)("registry".equals(url.getProtocol())?this.protocol.refer(type, url): new ListenerInvokerWrapper(this.protocol.refer(type, url), Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(InvokerListener.class).getActivateExtension(url, "invoker.listener"))));
}

上面的this.protocol就是DubboProtocol这个类,此类的其它方法暂时先不关注,只看refer。

public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
this.optimizeSerialization(url);
DubboInvoker invoker = new DubboInvoker(serviceType, url, this.getClients(url), this.invokers);
this.invokers.add(invoker);
return invoker;
}

getClients负责创建链接以供调用端调用服务端方法时使用。

 private ExchangeClient[] getClients(URL url) {
boolean service_share_connect = false;
int connections = url.getParameter("connections", 0);
if(connections == 0) {
service_share_connect = true;
connections = 1;
} ExchangeClient[] clients = new ExchangeClient[connections]; for(int i = 0; i < clients.length; ++i) {
if(service_share_connect) {
clients[i] = this.getSharedClient(url);
} else {
clients[i] = this.initClient(url);
}
} return clients;
}

创建代理

回到ReferenceConfig的createProxy方法,最后会调用proxyFactory.getProxy,此方法最终会调用JavassistProxyFactory的getProxy,一看javassist就知道是利用字节码来实现代理功能。

 public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}

Proxy,这个类的实现比较复杂就不详细分析了,得到了proxy将它放在容器中,当调用端调用服务端代码时就有了实例跟本地的实例没什么区别。

 public static Proxy getProxy(Class... ics) {
return getProxy(ClassHelper.getCallerClassLoader(Proxy.class), ics);
}

初始化时序图

下图中的callback是指监听注册中心后回调产生的调用关系。

总结

本文提到了分析框架源码的作用,RPC简单结构,并制定了一个源码分析的计划。最后以调用端在启动时执行的dubbo流程为起点开始了dubbo流程的源码分析。

dubbo源码分析(一)的更多相关文章

  1. dubbo源码分析6-telnet方式的管理实现

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  2. dubbo源码分析1-reference bean创建

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  3. dubbo源码分析2-reference bean发起服务方法调用

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  4. dubbo源码分析3-service bean的创建与发布

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  5. dubbo源码分析4-基于netty的dubbo协议的server

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  6. dubbo源码分析5-dubbo的扩展点机制

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  7. dubbo源码分析一:整体分析

    本文作为dubbo源码分析的第一章,先从总体上来分析一下dubbo的代码架构.功能及优缺点,注意,本文只分析说明开源版本提供的代码及功能. 1.dubbo的代码架构:  spring适配层:常规的sp ...

  8. Dubbo 源码分析 - 服务调用过程

    注: 本系列文章已捐赠给 Dubbo 社区,你也可以在 Dubbo 官方文档中阅读本系列文章. 1. 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与引入.以及集群容错方面的代码.经过 ...

  9. Dubbo 源码分析 - 集群容错之 LoadBalance

    1.简介 LoadBalance 中文意思为负载均衡,它的职责是将网络请求,或者其他形式的负载"均摊"到不同的机器上.避免集群中部分服务器压力过大,而另一些服务器比较空闲的情况.通 ...

  10. Dubbo 源码分析 - 集群容错之 Cluster

    1.简介 为了避免单点故障,现在的应用至少会部署在两台服务器上.对于一些负载比较高的服务,会部署更多台服务器.这样,同一环境下的服务提供者数量会大于1.对于服务消费者来说,同一环境下出现了多个服务提供 ...

随机推荐

  1. poi jar包介绍

    来自官网: Component Application type Maven artifactId Notes POIFS OLE2 Filesystem poi Required to work w ...

  2. IOS 利用图片设置背景

    UIImageView* imageView = [[UIImageView alloc] initWithFrame:self.view.bounds]; imageView.image = [UI ...

  3. UIscrollView 代理

    // // UIDemoViewController.m // 06-1UIScrollDemo // // Created by k on 14-9-4. // Copyright (c) 2014 ...

  4. Intellij Idea 配置并发布tomcat项目

    作为一个菜鸟,我还是很想提高自己.但是既然说了是菜鸟,当然很容易半路折翅 从刚听说intellij idea(以下简称 idea)到现在,应该有超过一个月了吧,我的电脑装了三四次系统了(刚换了一台电脑 ...

  5. swift 中使用OC第三方库(以AFNetworking为例)

    首先呢  把你需要的第三方库导入到你的项目中来  具体怎么导入 这不是这篇的重点  看上一篇 废话不多  直接上 (1)在项目中直接建一个 oc 的控制器  然后xcode会提醒你  要不要建造桥接文 ...

  6. JavaScript 模拟策略模式

    /** * 模拟一个接口,其方法会抛出异常: */ function FlyInter () {} FlyInter.prototype.fly = function() { throw '实现这个接 ...

  7. java调用oracle存储过程,返回结果集

    package com.srie.db.pro; import java.sql.CallableStatement; import java.sql.Connection; import java. ...

  8. ER图,以及转化成关系模式

    1.找出条件中的实体(矩形),属性(椭圆),关系(菱形)关系分为1:1,1:N,M:N,列出ER图 2. -1:1联系的转换方法 -两个实体分别转化为一个关系模式,属性即是本来的属性 -关系可以与任意 ...

  9. Redis系列一(Redis环境的搭建)

    最近工作中需要Redis缓存,由于也是第一次弄,在网上找了很多资料,在此记录一下. 安装Redis 我使用的系统是CentOS 6.6,安装步骤如下: 1.下载源码,解压后编译源码.(如果没有 wge ...

  10. cygwin 运行窗口程序

    首先, 默认安装的cygwin是不能运行窗口程序的 比如,一段python窗口程序: import * from tkinter Tk() mainloop() 如果使用命令行: python3 py ...