转载地址: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. final String url = "tcp://demo/NewsService";
  9. INewsService newsService = ProxyFactory.create(INewsService.class, url);
  10. List<News> list = newsService.getNewsByCateID();
  11. for (News news : list) {
  12. System.out.println("ID is " + news.getNewsID() + " title is "
  13. + news.getTitle());
  14. }

如注释所言,客户端通过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. //代理的作用就是将所有调用转交到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. Parameter[]paras = new Parameter[args.length];
  8. List<Integer> outParas = newArrayList<Integer>();
  9. if(typeAry != null) {
  10. for (int i = 0;i < typeAry.length; i++) {
  11. if(args[i] instanceof Out) {
  12. paras[i] = newParameter(args[i], clsAry[i], typeAry[i], ParaType.Out);
  13. outParas.add(i);
  14. } else {
  15. paras[i] = newParameter(args[i], clsAry[i], typeAry[i], ParaType.In);
  16. }
  17. }
  18. }
  19. //规范化方法名
  20. StringmethodName = methodInfo.getName();
  21. OperationContract ann =methodInfo.getAnnotation(OperationContract.class);
  22. if (ann !=null) {
  23. if(!ann.methodName().equals(AnnotationUtil.DEFAULT_VALUE)) {
  24. methodName = "$" + ann.methodName();
  25. }
  26. }
  27. ParameterreturnPara = new Parameter(null,methodInfo.getReturnType(), methodInfo.getGenericReturnType());
  28. //调用方法
  29. ServiceProxy proxy = ServiceProxy.getProxy(serviceName);
  30. InvokeResultresult = proxy.invoke(returnPara, lookup,methodName, paras);
  31. //设置返回值
  32. if (result!= null && result.getOutPara() != null) {
  33. for (int i = 0;i < outParas.size() && i < result.getOutPara().length; i++) {
  34. Object op = args[outParas.get(i)];
  35. if(op instanceof Out){
  36. ((Out)op).setOutPara(result.getOutPara()[i]);
  37. }
  38. }
  39. }
  40. returnresult.getResult();

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

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

ServiceProxy.getProxy:构造ServiceProxy

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

首先读取配置文件中属性为//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. ProtocolreceiveP = null;
  11. Serverserver = null;
  12. for(int i = 0;i <= count; i++){
  13. server = dispatcher.GetServer();
  14. if (server== null) {
  15. logger.error("cannotget server");
  16. throw newException("cannot get server");
  17. }
  18. try{
  19. //本地存根调用
  20. receiveP = server.request(sendP);
  21. break;
  22. } catch(IOExceptionio){
  23. } catch(RebootExceptionrb){
  24. this.createReboot(server);
  25. }catch(TimeoutExceptionte){
  26. } catch(Throwable ex){
  27. }
  28. }
  29. if(receiveP== null){
  30. throw newException("userdatatype error!");
  31. }
  32. if(receiveP.getSDPType() == SDPType.Response) {
  33. ResponseProtocol rp = (ResponseProtocol)receiveP.getSdpEntity();
  34. logger.debug("invoketime:" + (System.currentTimeMillis() - watcher) + "ms");
  35. return new InvokeResult(rp.getResult(),rp.getOutpara());
  36. } else if(receiveP.getSDPType()== SDPType.Reset){
  37. logger.info(server.getName()+"server is reboot,system will change normal server!");
  38. this.createReboot(server);
  39. returninvoke(returnType, typeName, methodName, paras);
  40. }else if(receiveP.getSDPType() == SDPType.Exception) {
  41. ExceptionProtocol ep = (ExceptionProtocol)receiveP.getSdpEntity();
  42. throwThrowErrorHelper.throwServiceError(ep.getErrorCode(), ep.getErrorMsg());
  43. } else {
  44. throw newException("userdatatype error!");
  45. }

Server.request()过程

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

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 返回

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

Gaea源码阅读(二):客户端流程相关推荐

  1. mybatis源码阅读(二):mybatis初始化上

    转载自  mybatis源码阅读(二):mybatis初始化上 1.初始化入口 //Mybatis 通过SqlSessionFactory获取SqlSession, 然后才能通过SqlSession与 ...

  2. LeGo-LOAM激光雷达定位算法源码阅读(二)

    文章目录 1.featureAssociation框架 1.1节点代码主体 1.2 FeatureAssociation构造函数 1.3 runFeatureAssociation()主体函数 2.重 ...

  3. nginx源码阅读(二).初始化:main函数及ngx_init_cycle函数

    前言 在分析源码时,我们可以先把握主干,然后其他部分再挨个分析就行了.接下来我们先看看nginx的main函数干了些什么. main函数 这里先介绍一些下面会遇到的变量类型: ngx_int_t: t ...

  4. DBFace: 源码阅读(二)

    上篇链接 看LZ上篇博客的时间竟然是7月18日,着实是懈怠了,其实有很多东西需要总结归纳,这周末就补一下之前欠的债吧 上篇主要介绍了DBFace的大体框架,这篇主要介绍数据的预处理部分 5. 数据预处 ...

  5. Gaea源码阅读(一):使用

    转载地址:http://blog.csdn.net/m_vptr/article/details/9145321 Gaea:58同城开源的中间层服务框架 https://github.com/58co ...

  6. Gaea源码阅读(五):C客户端

    转载地址:http://blog.csdn.net/m_vptr/article/details/9245763 除了Java客户端外,Gaea还提供了C语言和.NET实现. 基本都是相同的,只是序列 ...

  7. Gaea源码阅读(三):服务端启动流程

    转载地址:http://blog.csdn.net/m_vptr/article/details/9163319 相对于客户端,服务器端工作就比较多了.服务器端需要load jar包,利用fliter ...

  8. datax源码阅读二:Engine流程

    一.根据前面python文件知道,java的main函数是com.alibaba.datax.core.Engine public static void main(String[] args) th ...

  9. ThinkPHP源码阅读1-------访问流程

    ThinkPHP访问流程在手册1.11系统流程里就有介绍,我阅读的ThinkPHP的版本是3.1.3,大家可以看下手册,基本的流程也有,现在就是详细去介绍一下ThinkPHP的访问流程.(调试模式下的 ...

最新文章

  1. android shell hello world,Android Framework 之HelloWorld(三)
  2. iOS开发常用的RGB色值和宏
  3. html导航教程视频,导航_HTML+CSS前端基础知识教程_腾讯视频
  4. delphi控件切图界面闪烁_先本设计教你跳过UI小程序的七个坑
  5. Python - 遍历列表时删除元素的正确做法
  6. (转)游戏程序员养成计划 (更新2010.11.6)
  7. matlab的数值计算方法,数值计算方法中的一些常用算法的Matlab源码
  8. (44)FPGA面试题CMOS和TTL电路区别
  9. arguments.callee 指向正在执行的函数的指针
  10. html5 的 webScoket 和 C# 建立Socket连接
  11. HDU 1465 不容易系列之一 (错排)
  12. 深入解析Windows操作系统(笔记7)
  13. 基于stm32 ESP8266WiFi模块的基本通信
  14. Python实现一键翻译英文论文,实现了pdf文档英译汉,pdf格式不变
  15. 算法设计与分析 ——10-7课程总结
  16. python不用api爬twitter
  17. 分享解决方法:为什么QQ聊天框中无法使用输入法输入中文?
  18. DPDK-实战之load_balancer(负载均衡)
  19. 个人日记——用来激励自己
  20. matlab实现PS算法之亮度调整

热门文章

  1. C语言成绩管理系统实例 附源码(一)
  2. springmvc入门之映射处理器(一)
  3. 瞄准新机会--金山软件知名公司官网武汉公司项目
  4. 示波器上X10档与X1档的区别
  5. ubuntu16.04 更新软件源 操作步骤
  6. ambc现在什么情况_凤凰金融现在什么情况啊
  7. Hive-day06基本函数_窗口函数_行列转换_UDF_连续登录问题
  8. 14款备受好评的开源监控工具
  9. Launch启动文件的使用方法
  10. 关于的引用与取地址 区分