dubbo 在服务暴露发生了哪些事,今天咱们就来分析一下整个服务暴露中的本地暴露。本地暴露须要服务提供方与服务消费方在同一个 JVM。下面咱们来写一个本地暴露使用的例子:html
1 DemoService.javajava
2DemoServiceImpl.javaapi
3application.xml – Spring配置文件app
4Provider.java – 调用本地暴露的服务jvm
使用context.getBean("demoServiceDubbo", DemoService.class)
这种方式来获取Bean还不如使用context.getBean("demoService", DemoService.class)
来获取真正对象。前一种方式获取到是 dubbo 返回的代理类,其中能够获取到 dubbo 的InvokerListener
与Filter
这两个扩展点。可能这是与整个服务保持统一性吧。(你们若是有不一样的观点欢迎留言)。下面咱们就从源码的角度来分析一下 dubbo 的本地暴露吧。ide
若是你们看过dubbo官网的API配置(建议你们分析码源的时候都使用API的形式调用,尽可能少的引入第三方Jar包好比xml配置dubbo
),咱们就能够知道。dubbo服务的暴露的起点是ServiceConfig#export
。下面咱们就以这个方法以起点来分析它:export
这个方法就是dubbo服务暴露的入口,主要就是判断这个服务是否暴露以及经过ScheduledThreadPoolExecutor
这个线程池类支持延迟暴露。接下来就是
doExport
方法,在这个方法的前面就是作一些 check 操做,不是重点,就不一一分析了。咱们主要看一下它的appendProperties方法
以及doExportUrls
这两个方法。appendProperties()
方法主要是为当前对象经过setter 方法来添加属性,它主要是经过如下方式来添加属性:源码分析
从 System 中获取属性key值的优先通信是: dubbo.provider.
+ 当前类 Id + 当前属性名称 > dubbo.provider.
+ 当前属性名称 为 key 获取值.spa
首先从特定properties文件加载属性:首先 System.getProperty("dubbo.properties.file")
获取到文件路径,若是获取不到就会试图加载 dubbo 的默认的路径 dubbo.properties
加载。获取属性的 key 和上面从 System 里面获取的规则同样。线程
而后咱们就来分析一下doExportUrl
这个方法,由于 Dubbo 容许配置多协议,在不一样服务上支持不一样协议或者同一服务上同时支持多种协议。因此这里须要循环各个协议进行多协议暴露服务。3d
而后咱们来分析一下ServiceConfig#doExportUrlsFor1Protocol,首先咱们来看一下appendParameters(Map, Object)这个方法,这个方法的做用就是经过调用当前对象的getter方法获取到传入对象的值而后塞到 map 当中去。用于后面的构造URL这个对象。
注:URL,配置信息的统一格式,全部扩展点都经过传递 URL 携带配置信息)
若是你们没有看过我六、dubbo源码分析 之 服务暴露概述在这点我再向你们提醒一下,dubbo的对象扭转过程是:
服务配置类 –> Invoker –> Exporter
首先经过 ref (服务实现类)、服务接口类以及 URL 默认经过 javassist,也就是 JavassistProxyFactory类获取到代理对象。
而后再把 Invoker 对象转化成Exporter对象。还记得以前的5.dubbo源码分析 之 SPI分析以前是分析的远程暴露中的获取Protocol 实例。只是这里的 protocol实例是 本地方法暴露获取的实例。它也是 dubbo 自定义的 SPI 生成的 Protocol$Adaptive经过它的getExtension(name)方法建立 Protocol实例,而后经过 Protocol#export 方法获取Exporter。
dubbo 的定义 SPI 里面包括 AOP,其实就是获取到全部的 SPI 接口的实例对象。而后在调用 getExtension(name)
方法返回指定名字的扩展的时候会判断哪些实现类的构造器只包含 SPI 接口就会进行代理。这里的name
是从 URL 中获取协议。在调用ServiceConfig#loadRegistries
方法的里面返回的 URL 格式为registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?xxx=xxx
而后再调用ServiceConfig#exportLocal(URL)
方法的时候里面把协议(protocol)设置成injvm
, 而后 在 Protocol$Adaptive
进行服务暴露的时候:
由于 duubo 默认在dubbo-rpc-injvm的自定义Protocol配置文件(${dubbo-rpc-injvm}/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol)配置的是injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol因此获得的对象是InjvmProtocol。由于ProtocolListenerWrapper 与 ProtocolFilterWrapper 其实都包括 SPI 接口 Protocol的构造器。因此建立出来的对象如上因此。关于 dubbo 的SPI机制能够参看 – 2.dubbo源码分析 之 内核SPI实现.
ProtocolListenerWrapper : 经过 SPI 机制获取到 dubbo 的自定义扩展 InvokerListener。
ProtocolFilterWrapper : 经过 SPI 机制获取到 dubbo 的自定义扩展 Filter(经常使用)。
其实关于 dubbo 经过 SPI 机制获取机制获取到 dubbo 的自定义扩展 Filter,还蛮复杂与重要的。在这里就很少说了,感兴趣的朋友能够下去参看源码。
最终就到了InjvmProtocol暴露服务,其实它就是建立一个 InjvmExporter 对象返回。里面包括 4 个属性:
invoker:Invoker 对象实例
key:服务 key 值,在进行服务调用的时候会根据这个 key 值。获取到当前服务暴露生成的 Exporter 对象。
exporterMap:服务 key 值与当前 Exporter 的映射
最后这个生成的 Exporter 最终会返回添加到 ServiceConfig的 exporters 属性当中去。这样就完成了 dubbo 服务暴露的本地暴露的过程。
其实整个 dubbo 的本地暴露逻辑仍是蛮简单的,把它分开来主要仍是整个服务暴露过程比较复杂。先给你们讲解一下本地暴露。若是你们清楚了本地暴露,而后再理解远程暴露就会更加容易。