2.2 导出 Dubbo 服务

前置工作做完,接下来就可以进行服务导出了。服务导出分为导出到本地 (JVM),和导出到远程。在深入分析服务导出的源码前,我们先来从宏观层面上看一下服务导出逻辑。如下:

  1. private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
  2. // 省略无关代码
  3. if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
  4. .hasExtension(url.getProtocol())) {
  5. // 加载 ConfiguratorFactory,并生成 Configurator 实例,然后通过实例配置 url
  6. url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
  7. .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
  8. }
  9. String scope = url.getParameter(Constants.SCOPE_KEY);
  10. // 如果 scope = none,则什么都不做
  11. if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {
  12. // scope != remote,导出到本地
  13. if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
  14. exportLocal(url);
  15. }
  16. // scope != local,导出到远程
  17. if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {
  18. if (registryURLs != null && !registryURLs.isEmpty()) {
  19. for (URL registryURL : registryURLs) {
  20. url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
  21. // 加载监视器链接
  22. URL monitorUrl = loadMonitor(registryURL);
  23. if (monitorUrl != null) {
  24. // 将监视器链接作为参数添加到 url 中
  25. url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
  26. }
  27. String proxy = url.getParameter(Constants.PROXY_KEY);
  28. if (StringUtils.isNotEmpty(proxy)) {
  29. registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
  30. }
  31. // 为服务提供类(ref)生成 Invoker
  32. Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
  33. // DelegateProviderMetaDataInvoker 用于持有 Invoker 和 ServiceConfig
  34. DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
  35. // 导出服务,并生成 Exporter
  36. Exporter<?> exporter = protocol.export(wrapperInvoker);
  37. exporters.add(exporter);
  38. }
  39. // 不存在注册中心,仅导出服务
  40. } else {
  41. Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
  42. DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
  43. Exporter<?> exporter = protocol.export(wrapperInvoker);
  44. exporters.add(exporter);
  45. }
  46. }
  47. }
  48. this.urls.add(url);
  49. }

上面代码根据 url 中的 scope 参数决定服务导出方式,分别如下:

  • scope = none,不导出服务
  • scope != remote,导出到本地
  • scope != local,导出到远程

不管是导出到本地,还是远程。进行服务导出之前,均需要先创建 Invoker,这是一个很重要的步骤。因此下面先来分析 Invoker 的创建过程。