motan源码分析八:涉及到底层的客户端调用
之前我们分析了客户端调用服务端的源码,但是没有涉及到通讯层和序列化层,本文将之前讲过的内容做一次串联。
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源码分析八:涉及到底层的客户端调用的更多相关文章
- motan源码分析一:服务发布及注册
motan是新浪微博开源的服务治理框架,具体介绍请看:http://tech.sina.com.cn/i/2016-05-10/doc-ifxryhhh1869879.shtml. 本系列的文章将分析 ...
- motan源码分析六:客户端与服务器的通信层分析
本章将分析motan的序列化和底层通信相关部分的代码. 1.在上一章中,有一个getrefers的操作,来获取所有服务器的引用,每个服务器的引用都是由DefaultRpcReferer来创建的 pub ...
- ABP源码分析八:Logger集成
ABP使用Castle日志记录工具,并且可以使用不同的日志类库,比如:Log4Net, NLog, Serilog... 等等.对于所有的日志类库,Castle提供了一个通用的接口来实现,我们可以很方 ...
- Seata源码分析(一). AT模式底层实现
目录 GlobalTransactionScanner 继承AbstractAutoProxyCreator 实现InitializingBean接口 写在最后 以AT为例,我们使用Seata时只需要 ...
- Vue.js 源码分析(八) 基础篇 依赖注入 provide/inject组合详解
先来看看官网的介绍: 简单的说,当组件的引入层次过多,我们的子孙组件想要获取祖先组件的资源,那么怎么办呢,总不能一直取父级往上吧,而且这样代码结构容易混乱.这个就是这对选项要干的事情 provide和 ...
- motan源码分析十一:部分特性
本章将描述motan部分的特性并对源码进行分析. 1.requestid的维护,使用了当前时间左移20位,再和一个自增变量组合 public class RequestIdGenerator { ); ...
- motan源码分析十:流量切换
motan提供了流量切换的功能,可以实现把一个group的流量切换到另一个group(一个或多个服务都可以).大家可以使用tomcat部署motan的管理工具,并设置几个组,例如可以参考demo代码: ...
- motan源码分析五:cluster相关
上一章我们分析了客户端调用服务端相关的源码,但是到了cluster里面的部分我们就没有分析了,本章将深入分析cluster和它的相关支持类. 1.clustersupport的创建过程,上一章的Ref ...
- motan源码分析二:使用spi机制进行类加载
在motan的源码中使用了很多的spi机制进行对象的创建,下面我们来具体分析一下它的实现方法. 1.在实际的jar包的\META-INF\services目录中引入相关的文件,例如下图中,我解压了co ...
随机推荐
- UniqueID和ClientID的来源
在<漫话ID>一文中,作者提出了一个问题:为什么在ItemCreated事件中访问ClientID会导致MyButton无法响应事件,事实上 MyButton无法响应事件是因为他在客户端的 ...
- cmd连接mysql连接:mysql-h主机地址-u用户名-p用户密码(注:u与root可以不用加)
MySQL导入导出命令1.导出整个数据库 mysqldump -u 用户名 -p 数据库名 > 导出的文件名 mysqldump -u wcnc -p smgp_apps_wcnc >wc ...
- 微信 token 验证
package org.sxl.weixin; import java.security.MessageDigest; import java.security.NoSuchAlgorithmExce ...
- [个人原创]关于java中对象排序的一些探讨(二)
2. 使用Collections.sort()方法 Collections类中提供了诸多静态方法,诸如addAll(),max()等等.当自己相对Collection接口下的类处理的时候,可以看看这 ...
- JavaScript--函数-01
函数的本质: function:创建一个函数对象的意思 什么是函数对象: 专门封装一个函数定义的存储空间 其实,函数是一个引用类型的对象 函数名,其实是一个引用函数对象的变量 函数只有在调用时才执行, ...
- Hibernate 性能优化之查询缓存
查询缓存是建立在二级缓存基础之上的,所以与二级缓存特性相似,是共享的,适合修改不是很频繁的数据 查询缓存不是默认开启的,需要设置 1.在cfg文件中配置 <property name= ...
- (兼容IE6)又一个提示框思密达,腾讯UED 201401242352
找乐子 仿QQ空间的,先来看下,别嫌代码垃圾,业余菜鸟一个,用到的话就当个乐子就行了 注意: 因为有同学说需要IE6便做了一下. 已经处理了IE6,可测试. 腾讯的东西,感觉还好吧:) 使用方法老简单 ...
- css position 相对定位
<html> <head> <style type="text/css"> h2.pos_left { position:relative; l ...
- PostBack与IsPostBack区别
这涉及到aspx的页面回传机制的基础知识 postback是回传 即页面在首次加载后向服务器提交数据,然后服务器把处理好的数据传递到客户端并显示出来,就叫postback, ispostback只是一 ...
- 转:VS2010与SVN
在VS2010中使用SVN,必须先安装SVN的客户端,再安装VisualSVN(SVN的插件).必须保证两者的版本不冲突,我现在安装的是TortoiseSVN-1.7.10.23359-win32-s ...