部分图片和描述来自官方文档,非原创
初始化过程细节
解析服务
解析服务是暴露服务(提供方 provider )和消费方(引用提供方的 service )的前一个步骤。
回想我们如何使用dubbo的
提供方
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ... <dubbo:provider protocol="dubbo" port="-1"/> <dubbo:service interface="com.general.msg.service.PushCommentMeMsgService" ref="pushCommentMeMsgService" version="2.0.0" retries="0" timeout="6000"/> <dubbo:service interface="com.general.msg.service.MessageDetailService" ref="messageDetailService" version="1.0.0" retries="0" /> ... </beans>
x消费方
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ... <dubbo:consumer check="false"/> <dubbo:reference interface="com.general.business.service.IndexDataService" id="indexDataService" version="1.0.0"/> <dubbo:reference interface="com.general.business.service.AppCommentService" id="appCommentService" version="2.0.0"/> ... </beans>
下面我们看一下Dubbo 如何对XML的服务进行解析。
解析实现
基于 dubbo.jar 内的 META-INF/spring.handlers 配置,Spring 在遇到 dubbo 名称空间时,会回调 DubboNamespaceHandler。所有 dubbo 的标签,都统一用 DubboBeanDefinitionParser 进行解析,基于一对一属性映射,将 XML 标签解析为 Bean 对象。 我们看一下spring.handlers 是什么
http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
可以知道这是利用SPI机制加载这两个类,然后对XML 进行解析。
在 ServiceConfig.export() 或 ReferenceConfig.get() 初始化时,将 Bean 对象转换 URL 格式,所有 Bean 属性转成 URL 的参数。
这两个方法非常重要!!ServiceConfig.export()
是暴露服务用的;ReferenceConfig.get()
然后将 URL 传给 协议扩展点,基于扩展点的 扩展点自适应机制,根据 URL 的协议头,进行不同协议的服务暴露或引用。
暴露服务
大致的过程如上,我们来看一下官方的描述,向注册中心暴露服务:
在有注册中心,需要注册提供者地址的情况下 [2],ServiceConfig 解析出的 URL 的格式为: registry://registry-host/org.apache.dubbo.registry.RegistryService?export=URL.encode("dubbo://service-host/com.foo.FooService?version=1.0.0"),基于扩展点自适应机制,通过 URL 的 registry:// 协议头识别,就会调用 RegistryProtocol 的 export() 方法,将 export 参数中的提供者 URL,先注册到注册中心。再重新传给 Protocol 扩展点进行暴露: dubbo://service-host/com.foo.FooService?version=1.0.0,然后基于扩展点自适应机制,通过提供者 URL 的 dubbo:// 协议头识别,就会调用 DubboProtocol 的 export() 方法,打开服务端口。 整个时序图如下 : 对应的export 方法在图中已经标出,方框这是注册到注册中心去的过程。
引用提供者服务
引用和暴露过程差不多,见官方文档 。
远程调用细节
上一节将的是初始化的过程,这一节将会讲如何调用和消费的问题。
概述
假如存在
//消费方 public class DemoClientAction { private DemoService demoService; public void setDemoService(DemoService demoService) { this.demoService = demoService; } public void start() { String hello = demoService.sayHello("world" + i); } }
上面代码中的 DemoService 就是上图中服务消费端的 proxy,用户代码通过这个 proxy 调用其对应的 Invoker [5],而该 Invoker 实现了真正的远程服务调用。
//提供方代码 public class DemoServiceImpl implements DemoService { public String sayHello(String name) throws RemoteException { return "Hello " + name; } }
上面这个类会被封装成为一个 AbstractProxyInvoker 实例,并新生成一个 Exporter 实例。这样当网络通讯层收到一个请求后,会找到对应的 Exporter 实例,并调用它所对应的 AbstractProxyInvoker 实例,从而真正调用了服务提供者的代码。Dubbo 里还有一些其他的 Invoker 类,但上面两种是最重要的。
可以知道 invoker 起到了一个承上启下的作用,在提供方和消费方之前形成了一个桥梁。
服务提供者暴露一个服务的详细过程
暴露过程也不能理解,主线就是 invoker ---> exporter
对象的过程。
服务消费者消费一个服务的详细过程
线程派发模型
参考资料
- http://dubbo.apache.org/zh-cn/docs/dev/implementation.html