设计
整体设计图(引用自官网)以ServiceConfig类为起点,主要过程为执行invoker和Exporter两个操作,这样看起来就清晰了。下面是整个export的时序图,从中可以看出ServiceConfig动作为createInvoker()和export(),Protocol执行了init()和exported()。
时序图(引用自官网)注册中心暴露服务
ServiceConfig
解析出的 URL 的格式为: registry://registry-host/com.alibaba.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()
方法,打开服务端口。
首先 ServiceConfig 类拿到对外提供服务的实际类 ref(如:HelloWorldImpl),然后通过 ProxyFactory 类的 getInvoker 方法使用 ref 生成一个 AbstractProxyInvoker 实例,到这一步就完成具体服务到 Invoker 的转化。接下来就是 Invoker 转换到 Exporter 的过程。
Dubbo 处理服务暴露的关键就在 Invoker 转换到 Exporter 的过程,上图中的红色部分。 Dubbo 和 RMI 这两种典型协议的实现如下:
-
Dubbo 的实现
Dubbo 协议的 Invoker 转为 Exporter 发生在 DubboProtocol 类的 export 方法,它主要是打开 socket 侦听服务,并接收客户端发来的各种请求,通讯细节由 Dubbo 自己实现。 -
RMI 的实现
RMI 协议的 Invoker 转为 Exporter 发生在 RmiProtocol类的 export 方法,它通过 Spring 或 Dubbo 或 JDK 来实现 RMI 服务,通讯细节这一块由 JDK 底层来实现,这就省了不少工作量。
暴露过程
初始化的时候扫描配置文件,调用父类的方法registerBeanDefinitionParser(),存入一个名为parsers的hashMap中。
image.png然后ServiceConfig类中的export方法不知道怎么的就执行了到这了,可以看到方法里可以立即加载和延时加载。
image.png在调用当前类的doExport方法。方法中检查了加载的参数完不完整,正不正确。
img接下来进入doExportUrls();方法,可以看到这里有个for循环,可以接受多个注册地址。
image.png然后进入doExportUrlsFor1Protocol()方法,这个方法比较长,前半段负责检查拼装参数,还有一些逻辑,我觉得最重要的是下面箭头所指的两行代码,第一个是通过代理工厂生成代理方法,第二个是暴露服务。
image.png第二个会进入ProtocolFilterWrapper的export方法,调用buildInvokerChain链
image.png会默认进入DubboProtocol里,在这里的调用openServer()
image.png仔细看看openServer()都干了啥,openServer调用createServer(url),createServer(url)中最重要的bind方法。
image.png一步一步走下去,看到是调用了Transporters的bind方法。
image.png点进去bind方法,可以看到getTransporter()这个方法返回了一个Transporter对象,看一下Transporter的接口,bind方法上有@Adaptive注解,在 Dubbo 的 ExtensionLoader 的扩展点类对应的 Adaptive 实现是在加载扩展点里动态生成。指定提取的 URL 的 Key 通过 @Adaptive 注解在接口方法上提供。对于 bind() 方法,Adaptive 实现先查找 server key,如果该 Key 没有值则找 transport key 值,来决定代理到哪个实际扩展点。默认使用SPI中设定的值,所以是netty。
image.pngtransporter
Adaptive
在NettyServer继承了AbstractServer并且实现了Server接口,可以看到NettyServer在构造方法中实现了父类的构造方法,调用了doOpen,也可以看到打出start bind export的日志。
image.pngimage.png
image.png
然后进入到RegistryProtocol的export方法,在这里注册服务到zookeeper
image.png
调用下面方法,设置协议等
image.png执行这句 final Registry registry = getRegistry(originInvoker);
image.png
调用AbstractRegistryFactory的getRegistry
image.pngZookeeperRegistryFactory的createRegistry的方法,因为ZookeeperRegistryFactory继承了AbstractRegistryFactory,AbstractRegistryFactory实现了RegistryFactory接口,而这个接口的getRegistry方法注解为@Adaptive({"protocol"}),之前有设置协议为zookeeper,所以根据名称选择了ZookeeperRegistryFactory的实现。
image.png这里调用zookeeperTransporter的connect,就跟调用netty一样的
image.png
默认Zkclient的实现
image.png
在这里创建连接
image.png
创建成功之后,dubbo自己存一份
image.png
然后返回RegistryProtocol的export方法,添加一些订阅监听
最后回到ServiceConfig的export方法,整个服务暴露完成。
参考:http://dubbo.io/books/dubbo-dev-book/design.html
各位大神多多指导
网友评论