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

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

  1. private Response request(Request request, boolean async) throws TransportException {
  2. Channel channel = null;
  3.  
  4. Response response = null;
  5.  
  6. try {
  7. // return channel or throw exception(timeout or connection_fail)
  8. channel = borrowObject();//向连接池拿连接
  9.  
  10. if (channel == null) {
  11. LoggerUtil.error("NettyClient borrowObject null: url=" + url.getUri() + " "
  12. + MotanFrameworkUtil.toString(request));
  13. return null;
  14. }
  15.  
  16. // async request
  17. response = channel.request(request);//调用channel的request
  18. // return channel to pool
  19. returnObject(channel);//归还连接
  20. } catch (Exception e) {
  21. LoggerUtil.error(
  22. "NettyClient request Error: url=" + url.getUri() + " " + MotanFrameworkUtil.toString(request), e);
  23. //TODO 对特定的异常回收channel
  24. invalidateObject(channel);//销毁坏的连接
  25.  
  26. if (e instanceof MotanAbstractException) {
  27. throw (MotanAbstractException) e;
  28. } else {
  29. throw new MotanServiceException("NettyClient request Error: url=" + url.getUri() + " "
  30. + MotanFrameworkUtil.toString(request), e);
  31. }
  32. }
  33.  
  34. // aysnc or sync result
  35. response = asyncResponse(response, async);//处理response
  36.  
  37. return response;
  38. }

2.nettychannel的request操作

  1. public Response request(Request request) throws TransportException {
  2. int timeout = nettyClient.getUrl().getMethodParameter(request.getMethodName(), request.getParamtersDesc(),
  3. URLParamType.requestTimeout.getName(), URLParamType.requestTimeout.getIntValue());
  4. if (timeout <= 0) {
  5. throw new MotanFrameworkException("NettyClient init Error: timeout(" + timeout + ") <= 0 is forbid.",
  6. MotanErrorMsgConstant.FRAMEWORK_INIT_ERROR);
  7. }
  8. NettyResponseFuture response = new NettyResponseFuture(request, timeout, this.nettyClient);//创建异步response对象
  9. this.nettyClient.registerCallback(request.getRequestId(), response);//将此response存入到map,处理完后,会移出
  10. ChannelFuture writeFuture = this.channel.write(request);//向服务端传递request对象,写之前会进行序列化的操作
  11.  
  12. boolean result = writeFuture.awaitUninterruptibly(timeout, TimeUnit.MILLISECONDS);//标识是否成功
  13.  
  14. if (result && writeFuture.isSuccess()) {
  15. response.addListener(new FutureListener() {//增加response的监听器
  16. @Override
  17. public void operationComplete(Future future) throws Exception {
  18. if (future.isSuccess() || (future.isDone() && ExceptionUtil.isBizException(future.getException()))) {
  19. // 成功的调用
  20. nettyClient.resetErrorCount();//成功
  21. } else {
  22. // 失败的调用
  23. nettyClient.incrErrorCount();//对失败次数+1,如果同一个client连续失败达到所有的连接次数时,标识此client不可用,由心跳管理器负责恢复此client的可用状态
  24. }
  25. }
  26. });
  27. return response;//返回此response,此response为异步的response,由业务线程接手后续接收的过程
  28. }
  29.  
  30. writeFuture.cancel();
  31. response = this.nettyClient.removeCallback(request.getRequestId());//在map中移出此response
  32.  
  33. if (response != null) {
  34. response.cancel();
  35. }
  36.  
  37. // 失败的调用
  38. nettyClient.incrErrorCount();
  39.  
  40. if (writeFuture.getCause() != null) {
  41. throw new MotanServiceException("NettyChannel send request to server Error: url="
  42. + nettyClient.getUrl().getUri() + " local=" + localAddress + " "
  43. + MotanFrameworkUtil.toString(request), writeFuture.getCause());
  44. } else {
  45. throw new MotanServiceException("NettyChannel send request to server Timeout: url="
  46. + nettyClient.getUrl().getUri() + " local=" + localAddress + " "
  47. + MotanFrameworkUtil.toString(request));
  48. }
  49. }

3.异步的response NettyResponseFuture

  1. public Object getValue() {
  2. synchronized (lock) {
  3. if (!isDoing()) {
  4. return getValueOrThrowable();//返回成功值或失败
  5. }
  6.  
  7. if (timeout <= 0) {
  8. try {
  9. lock.wait();//未接收完毕则一直等待
  10. } catch (Exception e) {
  11. cancel(new MotanServiceException("NettyResponseFuture getValue InterruptedException : "
  12. + MotanFrameworkUtil.toString(request) + " cost="
  13. + (System.currentTimeMillis() - createTime), e));
  14. }
  15.  
  16. // don't need to notifylisteners, because onSuccess or
  17. // onFailure or cancel method already call notifylisteners
  18. return getValueOrThrowable();
  19. } else {
  20. long waitTime = timeout - (System.currentTimeMillis() - createTime);//等待的时间
  21.  
  22. if (waitTime > 0) {
  23. for (;;) {
  24. try {
  25. lock.wait(waitTime);//要么被通知,要么超时
  26. } catch (InterruptedException e) {
  27. }
  28.  
  29. if (!isDoing()) {
  30. break;
  31. } else {
  32. waitTime = timeout - (System.currentTimeMillis() - createTime);
  33. if (waitTime <= 0) {
  34. break;
  35. }
  36. }
  37. }
  38. }
  39.  
  40. if (isDoing()) {
  41. timeoutSoCancel();
  42. }
  43. }
  44. return getValueOrThrowable();
  45. }
  46. }

本章知识点:

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. UniqueID和ClientID的来源

    在<漫话ID>一文中,作者提出了一个问题:为什么在ItemCreated事件中访问ClientID会导致MyButton无法响应事件,事实上 MyButton无法响应事件是因为他在客户端的 ...

  2. cmd连接mysql连接:mysql-h主机地址-u用户名-p用户密码(注:u与root可以不用加)

    MySQL导入导出命令1.导出整个数据库 mysqldump -u 用户名 -p 数据库名 > 导出的文件名 mysqldump -u wcnc -p smgp_apps_wcnc >wc ...

  3. 微信 token 验证

    package org.sxl.weixin; import java.security.MessageDigest; import java.security.NoSuchAlgorithmExce ...

  4. [个人原创]关于java中对象排序的一些探讨(二)

    2.  使用Collections.sort()方法 Collections类中提供了诸多静态方法,诸如addAll(),max()等等.当自己相对Collection接口下的类处理的时候,可以看看这 ...

  5. JavaScript--函数-01

    函数的本质: function:创建一个函数对象的意思 什么是函数对象: 专门封装一个函数定义的存储空间 其实,函数是一个引用类型的对象 函数名,其实是一个引用函数对象的变量 函数只有在调用时才执行, ...

  6. Hibernate 性能优化之查询缓存

    查询缓存是建立在二级缓存基础之上的,所以与二级缓存特性相似,是共享的,适合修改不是很频繁的数据 查询缓存不是默认开启的,需要设置      1.在cfg文件中配置 <property name= ...

  7. (兼容IE6)又一个提示框思密达,腾讯UED 201401242352

    找乐子 仿QQ空间的,先来看下,别嫌代码垃圾,业余菜鸟一个,用到的话就当个乐子就行了 注意: 因为有同学说需要IE6便做了一下. 已经处理了IE6,可测试. 腾讯的东西,感觉还好吧:) 使用方法老简单 ...

  8. css position 相对定位

    <html> <head> <style type="text/css"> h2.pos_left { position:relative; l ...

  9. PostBack与IsPostBack区别

    这涉及到aspx的页面回传机制的基础知识 postback是回传 即页面在首次加载后向服务器提交数据,然后服务器把处理好的数据传递到客户端并显示出来,就叫postback, ispostback只是一 ...

  10. 转:VS2010与SVN

    在VS2010中使用SVN,必须先安装SVN的客户端,再安装VisualSVN(SVN的插件).必须保证两者的版本不冲突,我现在安装的是TortoiseSVN-1.7.10.23359-win32-s ...