当前位置: 首页 > 科技观察

面试官问我:解释一下Dubbo服务曝光

时间:2023-03-19 19:01:24 科技观察

前言。你应该读过上一篇文章。下面我将带大家简单介绍一下RPC、HTTP+Restful、Dubbo的来源、Dubbo的架构。下面说一下Dubbo的服务暴露、引用和消费,以及Dubbo的SPI机制。当然还有一些技术点,只是表面的,比如服务暴露。我们只说了这个东西是什么意思,代表什么。可能很多小仙女还在迷茫中,别着急,小编一一为大家详细介绍,带大家拨开云雾见天日。今天我们就来分析下Dubbo的服务暴露流程。该流程属于Dubbo的核心流程之一,因为Dubbo的总流程是服务暴露->服务引用->服务消费的主要流程。当然还涉及到注册发现、负载均衡、集群容错等,我们将从源码的角度来分析服务暴露的过程。当然,您不必担心。我们不会把代码分析的这么详细,也没有时间和精力,大家不用担心看不懂。我也会跟大家讲总结词,帮助大家理解Dubbo。三种调用方式:1.注解@Reference调用(这个是最常用的)@Reference(version="1.0.0")privateUserServiceuserService;2.指定调用dubbo的服务端口Stringurl="dubbo://192.168.1.102:10086/ccom.dayu.api.business.cache.IMerchantRedisCache?version=1.0.0";//更改ip地址&端口由不同的Dubbo服务暴露ReferenceBeanreferenceBean=newReferenceBean();referenceBean。setApplicationContext(applicationContext);referenceBean.setInterface(IMerchantRedisCache.class);referenceBean.setUrl(url);try{referenceBean.afterPropertiesSet();IMerchantRedisCachemerchantRedisCache=referenceBean.get();PlaneResDtoresDto=merchantRedisCache.getInDubbo(419248146L);JsonPrinter.printJson(resDto);Assert.assertTrue(SysCode.SUCCESS.equals(resDto.getRspCd()));}catch(异常){e.printStackTrace();}3.从Zookeeper获取服务提供者的信息,然后调用ZkClientzkClient=newZkClient(ZKServers,10000,10000,newSerializableSerializer());Listlists=zkClient.getChildren("/dubbo/com.yc.api.business.cache.ICacheFacade/providers");URLURL统一模型的含义不说dubbo,我们大多数人对URL这个概念并不陌生统一资源定位器(UniformResourceLocators)应该是最著名的RFC规范了,它的定义也很简单。Internet上可用的资源可以用简单的字符串表示。本文档描述了语法和语义,这些字符串被称为:“统一资源定位器”(URL)一个标准的URL格式最多可以包含以下部分protocol://username:password@host:port/path?key=value&key=value接下来我们看一下Dubbo中的URL:{thrownewIllegalArgumentException("Invalidurl,passwordwithoutusername!");}this.urlAddress=newPathURLAddress(protocol,username,password,path,host,port);this.urlParam=URLParam.parse(parameters);}protocol:一般在dubbo各种协议如:dubbo、thrift、http、zkusername/password:用户名/密码host/port:主机IP地址/端口号path:接口名parameter:参数键值对对于dubbo中的url,有人理解为配置bus,有人理解为统一配置m奥德尔。虽然用语不同,但都表达一个意思。这样的URL在dubbo中被视为公共合约。所有的扩展点参数都包括URL参数,在整个扩展点设计中,URL都被用作上下文信息。系统。在没有URL之前,参数只能以字符串的形式传递,不断地解析、组装,从而产生同类型的接口。参数有时是Map,有时是Parameters类封装:export(Stringurl)createExporter(Stringhost,intport,Parametersparams)使用同一个URL性模型:export(URLurl)createExporter(URLurl)在最新的dubbo代码中,我们可以看到一个大量URL用于在上下文之间传输信息。这样做的好处是显而易见的:1.编码标准使得代码易写,易读2.扩展性强,URL相当于一组参数(相当于一个Map)3.模型统一,各个扩展模块都可以使用它作为参数的表达形式Service暴露了主进程Service暴露了主进程,大致分析过程分为两个角度。我们先简单了解一下。接下来带大家一步步看源码:客观流程视角:前期工作,主要用于检查参数和拼接URL。导出服务,包括暴露服务给本地(JVM)和暴露服务给远程两个进程。向注册表注册服务以进行服务发现。对象转换视角:首先将服务的实现封装成一个Invoker,在Invoker中封装了服务的实现类。将Invoker打包成Exporter并缓存。缓存使用调用程序的URL作为键。服务器server启动并监听端口。初始化,属于入口,我们来看一下ServiceBean类的使用。这里有一个小插曲。经过对比发现,最新版本继承了ApplicationEventPublisherAware接口,而老版本继承了ApplicationListener接口。对了,源码地址在:https://gitee.com/dayumm大部分博客视频都说明了服务暴露的导出方法的来源是ServiceConfig的导出方法。ServiceBean继承ServiceConfig,通过实现ApplicationListener接口的onApplicationEvent方法最终调用ServiceConfig的export方法。但是最新版本实现了ApplicationEventPublisherAware,并没有调用ServiceConfig的export方法,而是ServiceBean在导出完成后使用该接口发布一个导出的事件,即暴露事件不是暴露事件,所以新继承的ApplicationEventPublisherAware接口似乎并没有直接对服务暴露过程产生影响。那么ServiceConfig的export方法会在哪里调用呢?追根溯源,发现DubboBootstrapApplicationListener类继承了ApplicationListener和ApplicationContextAware,最后调用了DubboBootStrap方法,发现在start方法中有一行exportServices。顾名思义,就是导出服务或者暴露服务。服务,点击查看exportServices。exportServices会在中间调用ServiceConfigBase的export方法。来看看这个ServiceConfigBase到底有何高见。打开ServiceConfig的结构图一看:原来是父类。这是一个抽象方法,最终调用的是ServiceConfig中最重要的export方法。我们重点关注的是export中的doExport方法。我们可以看到Dubbo支持多注册中心和多协议。如果一个服务有多个协议,它们都需要公开。比如同时支持dubbo协议和hessian协议,需要使用这两个协议向多个注册中心(如果有多个)进行暴露和注册。我们点开doExportUrlsFor1Protocol方法看看,这个方法很长,我们就不一步步看了,这里滑动到方法末尾:本地暴露和远程暴露继续看源码,差不多了over,去本地暴露:调用的服务在使用同一个JVM时,会直接在本地调用Protocol的export方法。标注了@Adaptive注解,所以会生成代理类,然后代理类会根据Invoker中的URL参数知道具体的协议,然后通过DubboSPI机制选择对应的。导出实现类,这个方法会调用InjvmProtocol#export方法InjvmProtocol:其实就是对具体实现类的逐层封装。调用程序实际上是由Javassist创建的。具体创建过程proxyFactory.getInvoker就不分析了。对于Javassist有兴趣的同学可以自行了解,后面可能会写一篇文章。至于dubbo为什么使用javassist而不是jdk动态代理,是因为javassist速度快。为什么要打包成invoker?创建一个可执行体,以便调用者可以简单地使用它并启动对它的调用。可能是本地实现,也可能是远程实现,也可能是集群实现。本地暴露的含义:因为有可能出现同一个JVM内部引用自己服务的情况,所以暴露的本地服务在内部调用时可以直接消费同一个JVM的服务,避免了网络之间的通信。我们来看一张exportLocal的时序图:远程暴露:本机的服务暴露给其他机器的消费者。关注DubboProtocol#export方法及其内部的openServer()方法。可以看到这里的关键其实就是开启Server。RPC必须要求远程调用。这里我们使用NettyServer来监控服务。我就不赘述了,一一分析。有兴趣的可以拉取代码看看。最重要的是了解大概的流程和其中的设计思路。