Dobbo源码解析 - 图1

注册服务的过程

  1. ###加载注册中心链接
  2. //加载注册中心,用于链接,dubbo支持多注册中心
  3. //注册中心 <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
  4. List<URL> registryURLs = ConfigValidationUtils.loadRegistries(this, true);
  5. //协议,可以暴露多协议,用,分开
  6. //dubbo 协议、端口号 <dubbo:protocol name="dubbo" port="2181"/>
  7. ProtocolConfig
  8. ###服务导出
  9. //解析配置
  10. Map<String, String> map = new HashMap<String, String>();
  11. "side" -> "provider"
  12. "metadata-type" -> "remote"
  13. "application" -> "family-provider"
  14. "release" -> ""
  15. "deprecated" -> "false"
  16. "dubbo" -> "2.0.2"
  17. "pid" -> "9812"
  18. "dynamic" -> "true"
  19. "interface" -> "org.apache.dubbo.service.EsProductService"
  20. "generic" -> "false"
  21. "timestamp" -> "1591705088689"
  22. //封装成URL dubbo协议、端口、
  23. //dubbo://192.168.56.1:20880/org.apache.dubbo.service.EsProductService?
  24. //anyhost=true&application=family-provider&
  25. //bind.ip=192.168.56.1&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&
  26. //interface=org.apache.dubbo.service.EsProductService&metadata-type=remote&
  27. //methods=searchPage&pid=11384&release=&side=provider&timestamp=1591706038181
  28. URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
  29. //创建invoker
  30. //ref服务实例对象、interfaceClass接口、url注册中心:将dubbo服务注册到添加中心
  31. //dubbo://192.168.56.1:20880/org.apache.dubbo.service.EsProductService?
  32. //anyhost=true&application=family-provider&bind.ip=192.168.56.1&
  33. //bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&
  34. //interface=org.apache.dubbo.service.EsProductService&metadata-type=remote&
  35. //methods=searchPage&pid=5660&release=&side=provider&timestamp=1591708521903
  36. Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass,
  37. registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
  38. //建立通信
  39. Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
  40. //提供发现能力 RegistryProtocol
  41. //通过url 加载 Registery,建立链接 final Registry registry = getRegistry(originInvoker);
  42. //将url 注册 到(zk)远程 final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
  43. //创建监听 监听对象:
  44. //final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
  45. //overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
  46. //向注册中心订阅
  47. //registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
  48. public <T> Exporter<T> export(final Invoker<T> originInvoker);
  49. //服务暴露 DubboProtocol
  50. //将我们的Invoker对象 包装为 DubboExporter 对象
  51. //启动服务,创建Netty服务,此时启动了一个IP+Port的Netty服务,可以提供远程服务调用的能力
  52. public <T> Exporter<T> export(Invoker<T> invoker);
  53. ###以上代码只是提供了一个(IP+PORT+Bean+Method)服务,但是这时候消费端是不知道有这么一个服务的

RegistryProtocol

  1. @Override
  2. public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
  3. URL registryUrl = getRegistryUrl(originInvoker);
  4. // url to export locally
  5. URL providerUrl = getProviderUrl(originInvoker);
  6. // 订阅override数据
  7. // FIXME 提供者订阅时,会影响同一JVM即暴露服务,又引用同一服务的的场景,
  8. // 因为subscribed以服务名为缓存的key,导致订阅信息覆盖。
  9. final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
  10. final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
  11. overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
  12. providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
  13. // 在本地暴露服务
  14. final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
  15. //registry provider
  16. // 拿到zookeeper的注册信息
  17. final Registry registry = getRegistry(originInvoker);
  18. // 获取需要暴露provider的url对象,dubbo的注册订阅通信都是以url作为参数传递的
  19. final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
  20. // decide if we need to delay publish
  21. boolean register = providerUrl.getParameter(REGISTER_KEY, true);
  22. if (register) {
  23. //注册服务到注册中心zooker
  24. register(registryUrl, registeredProviderUrl);
  25. }
  26. // register stated url on provider model
  27. registerStatedUrl(registryUrl, registeredProviderUrl, register);
  28. // 暴露的同时订阅服务,另外会在zk上创建configurators节点信息
  29. registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
  30. exporter.setRegisterUrl(registeredProviderUrl);
  31. exporter.setSubscribeUrl(overrideSubscribeUrl);
  32. notifyExport(exporter);
  33. //保证每次export都返回一个新的exporter实例
  34. return new DestroyableExporter<>(exporter);
  35. }

DubboProtocol

  1. @Override
  2. public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
  3. URL url = invoker.getUrl();
  4. // export service.
  5. String key = serviceKey(url);
  6. DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
  7. exporterMap.put(key, exporter);
  8. // 这里会判断是否是stub服务,默认false
  9. Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT);
  10. // 判断是否是callback服务
  11. Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false);
  12. if (isStubSupportEvent && !isCallbackservice) {
  13. String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY);
  14. if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
  15. if (logger.isWarnEnabled()) {
  16. logger.warn(new IllegalStateException("consumer [" + url.getParameter(INTERFACE_KEY) +
  17. "], has set stubproxy support event ,but no stub methods founded."));
  18. }
  19. }
  20. }
  21. // 开启Netty服务
  22. openServer(url);
  23. optimizeSerialization(url);
  24. return exporter;
  25. }
  1. 服务暴露
  2. xxxService这个实例对象转换成AbstractProxyInvoker
  3. Invoker对象 包装为 DobboExporter
  4. 创建Transporter
  5. 创建Server(NettyServer)
  6. 服务注册
  7. 连接Zookeeper
  8. 创建Provier下的临时节点(绑定服务器节点的URL
  9. 监听Zookeeperconfigurators节点

RPC原理

为什么要用Dubbo

1.各个应用节点中的url管理维护困难、依赖关系很模糊 -注册中心
2.每个应用节点的性能、并发量、响应时间、没办法评估 -监控中心

protocol 协议

webservice、Thrift、hessain、http、dubbo、rmi

发布服务

dubbo【协议】://ip:20880【端口】/com.xxx.provider.service.xxxService【接口名称】?参数【服务端配置】

URL

  1. dubbo://192.168.56.1:20880/com.city.service.DemoService?
  2. anyhost=true&
  3. application=hello-world-app&
  4. bind.ip=192.168.56.1&
  5. bind.port=20880&
  6. dubbo=2.6.0&
  7. generic=false&
  8. interface=com.city.service.DemoService&methods=sayHello&
  9. pid=11508&
  10. side=provider&
  11. timestamp=1591614320441

配置参数

  1. 发布服务参数介绍
  2. dubbo.application.name = 提供方应用信息,用于计算依赖关系
  3. dubbo.registry.address = 注册中心,N/A表示不使用注册中心
  4. dubbo.protocol.name = 使用的协议
  5. dubbo.protocol.port = 端口号
  6. dubbo.service.interface = 提供服务的接口名称
  7. dubbo.service.ref = 服务的引用实现

zk节点

  1. zk 存放节点路径
  2. /dubbo/com.city.common.service.EsProductService/configurators
  3. /dubbo/com.city.common.service.EsProductService/providers
  4. providers 下面挂着url
  5. 临时节点:url
  6. 持久化节点:/dubbo/com.city.common.service.EsProductService/providers
  7. /dubbo/com.city.common.service.EsProductService/configurators

调用服务

  1. 基于spring 配置文件拓展
  2. NamespaceHander 注册BeanDefinitonParser,利用它来解析
  3. BeanDefintionParser 解析配置文件元素
  4. spring 默认加载jar 包下/META-INF/spring.handlers 找到对象的NamespaceHander
  5. ServiceConfig<T> implements
  6. InitializingBean, spring容器初始化完后,会调用afterPropertiesSet方法
  7. DisposableBean, 当容器被销毁的时候会调用destroy方法
  8. ApplicationContextAware, spring容器初始化以后主动注入ApplicationContext对象
  9. BeanNameAware, 获取bean本身id属性
  10. ApplicationEventPublisherAware 事件通知

Dobbo源码解析 - 图2