8.1 构建客户端总体流程

一 示例

1 配置文件:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3        xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
 4        xmlns="http://www.springframework.org/schema/beans"
 5        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 6     http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
 7     <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
 8     <dubbo:application name="demo-consumer"/>
 9     <!-- 使用zookeeper注册中心 -->
10     <dubbo:registry protocol="zookeeper" address="10.211.55.5:2181"/>
11     <!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
12     <dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService"/>
13 </beans>

2 Consumer

 1 package com.alibaba.dubbo.demo.consumer;
 2
 3 import com.alibaba.dubbo.demo.DemoService;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5
 6 public class Consumer {
 7     public static void main(String[] args) {
 8         ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"});
 9         context.start();
10
11         DemoService demoService = (DemoService) context.getBean("demoService"); // 获取远程服务代理
12         String hello = demoService.sayHello("world"); // 执行远程方法
13
14         System.out.println(hello); // 显示调用结果
15     }
16 }

先来看DemoService demoService = (DemoService) context.getBean("demoService"); // 获取远程服务代理。

二 调用简图

三 总体代码调用链

ReferenceConfig.init()
-->createProxy(Map<String, String> map)
  //一 获取Invoker
  -->RegistryProtocol.refer(Class<T> type, URL url)
    //1 获取注册中心:创建ZkClient实例,连接zk
    -->Registry registry = registryFactory.getRegistry(url)
      -->AbstractRegistryFactory.getRegistry(URL url)
        -->ZookeeperRegistryFactory.createRegistry(URL url)
          -->new ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter)
            -->ZkclientZookeeperTransporter.connect(URL url)
              -->new ZkclientZookeeperClient(URL url)
                -->new ZkClient(url.getBackupAddress())
            -->AbstractRegistryFactory.Map<String, Registry> REGISTRIES.put("zookeeper://10.211.55.5:2181/com.alibaba.dubbo.registry.RegistryService", 上边的ZookeeperRegistry实例)
    -->doRefer(Cluster cluster, Registry registry, Class<T> type, URL url)
      -->new RegistryDirectory<T>(type, url)
      //2 向注册中心注册服务
      -->registry.register(url)
        -->ZookeeperRegistry.doRegister(URL url)
          -->AbstractZookeeperClient.create(String path, boolean ephemeral)
      -->RegistryDirectory.subscribe(URL url)
        -->ZookeeperRegistry.doSubscribe(final URL url, final NotifyListener listener)
          //3 会获取当前节点下已经存在的字节点(第一次服务发现发生在这里),添加子节点变化监听器
          -->List<String> children = zkClient.addChildListener(path, zkListener)
          -->AbstractRegistry.notify(URL url, NotifyListener listener, List<URL> urls)
            -->saveProperties(url)
            -->RegistryDirectory.notify(List<URL> urls)
              //仅仅针对的是providers
              -->refreshInvoker(List<URL> invokerUrls)
                -->toInvokers(List<URL> urls
                  -->ProtocolFilterWrapper.refer(Class<T> type, URL url)
                    -->DubboProtocol.refer(Class<T> serviceType, URL url)
                      //4 创建ExchangeClient,对第一次服务发现providers路径下的相关url建立长连接
                      -->getClients(URL url)
                        -->getSharedClient(URL url)
                          -->ExchangeClient exchangeClient = initClient(url)
                            -->Exchangers.connect(url, requestHandler)
                              -->HeaderExchanger.connect(URL url, ExchangeHandler handler)
                                -->new DecodeHandler(new HeaderExchangeHandler(handler)))
                                  -->Transporters.connect(URL url, ChannelHandler... handlers)
                                    -->NettyTransporter.connect(URL url, ChannelHandler listener)
                                      -->new NettyClient(url, listener)
                                        -->new MultiMessageHandler(HeartbeatHandler(AllChannelHandler(handler)))
                                        -->getChannelCodec(url)//获取Codec2,这里是DubboCountCodec实例
                                        -->doOpen()//开启netty客户端
                                        -->doConnect()//连接服务端,建立长连接
                                -->new HeaderExchangeClient(Client client, boolean needHeartbeat)//上述的NettyClient实例,needHeartbeat:true
                                  -->startHeatbeatTimer()//启动心跳计数器
                          -->ReferenceCountExchangeClient(ExchangeClient client, ConcurrentMap<String, LazyConnectExchangeClient> ghostClientMap)/
                          -->Map<String, ReferenceCountExchangeClient> referenceClientMap.put("10.242.48.210:20880", 上边的ReferenceCountExchangeClient实例)
                      //5 创建DubboInvoker
                      -->new DubboInvoker(Class<T> serviceType, URL url, ExchangeClient[] clients, Set<Invoker<?>> invokers)
                      -->DubboProtocol.Set<Invoker<?>> invokers.add(上边的DubboInvoker实例)
                    -->ProtocolFilterWrapper.buildInvokerChain(final Invoker<T> invoker, String key, String group)
                  -->new InvokerDelegete(Invoker<T> invoker, URL url, URL providerUrl)
                  //6 将创建出来的Invoker缓存起来
                  -->newUrlInvokerMap.put("dubbo://10.242.48.210:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-consumer&check=false&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=16001&register.ip=10.242.48.210&remote.timestamp=1510127991625&side=consumer&timestamp=1510128022123", 上边的InvokerDelegate实例)
                -->toMethodInvokers(newUrlInvokerMap)
                -->Map<String, List<Invoker<T>>> newMethodInvokerMap:{sayHello=[InvokerDelegete实例], *=[InvokerDelegete实例]}
      //7 将directory封装成一个ClusterInvoker(MockClusterInvoker)
      -->cluster.join(directory)
        -->Cluster$Adaptive.join(directory)
          -->ExtensionLoader.getExtensionLoader(Cluster.class).getExtension("failover")//MockClusterWrapper包装FailoverCluster
            -->MockClusterWrapper.join(Directory<T> directory)
              -->FailoverCluster.join(Directory<T> directory)
                -->new FailoverClusterInvoker<T>(directory)
              -->MockClusterInvoker(Directory<T> directory, Invoker<T> invoker)//invoker:上边的FailoverClusterInvoker实例
  //二 获取代理
  -->JavassistProxyFactory.getProxy(Invoker<T> invoker, Class<?>[] interfaces)//invoker:上边的MockClusterInvoker实例, interfaces:[interface com.alibaba.dubbo.demo.DemoService, interface com.alibaba.dubbo.rpc.service.EchoService]
    -->Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker))
      -->Proxy.getProxy(ClassLoader cl, Class<?>... ics)//使用javassist获取一个动态类
      -->new InvokerInvocationHandler(invoker)//invoker:上边的MockClusterInvoker实例
时间: 2024-10-09 17:43:36

8.1 构建客户端总体流程的相关文章

【原创】我所理解的自动更新-客户端更新流程

创建更新线程,跟ui主线程通过message进行交互.1,去http://version.mygame.com/check.php? channelid=%d&appver=%d&resver=%d获取客户端最新版本信息.用curl获取,代码如下,至于curl的具体参数,man或者搜索引擎会告诉你答案 1 static size_t funcGetHttpText(void *ptr, size_t size, size_t nmemb, void *userdata) { 2 size_

iOS客户端开发流程

客户端项目流程: 1)产品经理做需求调研,确定产品需求,编写需求文档 2)产品人员完成产品原型 3)产品经理召开会议(产品.UI.UE.开发.服务器) 4) 设计人员根据原型设计出一系列UI界面.用户交互体验制定 5) 服务器与客户端成员一起制定接口文档 6)项目经理制定项目开发进度,分配任务,估算开发周期 7) 移动客户端开发人员根据UI界面和需求文档开始编写代码,开发模块上的功能 8) 开发者提交测试 9) 测试部分完毕,提交产品经理,验收产品 10) 提交appstore上线 开发流程:

深入浅出高性能服务发现、配置框架Nacos系列 3: 服务发现:Nacos客户端初始化流程

上一章节,我们从全局了解了一下Nacos项目的模块架构,做到了心中有数,现在,我们去逐步去挖掘里面的代码细节,很多人在学习开源的时候,无从下手,代码那么多,从哪个地方开始看呢?我们可以从一个接口开始入手,这个接口是你使用过的,知道它大概做什么事,有体感的,大家还记得第一章时,我们写的HelloWorld吗,对,就从里面的接口开始剥洋葱. 这个是Nacos的github代码地址,开始之前先start关注一下,加上watch,后续Nacos的邮件列表也会通知到你,可以关注到Nacos的最新实时消息,

Netty源码分析第3章(客户端接入流程)----&gt;第5节: 监听读事件

Netty源码分析第三章: 客户端接入流程 第五节: 监听读事件 我们回到AbstractUnsafe的register0()方法: private void register0(ChannelPromise promise) { try { //省略代码 //做实际的注册 doRegister(); neverRegistered = false; registered = true; //触发事件 pipeline.invokeHandlerAddedIfNeeded(); safeSetS

Netty源码分析第3章(客户端接入流程)----&gt;第4节: NioSocketChannel注册到selector

Netty源码分析第三章: 客户端接入流程 第四节: NioSocketChannel注册到selector 我们回到最初的NioMessageUnsafe的read()方法: public void read() { //必须是NioEventLoop方法调用的, 不能通过外部线程调用 assert eventLoop().inEventLoop(); //服务端channel的config final ChannelConfig config = config(); //服务端channel

Netty源码分析第3章(客户端接入流程)----&gt;第3节: NioSocketChannel的创建

Netty源码分析第三章: 客户端接入流程 第三节: NioSocketChannel的创建 回到上一小结的read()方法: public void read() { //必须是NioEventLoop方法调用的, 不能通过外部线程调用 assert eventLoop().inEventLoop(); //服务端channel的config final ChannelConfig config = config(); //服务端channel的pipeline final ChannelPi

C/S模型:TCP,UDP构建客户端和服务器端(BIO实现

Java中提供了socket编程来构建客户端和服务器端 TCP构建服务器端的步骤:(1)bind:绑定端口号(2)listen:监听客户端的连接请求(3)accept:返回和客户端连接的实例(4)read/write:进行读写操作,也就是和客户端进行交互(5)close:关闭资源Java中提供了ServiceSocket关键字来构建服务器,在Java中listen和accept合并为一个accept操作,下面通过代码演示一下这5个步骤 public class Server { public s

GeneXus DevOps 自动化构建和部署流程

以下视频详细介绍了GeneXus DevOps自动化构建和部署流程,包括通过MS Bulid来管理自动化流程,自动化的架构,以及在GeneXus Server上使用Jenkins做为自动化引擎. 视频链接:https://v.qq.com/x/page/e3048y6pl9e.html(视频为英文语音和英文字幕) 原文地址:https://www.cnblogs.com/genexusblog/p/12191319.html

模拟构建DNS解析流程

背景 DNS初步认识 ??DNS(Domain Name Server,域名系统)是互联网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户方便的访问互联网,而不用去费力的记忆IP字符串.通过域名,最终可以得到该域名对应的IP地址的过程叫做域名解析.DNS协议运行在UDP洗衣上,使用的是53号端口.???? DNS的重要性以及高可用(DNS冗余) 重要性 ????DNS解析是目前互联网大多数应用的实际的寻址方式:域名技术的不断发展,和基于域名技术出现的新技术和新思路极大的丰富了互联网的应