Gaea源码阅读(二):客户端流程

转载地址:http://blog.csdn.net/m_vptr/article/details/9147279

以GaeaClientTest为入口

[java]  view plain  copy
  1. GaeaInit.init("conf/gaea.config");  
  2. /** 
  3.  * 调用URL 格式:tcp://服务名//接口实现类  
  4.  * 备注:  
  5.  * 服务名:需要与gaea.config中的服务名一一对应 
  6.  * 接口实现类:具体调用接口的接口实现类 
  7.  */  
  8.   
  9. final String url = "tcp://demo/NewsService";  
  10. INewsService newsService = ProxyFactory.create(INewsService.class, url);  
  11. List<News> list = newsService.getNewsByCateID();  
  12. for (News news : list) {  
  13.     System.out.println("ID is " + news.getNewsID() + " title is "  
  14.             + news.getTitle());  
  15. }  

如注释所言,客户端通过Restfull格式url"tcp://serviceName/lookup "访问服务。

 

关键的一句:INewsService newsService = ProxyFactory. create (INewsService. class ,url); ,这句话创建了一个实现了INewsService接口的代理,返回的这个代理对象将作为getNewsByCateID的调用句柄。

让我们看看代理的内部如何实现的,跟踪ProxyFactory.create

[java]  view plain  copy
  1. InvocationHandler handler = new ProxyStandard(type,serviceName, lookup);  
  2.  return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),  
  3.          newClass[]{type},  
  4.         handler);  
  5.   
  6. //代理的作用就是将所有调用转交到Handler  

 

InvocationHandler接口实现类ProxyStandard

[java]  view plain  copy
  1. public ProxyStandard(Class<?> interfaceClass, String serviceName, String lookup){  
  2.     this.interfaceClass =interfaceClass;  
  3.     this.methodCaller = newMethodCaller(serviceName, lookup);  

InvocationHandler主要由methodCaller完成功能,在invoke()中交给methodCaller

        Object obj= methodCaller.doMethodCall(args, method);


MethodCaller机制 //doMethodCall

[java]  view plain  copy
  1.  //准备参数  
  2. Type[]typeAry = methodInfo.getGenericParameterTypes();  
  3. Class<?>[] clsAry = methodInfo.getParameterTypes();  
  4. if (args== null) {  
  5.     args = newObject[0];  
  6. }  
  7.   
  8. Parameter[]paras = new Parameter[args.length];  
  9. List<Integer> outParas = newArrayList<Integer>();  
  10.   
  11. if(typeAry != null) {  
  12.     for (int i = 0;i < typeAry.length; i++) {  
  13.         if(args[i] instanceof Out) {  
  14.            paras[i] = newParameter(args[i], clsAry[i], typeAry[i], ParaType.Out);  
  15.             outParas.add(i);  
  16.         } else {  
  17.            paras[i] = newParameter(args[i], clsAry[i], typeAry[i], ParaType.In);  
  18.         }  
  19.     }  
  20. }  
  21.   
  22. //规范化方法名  
  23. StringmethodName = methodInfo.getName();  
  24. OperationContract ann =methodInfo.getAnnotation(OperationContract.class);  
  25. if (ann !=null) {  
  26.     if(!ann.methodName().equals(AnnotationUtil.DEFAULT_VALUE)) {  
  27.        methodName = "$" + ann.methodName();  
  28.     }  
  29. }  
  30.   
  31. ParameterreturnPara = new Parameter(null,methodInfo.getReturnType(), methodInfo.getGenericReturnType());  
  32.   
  33. //调用方法  
  34. ServiceProxy proxy = ServiceProxy.getProxy(serviceName);  
  35.   
  36. InvokeResultresult = proxy.invoke(returnPara, lookup,methodName, paras);  
  37.   
  38. //设置返回值  
  39. if (result!= null && result.getOutPara() != null) {  
  40.     for (int i = 0;i < outParas.size() && i < result.getOutPara().length; i++) {  
  41.        Object op = args[outParas.get(i)];  
  42.         if(op instanceof Out){  
  43.            ((Out)op).setOutPara(result.getOutPara()[i]);  
  44.         }  
  45.     }  
  46. }  
  47. returnresult.getResult();  

这里出现了OperationContract注解,这是在方法上面注解的。注解有一个methodName属性。

 

关键点是ServiceProxy的getProxy和invoke方法。


ServiceProxy.getProxy:构造ServiceProxy

[java]  view plain  copy
  1. config =ServiceConfig.GetConfig(serviceName);  
  2. dispatcher = newDispatcher(config);  
  3.   
  4. requestTime = config.getSocketPool().getReconnectTime();  
  5.      intserverCount = 1;  
  6.      if(dispatcher.GetAllServer()!= null && dispatcher.GetAllServer().size()> 0){  
  7.                serverCount = dispatcher.GetAllServer().size();  
  8.      }  
  9.       
  10.      ioreconnect =serverCount - 1;  
  11.   
  12.  //     count = max {ioreconnect,requestTime}  
  13.      count = requestTime;  
  14.       
  15.      if(ioreconnect > requestTime){  
  16.                count = ioreconnect;  
  17.      }  

                   首先读取配置文件中属性为//Service[@name= serviceName]的节点

 

                   创建实现负载均衡的dispatcher,在这里创建了Server

[java]  view plain  copy
  1. for(ServerProfile ser : config.getServers()) {  
  2.     if(ser.getWeithtRate() > 0) {  
  3.        Server s = newServer(ser);  
  4.         if(s.getState() != ServerState.Disable) {  
  5.            ScoketPool sp = newScoketPool(s, config);  
  6.            s.setScoketpool(sp);  
  7.            ServerPool.add(s);  
  8.         }  
  9.     }  
  10. }  


ServiceProxy.Invoke方法

[java]  view plain  copy
  1. //构造RequestProtocol  
  2. RequestProtocol requestProtocol = newRequestProtocol(typeName, methodName, listPara);  
  3. ProtocolsendP = new Protocol(createSessionId(),  
  4.                    (byte) config.getServiceid(),  
  5.                    SDPType.Request,  
  6.                    CompressType.UnCompress,  
  7.                    config.getProtocol().getSerializerType(),  
  8.                    PlatformType.Java,  
  9.                    requestProtocol);  
  10.   
  11. ProtocolreceiveP = null;  
  12. Serverserver = null;  
  13.   
  14. for(int i = 0;i <= count; i++){  
  15.          server = dispatcher.GetServer();  
  16.     if (server== null) {  
  17.         logger.error("cannotget server");  
  18.         throw newException("cannot get server");  
  19.     }  
  20.     try{  
  21.              //本地存根调用  
  22.              receiveP = server.request(sendP);  
  23.              break;  
  24.     } catch(IOExceptionio){  
  25.               
  26.     } catch(RebootExceptionrb){  
  27.              this.createReboot(server);  
  28.     }catch(TimeoutExceptionte){  
  29.               
  30.     } catch(Throwable ex){  
  31.               
  32.     }  
  33. }  
  34.   
  35. if(receiveP== null){  
  36.          throw newException("userdatatype error!");  
  37. }  
  38.   
  39. if(receiveP.getSDPType() == SDPType.Response) {  
  40.     ResponseProtocol rp = (ResponseProtocol)receiveP.getSdpEntity();  
  41.     logger.debug("invoketime:" + (System.currentTimeMillis() - watcher) + "ms");  
  42.     return new InvokeResult(rp.getResult(),rp.getOutpara());  
  43. else if(receiveP.getSDPType()== SDPType.Reset){  
  44.     logger.info(server.getName()+"server is reboot,system will change normal server!");  
  45.     this.createReboot(server);  
  46.     returninvoke(returnType, typeName, methodName, paras);  
  47. }else if(receiveP.getSDPType() == SDPType.Exception) {  
  48.     ExceptionProtocol ep = (ExceptionProtocol)receiveP.getSdpEntity();  
  49.     throwThrowErrorHelper.throwServiceError(ep.getErrorCode(), ep.getErrorMsg());  
  50. else {  
  51.     throw newException("userdatatype error!");  
  52. }  

Server.request()过程

[java]  view plain  copy
  1. //每个CSocket有个WaitWindows注册了SessionId到WindowData的表  
  2.   
  3. increaseCU();  
  4.  CSocketsocket = null;  
  5.  try {  
  6.      try {//发送消息  
  7.         socket = this.scoketpool.getSocket();  
  8.         byte[] data= p.toBytes(socket.isRights(),socket.getDESKey());  
  9.         socket.registerRec(p.getSessionID());  
  10.         socket.send(data);   
  11.      } catch(Throwable ex) {  
  12.          logger.error("Serverget socket Exception", ex);  
  13.          throw ex;  
  14.      }finally {  
  15.               if(socket!= null){  
  16.                         socket.dispose();  
  17.               }  
  18.      }  
  19.   
  20.      //接收应答  
  21.      byte[]buffer = socket.receive(p.getSessionID(), currUserCount);  
  22.      Protocol result = Protocol.fromBytes(buffer,socket.isRights(),socket.getDESKey());  
  23.      if (this.state ==ServerState.Testing) {  
  24.         relive();  
  25.      }  
  26.      return result;  
  27.  } catch(IOException ex) {  
  28.       
  29.  } catch(Throwable ex) {  
  30.   
  31.  } finally {  
  32.      
  33.  }  

 

Receive接收应答时,通过sessionId对应的AutoResetEvent等待

[java]  view plain  copy
  1. //CSocket.receive  
  2. AutoResetEvent event = wd.getEvent();  
  3. int timeout= getReadTimeout(socketConfig.getReceiveTimeout(), queueLen);  
  4. if(!event.waitOne(timeout)) {  
  5.     throw newTimeoutException("Receive data timeout or error!timeout:" +timeout + "ms,queue length:" +queueLen);  
  6. }  

返回应答可能为Response、Reset、Exception

Response -> 返回InvokeResult结构体

Reset -> 重启则再调用invoke(returnType,typeName, methodName, paras)

Exception -> 抛出异常


frameHandler从Socket接收数据,并根据协议反解出session id,然后从waitWindows中取出对应的WindowData,然后调用对应的Event的set()通知CSocket.receive 返回


客户端做的工作主要就是这些


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值