之前我们分析了客户端调用服务端的源码,但是没有涉及到通讯层和序列化层,本文将之前讲过的内容做一次串联。

1.上层通过动态代理调用refer的call,每个refer又对应一个nettyclient,下面来看一下nettyclient的调用服务端操作

	private Response request(Request request, boolean async) throws TransportException {
Channel channel = null; Response response = null; try {
// return channel or throw exception(timeout or connection_fail)
channel = borrowObject();//向连接池拿连接 if (channel == null) {
LoggerUtil.error("NettyClient borrowObject null: url=" + url.getUri() + " "
+ MotanFrameworkUtil.toString(request));
return null;
} // async request
response = channel.request(request);//调用channel的request
// return channel to pool
returnObject(channel);//归还连接
} catch (Exception e) {
LoggerUtil.error(
"NettyClient request Error: url=" + url.getUri() + " " + MotanFrameworkUtil.toString(request), e);
//TODO 对特定的异常回收channel
invalidateObject(channel);//销毁坏的连接 if (e instanceof MotanAbstractException) {
throw (MotanAbstractException) e;
} else {
throw new MotanServiceException("NettyClient request Error: url=" + url.getUri() + " "
+ MotanFrameworkUtil.toString(request), e);
}
} // aysnc or sync result
response = asyncResponse(response, async);//处理response return response;
}

2.nettychannel的request操作

	public Response request(Request request) throws TransportException {
int timeout = nettyClient.getUrl().getMethodParameter(request.getMethodName(), request.getParamtersDesc(),
URLParamType.requestTimeout.getName(), URLParamType.requestTimeout.getIntValue());
if (timeout <= 0) {
throw new MotanFrameworkException("NettyClient init Error: timeout(" + timeout + ") <= 0 is forbid.",
MotanErrorMsgConstant.FRAMEWORK_INIT_ERROR);
}
NettyResponseFuture response = new NettyResponseFuture(request, timeout, this.nettyClient);//创建异步response对象
this.nettyClient.registerCallback(request.getRequestId(), response);//将此response存入到map,处理完后,会移出
ChannelFuture writeFuture = this.channel.write(request);//向服务端传递request对象,写之前会进行序列化的操作 boolean result = writeFuture.awaitUninterruptibly(timeout, TimeUnit.MILLISECONDS);//标识是否成功 if (result && writeFuture.isSuccess()) {
response.addListener(new FutureListener() {//增加response的监听器
@Override
public void operationComplete(Future future) throws Exception {
if (future.isSuccess() || (future.isDone() && ExceptionUtil.isBizException(future.getException()))) {
// 成功的调用
nettyClient.resetErrorCount();//成功
} else {
// 失败的调用
nettyClient.incrErrorCount();//对失败次数+1,如果同一个client连续失败达到所有的连接次数时,标识此client不可用,由心跳管理器负责恢复此client的可用状态
}
}
});
return response;//返回此response,此response为异步的response,由业务线程接手后续接收的过程
} writeFuture.cancel();
response = this.nettyClient.removeCallback(request.getRequestId());//在map中移出此response if (response != null) {
response.cancel();
} // 失败的调用
nettyClient.incrErrorCount(); if (writeFuture.getCause() != null) {
throw new MotanServiceException("NettyChannel send request to server Error: url="
+ nettyClient.getUrl().getUri() + " local=" + localAddress + " "
+ MotanFrameworkUtil.toString(request), writeFuture.getCause());
} else {
throw new MotanServiceException("NettyChannel send request to server Timeout: url="
+ nettyClient.getUrl().getUri() + " local=" + localAddress + " "
+ MotanFrameworkUtil.toString(request));
}
}

3.异步的response NettyResponseFuture

	public Object getValue() {
synchronized (lock) {
if (!isDoing()) {
return getValueOrThrowable();//返回成功值或失败
} if (timeout <= 0) {
try {
lock.wait();//未接收完毕则一直等待
} catch (Exception e) {
cancel(new MotanServiceException("NettyResponseFuture getValue InterruptedException : "
+ MotanFrameworkUtil.toString(request) + " cost="
+ (System.currentTimeMillis() - createTime), e));
} // don't need to notifylisteners, because onSuccess or
// onFailure or cancel method already call notifylisteners
return getValueOrThrowable();
} else {
long waitTime = timeout - (System.currentTimeMillis() - createTime);//等待的时间 if (waitTime > 0) {
for (;;) {
try {
lock.wait(waitTime);//要么被通知,要么超时
} catch (InterruptedException e) {
} if (!isDoing()) {
break;
} else {
waitTime = timeout - (System.currentTimeMillis() - createTime);
if (waitTime <= 0) {
break;
}
}
}
} if (isDoing()) {
timeoutSoCancel();
}
}
return getValueOrThrowable();
}
}

本章知识点:

1.motan通过NettyResponseFuture来实现在框架层面异步处理同一笔业务,提升了框架的性能;

2.对于连续失败的client,进行下线操作。

  

motan源码分析八:涉及到底层的客户端调用的更多相关文章

  1. motan源码分析一:服务发布及注册

    motan是新浪微博开源的服务治理框架,具体介绍请看:http://tech.sina.com.cn/i/2016-05-10/doc-ifxryhhh1869879.shtml. 本系列的文章将分析 ...

  2. motan源码分析六:客户端与服务器的通信层分析

    本章将分析motan的序列化和底层通信相关部分的代码. 1.在上一章中,有一个getrefers的操作,来获取所有服务器的引用,每个服务器的引用都是由DefaultRpcReferer来创建的 pub ...

  3. ABP源码分析八:Logger集成

    ABP使用Castle日志记录工具,并且可以使用不同的日志类库,比如:Log4Net, NLog, Serilog... 等等.对于所有的日志类库,Castle提供了一个通用的接口来实现,我们可以很方 ...

  4. Seata源码分析(一). AT模式底层实现

    目录 GlobalTransactionScanner 继承AbstractAutoProxyCreator 实现InitializingBean接口 写在最后 以AT为例,我们使用Seata时只需要 ...

  5. Vue.js 源码分析(八) 基础篇 依赖注入 provide/inject组合详解

    先来看看官网的介绍: 简单的说,当组件的引入层次过多,我们的子孙组件想要获取祖先组件的资源,那么怎么办呢,总不能一直取父级往上吧,而且这样代码结构容易混乱.这个就是这对选项要干的事情 provide和 ...

  6. motan源码分析十一:部分特性

    本章将描述motan部分的特性并对源码进行分析. 1.requestid的维护,使用了当前时间左移20位,再和一个自增变量组合 public class RequestIdGenerator { ); ...

  7. motan源码分析十:流量切换

    motan提供了流量切换的功能,可以实现把一个group的流量切换到另一个group(一个或多个服务都可以).大家可以使用tomcat部署motan的管理工具,并设置几个组,例如可以参考demo代码: ...

  8. motan源码分析五:cluster相关

    上一章我们分析了客户端调用服务端相关的源码,但是到了cluster里面的部分我们就没有分析了,本章将深入分析cluster和它的相关支持类. 1.clustersupport的创建过程,上一章的Ref ...

  9. motan源码分析二:使用spi机制进行类加载

    在motan的源码中使用了很多的spi机制进行对象的创建,下面我们来具体分析一下它的实现方法. 1.在实际的jar包的\META-INF\services目录中引入相关的文件,例如下图中,我解压了co ...

随机推荐

  1. 经验分享:CSS浮动(float,clear)通俗讲解(转载)

    很早以前就接触过CSS,但对于浮动始终非常迷惑,可能是自身理解能力差,也可能是没能遇到一篇通俗的教程. 前些天小菜终于搞懂了浮动的基本原理,迫不及待的分享给大家. 写在前面的话: 由于CSS内容比较多 ...

  2. Android Studio中关于Project与Module

    在Android Studio中一个Project和Eclipse中的WorkSpace是相似的,而一个Module与Eclipse中的Project是相似的(大致可以这么的认为) 若在Android ...

  3. oracle中使用minus进行数据排除(类似SqlServer except函数)

    minus这个集合操作符号的作用是从一个结果集合中减掉另一个结果集中数据,也就是说从一个结果集中去除两个结果集中的共有部分. 下面是一些例子: 这个例子使用minus从第一个结果集中将两个结果集的公有 ...

  4. html table 知识点

    第一点就是图片在表格中不能对齐边沿的问题,这是和浏览器的渲染模式相关的,在标准模式中是不能对齐的,除非改变CSS某些样式.而在准标准模式和怪异模式中,默认就是对齐的. 这一特性在以前的表格布局时代是大 ...

  5. 四、C#方法和参数

    方法是一种组合一系列语句以执行一个特定操作或计算一个特殊结果的方式. 它能够为构成程序的语句提供更好的结构和组织.   在面向对象的语言中,方法总是和类关联在一起的,我们用类将相关的方法分为一组. 方 ...

  6. sql -实验二

    8. 统计各部门下工资大于2000的雇员的平均工资. select avg(sal)from empwhere sal>2000;

  7. 打包静默安装参数(nsis,msi,InstallShield,InnoSetup)[转]

    有时我们在安装程序的时候,希望是静默安装的,不显示下一步下一步,这编访问来教大家如何来操作,现在常用的制作安装程序的软件有,  Microsoft Windows Installer  , Windo ...

  8. angularjs现学现记之—$apply()和$digest()

    angularjs的双向数据绑定是个重要的特性,它让我们的代码简洁了许多,然而它又是如何知道数据发生了变化并改变页面的呢.最近看了一篇介绍觉得十分有用 首先,在angularjs中是有$watch事件 ...

  9. php中抽象类和接口的特点、区别和选择

    一.特点: 1.抽象类特点 (1) 用 abstract 来修饰一个类,那么这个类就是抽象类:抽象类绝对不能被实例化,即$abc = new 抽象类名();会报错. (2) 用abstract 来修饰 ...

  10. C# windows窗体程序打包安装及卸载

    一.新建安装部署项目