<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>源码解析 on Apache Dubbo</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/tags/%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/</link><description>Recent content in 源码解析 on Apache Dubbo</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 13 Nov 2025 22:33:41 +0800</lastBuildDate><atom:link href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/tags/%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/index.xml" rel="self" type="application/rss+xml"/><item><title>引言</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2023/04/28/%E5%BC%95%E8%A8%80/</link><pubDate>Fri, 28 Apr 2023 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2023/04/28/%E5%BC%95%E8%A8%80/</guid><description>&lt;h2 id="引言">引言&lt;/h2>
&lt;p>服务指标统计体系是 Dubbo 可观测能力的重要组成部分。
dubbo-metrics 指标模块旨在将 dubbo 内部零散的 Metrics 相关类综合到一个单独的模块中，提供一套更加完善、全面、可拓展、解耦合的指标采样-统计-导出解决方案。&lt;/p>
&lt;p>dubbo-metrics 模块包括：&lt;/p>
&lt;ul>
&lt;li>dubbo-metrics-api 公用接口包&lt;/li>
&lt;li>dubbo-metrics-prometheus 普罗米修斯适配包&lt;/li>
&lt;li>dubbo-metrics-metadata 元数据中心指标监控包&lt;/li>
&lt;li>dubbo-metrics-registry 注册中心指标监控包&lt;/li>
&lt;li>dubbo-metrics-config-center 配置中心指标监控包&lt;/li>
&lt;li>dubbo-metrics-default 接口默认实现包，提供dubbo内部核心指标的监控功能&lt;/li>
&lt;/ul>
&lt;p>在设计上，dubbo-metrics 深入应用事件驱动编程思想，总体体现出下图的事件处理链路：&lt;/p>
&lt;p>&lt;img alt="metrics-event-struct" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/metrics-source-blog/metrics-event-struct.png">&lt;/p>
&lt;p>在拓展上，dubbo-metrics 抽象了一套指标导出接口与抽象实现，可实现兼容多种指标统计监控中心，默认提供了普罗米修斯实现。&lt;/p></description></item><item><title>1-指标样本的收集与存储</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2023/04/28/1-%E6%8C%87%E6%A0%87%E6%A0%B7%E6%9C%AC%E7%9A%84%E6%94%B6%E9%9B%86%E4%B8%8E%E5%AD%98%E5%82%A8/</link><pubDate>Fri, 28 Apr 2023 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2023/04/28/1-%E6%8C%87%E6%A0%87%E6%A0%B7%E6%9C%AC%E7%9A%84%E6%94%B6%E9%9B%86%E4%B8%8E%E5%AD%98%E5%82%A8/</guid><description>&lt;h2 id="一指标样本的收集与存储">一、指标样本的收集与存储&lt;/h2>
&lt;h3 id="指标样本收集">指标样本收集&lt;/h3>
&lt;p>&lt;strong>指标收集器（Collector）是指标对外导出的入口&lt;/strong>。最终导出到指标统计中心的指标采样实际均直接来源于各个指标采样器。因此，我们将从各个收集器实现开始，分析 dubbo-metrics 模块是如何工作的。&lt;/p>
&lt;p>指标收集操作定义在 MetricsCollector （指标采集器，SPI）接口中，可以通过它的实现收集某一类的指标样本（MetricSample）。它主要有以下实现，对应着不同类型的指标：&lt;/p>
&lt;ul>
&lt;li>ConfigCenterMetricsCollector &lt;strong>配置中心操作相关指标收集器&lt;/strong> ，收集配置信息的变化次数&lt;/li>
&lt;li>MetadataMetricsCollector &lt;strong>元数据中心操作相关指标收集器&lt;/strong>，收集提供者、消费者对元数据中心操作（推送数据、拉取数据）情况的计数、耗时统计。&lt;/li>
&lt;li>RegistryMetricsCollector &lt;strong>注册中心相关操作指标收集器&lt;/strong>，收集应用级、接口级服务注册成功、失败、耗时的相关计数。&lt;/li>
&lt;li>DefaultMetricsCollector &lt;strong>默认指标收集器&lt;/strong>，内置多种采样器来完成不同类型的内部指标采样。&lt;/li>
&lt;li>HistogramMetricsCollector &lt;strong>直方图指标收集器&lt;/strong>，利用 micrometer API 处理直方图类型的指标，它的实现较为特殊。&lt;/li>
&lt;/ul>
&lt;p>配置中心 、元数据、服务注册及默认指标收集器均实现自混合指标收集器（CombMetricsCollector）。混合指标收集器实现了 ApplicationMetricsCollector 、ServiceMetricsCollector 、MethodMetricsCollector 三个接口（定义按应用名收集、按应用名-服务名收集和按应用-方法名收集指标的操作），因此它们可以进行应用、服务和方法三个层面的指标收集工作。&lt;/p>
&lt;p>默认指标收集器的特点是通过内部的指标采样器（MetricsSampler）完成指标事件的处理操作，而不是其它收集器的指标监听器（MetricsListener）&lt;/p>
&lt;p>直方图指标收集器则负责收集直方图类型的指标。它利用直方图度量寄存器（HistogramMetricRegister）借助 micrometer API 完成直方图样本的采集。直方图类型包括百分位数、服务水平目标、最小预期值、最大预期值、统计数据分布有效期等。&lt;/p>
&lt;p>&lt;strong>Collector的继承关系：&lt;/strong>&lt;/p>
&lt;p>&lt;img alt="collectors" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/metrics-source-blog/collectors.png">&lt;/p>
&lt;p>可以看出，每个指标收集器都具有来自 MetricsListener 的监听指标事件的能力。为什么指标收集器本身需要监听指标事件？ 在后文中，我们将讨论指标收集器是如何利用内置的子转发器（SubDispatcher）转发指标事件，并完成计数处理的。&lt;/p>
&lt;h3 id="指标样本存储">指标样本存储&lt;/h3>
&lt;p>前文中，我们了解了指标收集的入口是指标收集器（Collector）。那么各个收集器从哪里收集指标样本？&lt;/p>
&lt;p>&lt;strong>对于配置中心、元数据中心、 注册中心的指标收集器：&lt;/strong>&lt;/p>
&lt;p>它们分别负责采集三大中心模块的指标，均继承于&lt;strong>混合数据收集器（CombMetricsCollector）&lt;/strong>，而混合数据收集器中实现了 export 方法 。&lt;/p>
&lt;p>混合数据收集器内部有一个&lt;strong>基本数据聚合器（BaseStatComposite）&lt;/strong>，它实现了 MetricsExport 接口，该接口定义了指标导出操作，混合数据收集器则利用它的 export 方法导出指标。&lt;/p>
&lt;p>基本数据聚合器是一个抽象类，内有三个属性：ApplicationStatComposite 、ServiceStatComposite 和 RtStatComposite 。它们的作用：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>ApplicationStatComposite 应用数据聚合器&lt;/strong>，应用程序级别相关事件的计数 ，根据指标Key（ MetricsKey ）和应用名统计指标，提供计数递增操作&lt;/li>
&lt;li>&lt;strong>ServiceStatComposite 服务数据聚合器&lt;/strong>，服务级别相关事件的计数，根据指标Key、应用名和服务名统计指标，提供计数递增操作&lt;/li>
&lt;li>&lt;strong>MethodStatComposite 方法数据聚合器&lt;/strong>，方法级别相关事件的计数，存储各方法RPC调用相关计数。&lt;/li>
&lt;li>&lt;strong>RtStatComposite，Rt（Response Time，响应时间）数据聚合器&lt;/strong>，包括应用级别和服务级别。根据应用名、服务名、注册的指标名及相应相应时间统计指标，提供添加操作。&lt;/li>
&lt;/ul>
&lt;p>对于以上四个聚合器，他们的职责就是存储某一类型的采样样本。&lt;/p>
&lt;p>&lt;strong>基本数据聚合器 （BaseStatComposite）&lt;/strong> 对这三个子聚合器的操作进行了简单整合，统一提供给外界。&lt;strong>而混合指标收集器（CombMetricsCollector）&lt;/strong> 也基本保留了内部基本数据聚合器的所有操作，将其封装为 &lt;code>increment&lt;/code>、&lt;code>setNum&lt;/code>、&lt;code>addRt &lt;/code>三个方法（及它们的重载，分别收集应用级数据和服务级数据）向上提供。外部组件可以直接调用这些收集器完成指标更新操作。&lt;/p></description></item><item><title>2-指标收集器的指标采集流程</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2023/04/28/2-%E6%8C%87%E6%A0%87%E6%94%B6%E9%9B%86%E5%99%A8%E7%9A%84%E6%8C%87%E6%A0%87%E9%87%87%E9%9B%86%E6%B5%81%E7%A8%8B/</link><pubDate>Fri, 28 Apr 2023 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2023/04/28/2-%E6%8C%87%E6%A0%87%E6%94%B6%E9%9B%86%E5%99%A8%E7%9A%84%E6%8C%87%E6%A0%87%E9%87%87%E9%9B%86%E6%B5%81%E7%A8%8B/</guid><description>&lt;h2 id="二指标收集器的指标采集流程">二、指标收集器的指标采集流程&lt;/h2>
&lt;p>在前文中，我们了解了指标收集器（Collector）最终收集的数据只有三个来源：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>实现自混合指标收集器（CombMetricsCollector） 的元数据指标收集器（MetadataMetricsCollector）和注册中心指标收集器（RegistryMetricsCollector），它们的样本均存储在内置的基本数据聚合器中。具体来说，是基本数据聚合器下的四个子数据聚合器中：&lt;/p>
&lt;p>&lt;img alt="composite-struct" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/metrics-source-blog/composite-struct.png">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>DefaultMetricsCollector 默认指标收集器&lt;/strong>，它的样本不仅来自于指标事件，还来自其下&lt;strong>采样器（Sampler）&lt;/strong> 中，用于Dubbo核心模块的采样。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>HistogramMetricsCollector 直方图指标收集器&lt;/strong>，由于采样数据的特殊性，它的样本直接以 Map 存储在内部。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>接下来，我们需要明确它们存储的指标是如何添加进去的。&lt;/p>
&lt;h3 id="1服务治理模块的指标采集流程">1，服务治理模块的指标采集流程&lt;/h3>
&lt;p>通过之前的分析，我们知道服务治理模块的指标采集器均实现自混合指标收集器（CombMetricsCollector）。它对基本数据聚合器（BaseStatComposite） 的大部分方法做了封装。基本数据聚合器又封装了四个负责存储不同类型指标采样的子聚合器。&lt;/p>
&lt;p>这四个子聚合器包括：&lt;/p>
&lt;ul>
&lt;li>ApplicationStatComposite&lt;/li>
&lt;li>ServiceStatComposite&lt;/li>
&lt;li>MethodStatComposite&lt;/li>
&lt;li>RtStatComposite&lt;/li>
&lt;/ul>
&lt;p>实际上，&lt;strong>元数据、注册中心指标收集器&lt;/strong>更新、添加指标的操作都是通过混合指标收集器暴露的方法进行。而具体的，是通过 &lt;code>setNum&lt;/code>、&lt;code>increment&lt;/code>、&lt;code>addRt&lt;/code> 这三个方法（及它们的重载）进行操作。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">//CombMetricsCollector&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>...
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#268bd2">final&lt;/span> BaseStatComposite stats;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>...
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">setNum&lt;/span>(MetricsKey metricsKey, String applicationName, String serviceKey, &lt;span style="color:#dc322f">int&lt;/span> num) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">this&lt;/span>.stats.setServiceKey(metricsKey, applicationName, serviceKey, num);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">increment&lt;/span>(String applicationName, MetricsKey metricsKey) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">this&lt;/span>.stats.incrementApp(metricsKey, applicationName, SELF_INCREMENT_SIZE);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">increment&lt;/span>(String applicationName, String serviceKey, MetricsKey metricsKey, &lt;span style="color:#dc322f">int&lt;/span> size) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">this&lt;/span>.stats.incrementServiceKey(metricsKey, applicationName, serviceKey, size);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">addRt&lt;/span>(String applicationName, String registryOpType, Long responseTime) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> stats.calcApplicationRt(applicationName, registryOpType, responseTime);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">addRt&lt;/span>(String applicationName, String serviceKey, String registryOpType, Long responseTime) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> stats.calcServiceKeyRt(applicationName, serviceKey, registryOpType, responseTime);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>由于几个方法实际上的调用链路类似，我们选择从其中的 setNum 方法开始分析。&lt;/p></description></item><item><title>3-指标监听注册梳理</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2023/04/28/3-%E6%8C%87%E6%A0%87%E7%9B%91%E5%90%AC%E6%B3%A8%E5%86%8C%E6%A2%B3%E7%90%86/</link><pubDate>Fri, 28 Apr 2023 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2023/04/28/3-%E6%8C%87%E6%A0%87%E7%9B%91%E5%90%AC%E6%B3%A8%E5%86%8C%E6%A2%B3%E7%90%86/</guid><description>&lt;h2 id="三指标监听注册梳理">三、指标监听注册梳理&lt;/h2>
&lt;p>在前一章中，我们了解了不同收集器中的指标样本是如何被监听器添加进去的。接下来，我们将归纳指标监听器 的创建位置，及它们对应统计的指标。&lt;/p>
&lt;p>通过之前的分析，我们已经知道指标 注册事件多播器（RegistryMetricsEventMulticaster）中定义了并绑定了服务注册相关的指标。这种绑定操作同样存在于其它几个简单指标事件多播器（SimpleMetricsEventMulticaster）的几个实现中。&lt;/p>
&lt;h3 id="转发器注册">转发器注册&lt;/h3>
&lt;p>&lt;strong>RegistrySubDispatcher （服务注册指标转发器）注册了服务注册相关指标：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>应用级实例注册成功/失败/总数计数 （APPLICATION_REGISTER_&amp;hellip;)&lt;/li>
&lt;li>应用级服务接口订阅成功/失败/总数计数 （APPLICATION_SUBSCRIBE_&amp;hellip;)&lt;/li>
&lt;li>服务级注册成功/失败/总数计数 （SERVICE_REGISTER_&amp;hellip;）&lt;/li>
&lt;li>特殊的 APPLICATION_NOTIFY_FINISH 和 APPLICATION_DIRECTORY_POST （应用服务目录变化次数）&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>MetadataSubDispatcher（元数据指标转发器）注册应用元数据相关指标&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>应用推送元数据相关计数 （APPLICATION_PUSH_&amp;hellip;)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>应用订阅元数据相关计数 （APPLICAITON_SUBSCRIBE_&amp;hellip;）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>服务订阅元数据相关计数 （SERVICE_SUBSCRIBE_&amp;hellip;）&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>ConfigCenterSubDispatcher (配置中心指标转发器) 注册配置中心配置更新次数指标&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>配置中心推送新配置次数 （CONFIGCENTER_METRIC_TOTAL）&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>DefaultSubDispatcher (默认转发器) 注册核心RPC调用次数指标&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>请求次数 （METRIC_REQUESTS）&lt;/li>
&lt;li>请求成功次数（METRIC_REQUESTS_SUCCEED）&lt;/li>
&lt;li>请求失败次数（METRIC_REQUEST_BUSINESS_FAILED）&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>MetricsDispatcher&lt;/strong>&lt;/p>
&lt;p>MetricsDispatcher 较为特殊，它负责 ApplicationModel 下所有 MetricsCollector（前文中提到的指标收集器） 的初始化注册工作，并将它们添加到自己的监听器列表中。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">MetricsDispatcher&lt;/span> &lt;span style="color:#268bd2">extends&lt;/span> SimpleMetricsEventMulticaster {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@SuppressWarnings&lt;/span>({&lt;span style="color:#2aa198">&amp;#34;rawtypes&amp;#34;&lt;/span>})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">MetricsDispatcher&lt;/span>(ApplicationModel applicationModel) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ScopeBeanFactory beanFactory &lt;span style="color:#719e07">=&lt;/span> applicationModel.getBeanFactory();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ExtensionLoader&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricsCollector&lt;span style="color:#719e07">&amp;gt;&lt;/span> extensionLoader &lt;span style="color:#719e07">=&lt;/span> applicationModel.getExtensionLoader(MetricsCollector.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (extensionLoader &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> List&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricsCollector&lt;span style="color:#719e07">&amp;gt;&lt;/span> customizeCollectors &lt;span style="color:#719e07">=&lt;/span> extensionLoader
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .getActivateExtensions();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (MetricsCollector customizeCollector : customizeCollectors) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> beanFactory.registerBean(customizeCollector);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> customizeCollectors.forEach(&lt;span style="color:#719e07">this&lt;/span>::addListener);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>需要注意，以上几个实现均继承自 SimpleMetricsEventMulticaster，因此它们都具有注册监听、转发事件的能力。它们将自己注册到对应领域的指标 Collector 中，并在收到指标事件时转发到自己注册的监听器中。&lt;/p></description></item><item><title>4-指标转换与导出</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2023/04/28/4-%E6%8C%87%E6%A0%87%E8%BD%AC%E6%8D%A2%E4%B8%8E%E5%AF%BC%E5%87%BA/</link><pubDate>Fri, 28 Apr 2023 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2023/04/28/4-%E6%8C%87%E6%A0%87%E8%BD%AC%E6%8D%A2%E4%B8%8E%E5%AF%BC%E5%87%BA/</guid><description>&lt;h2 id="四指标转换与导出">四、指标转换与导出&lt;/h2>
&lt;p>本章主要梳理指标收集完成后，向外部收集器导出的流程。&lt;/p>
&lt;p>通过之前的分析，我们知道不同类型指标的收集分别由各个 Collector 实现进行。它们底层的 MetricsCollector 接口定义了指标导出的操作。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">@SPI&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">interface&lt;/span> &lt;span style="color:#268bd2">MetricsCollector&lt;/span>&lt;span style="color:#719e07">&amp;lt;&lt;/span>E &lt;span style="color:#268bd2">extends&lt;/span> TimeCounterEvent&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">extends&lt;/span> MetricsLifeListener&lt;span style="color:#719e07">&amp;lt;&lt;/span>E&lt;span style="color:#719e07">&amp;gt;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">default&lt;/span> &lt;span style="color:#dc322f">boolean&lt;/span> &lt;span style="color:#268bd2">isCollectEnabled&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#cb4b16">false&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * Collect metrics as {@link MetricSample}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return List of MetricSample
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> List&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetricSample&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">collect&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>而指标报告器 (MetricsReporter) 的实现会定时调用Collector 的 &lt;code>collect&lt;/code> 方法，更新并导出指标数据。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">interface&lt;/span> &lt;span style="color:#268bd2">MetricsReporter&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//初始化&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">init&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//刷新统计数据，定时调用collect()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">refreshData&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//获取指标数据&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String &lt;span style="color:#268bd2">getResponse&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//获取带指标名的指标样本（单个指标）&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">default&lt;/span> String &lt;span style="color:#268bd2">getResponseWithName&lt;/span>(String metricsName) { &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>指标报告器有两个实现：DefaultMetricsReporter 和 PrometheusMetricsReporter，它们都实现自 AbstractMetricsRepoter，并使用它的指标刷新逻辑 (&lt;code>refreshData&lt;/code>方法)。&lt;/p></description></item><item><title>Dubbo 3 之 Triple 流控反压原理解析</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/12/28/dubbo-3-%E4%B9%8B-triple-%E6%B5%81%E6%8E%A7%E5%8F%8D%E5%8E%8B%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/</link><pubDate>Wed, 28 Dec 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/12/28/dubbo-3-%E4%B9%8B-triple-%E6%B5%81%E6%8E%A7%E5%8F%8D%E5%8E%8B%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/</guid><description>&lt;p>Triple 是 Dubbo 3 提出的基于 HTTP2 的开放协议，
旨在解决 Dubbo 2 私有协议带来的互通性问题。
Triple 基于 HTTP/2 定制自己的流控，支持通过特定的异常通知客户端业务层服务端负载高情况，
保护了服务端被大流量击垮，提高系统高可用能力。&lt;/p>
&lt;h2 id="一流控反压现状">一、流控反压现状&lt;/h2>
&lt;p>客户端和服务器端在接收数据的时候有一个缓冲区来临时存储数据，
但是缓冲区的大小是有限制的，所以有可能会出现缓冲区溢出的情况，
HTTP 通过流控保护数据溢出丢失风险。&lt;/p>
&lt;h3 id="1http1-流控">1、HTTP/1 流控&lt;/h3>
&lt;p>在 HTTP/1.1 中，流量的控制依赖的是底层TCP协议，在客户端和服务器端建立连接的时候，
会使用系统默认的设置来建立缓冲区。在数据进行通信的时候，会告诉对方它的接收窗口的大小，
这个接收窗口就是缓冲区中剩余的可用空间。如果接收窗口大小为零，则说明接收方缓冲区已满，
则发送方将不再发送数据，直到客户端清除其内部缓冲区，然后请求恢复数据传输。&lt;/p>
&lt;h3 id="2http2-流控">2、HTTP/2 流控&lt;/h3>
&lt;p>HTTP/2 使用了多路复用机制，一个TCP连接可以有多个 HTTP/2 连接，
故在 HTTP/2 中，有更加精细的流控制机制，允许服务端实现自己数据流和连接级的流控制。
服务端与客户端第一次连接时，会通过发送 &lt;code>HTTP/2 SettingsFrame&lt;/code>设置初始化的流控窗口大小，
用于 &lt;code>Stream&lt;/code> 级别流控，默认为 65,535 字节。
定好流控窗口后，每次客户端发送数据就会减少流控窗口的大小，
服务端收到数据后会发送窗口更新包（&lt;code>WINDOW_UPDATE frame&lt;/code>）通知客户端更新窗口。
客户端收到窗口更新包后就会增加对应值的流控窗口，从而达到动态控制的目的。&lt;/p>
&lt;p>&lt;img alt="1.png" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/2022/12/28/triple/1.png">&lt;/p>
&lt;h2 id="二triple流控反压">二、Triple流控反压&lt;/h2>
&lt;p>Netty 基于 HTTP/2 实现了基础的流控，当服务端负载过高，客户端发送窗口为 0 时，
新增请求就无法被发送出去，会在缓存到客户端待发送请求队列中，缓存数据过大，
就会造成客户端内存溢出，影响业务程序。&lt;/p>
&lt;p>Triple 基于 Netty 实现了 HTTP/2 协议，通过 &lt;code>HTTP/2 FlowController&lt;/code>接口统一封装，
在实现分为进站（inbound）和出站（outbound）两个维度的实现。
Triple 在 inbound 流量上使用了 Netty 的默认流控实现，
在 outbound 上实现了自己流控，基于服务端负载，
将服务端流量压力透传到客户端业务层，实现客户端的业务反压，暂停业务继续发送请求，
保护服务端不被大流量击垮。&lt;/p></description></item><item><title>Triple 协议支持 Java 异常回传的设计与实现</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/12/19/triple-%E5%8D%8F%E8%AE%AE%E6%94%AF%E6%8C%81-java-%E5%BC%82%E5%B8%B8%E5%9B%9E%E4%BC%A0%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%AE%9E%E7%8E%B0/</link><pubDate>Mon, 19 Dec 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/12/19/triple-%E5%8D%8F%E8%AE%AE%E6%94%AF%E6%8C%81-java-%E5%BC%82%E5%B8%B8%E5%9B%9E%E4%BC%A0%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%AE%9E%E7%8E%B0/</guid><description>&lt;h2 id="背景">背景&lt;/h2>
&lt;p>在一些业务场景, 往往需要自定义异常来满足特定的业务, 主流用法是在catch里抛出异常, 例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">deal&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//doSomething &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ...
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span>(IGreeterException e) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ...
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> e;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>或者通过ExceptionBuilder，把相关的异常对象返回给consumer：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>provider.send(&lt;span style="color:#719e07">new&lt;/span> ExceptionBuilders.IGreeterExceptionBuilder()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .setDescription(&amp;#39;异常描述信息&amp;#39;); 
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在抛出异常后, 通过捕获和instanceof来判断特定的异常, 然后做相应的业务处理，例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> greeterProxy.echo(REQUEST_MSG);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#719e07">catch&lt;/span> (IGreeterException e) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//做相应的处理&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ...
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在 Dubbo 2.x 版本，可以通过上述方法来捕获 Provider 端的异常。
而随着云原生时代的到来， Dubbo 也开启了 3.0 的里程碑。&lt;/p>
&lt;p>Dubbo 3.0 的一个很重要的目标就是全面拥抱云原生，
在 3.0 的许多特性中，很重要的一个改动就是支持&lt;strong>新的一代Rpc协议Triple&lt;/strong>。&lt;/p>
&lt;p>Triple 协议基于 HTTP 2.0 进行构建，对网关的穿透性强，&lt;strong>兼容 gRPC&lt;/strong>，
提供 Request Response、Request Streaming、Response Streaming、
Bi-directional Streaming 等通信模型；
从 Triple 协议开始，Dubbo 还支持基于 IDL 的服务定义。&lt;/p></description></item><item><title>22-Dubbo3消费者自动感应决策应用级服务发现原理</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/22/22-dubbo3%E6%B6%88%E8%B4%B9%E8%80%85%E8%87%AA%E5%8A%A8%E6%84%9F%E5%BA%94%E5%86%B3%E7%AD%96%E5%BA%94%E7%94%A8%E7%BA%A7%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%E5%8E%9F%E7%90%86/</link><pubDate>Mon, 22 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/22/22-dubbo3%E6%B6%88%E8%B4%B9%E8%80%85%E8%87%AA%E5%8A%A8%E6%84%9F%E5%BA%94%E5%86%B3%E7%AD%96%E5%BA%94%E7%94%A8%E7%BA%A7%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%E5%8E%9F%E7%90%86/</guid><description>&lt;h1 id="22-dubbo3消费者自动感应决策应用级服务发现原理">22-Dubbo3消费者自动感应决策应用级服务发现原理&lt;/h1>
&lt;h2 id="221-简介">22.1 简介&lt;/h2>
&lt;p>这里要说的内容对Dubbo2迁移到Dubbo3的应用比较有帮助，消费者应用级服务发现做了一些自动决策的逻辑来决定当前消费者是应用级发现还是接口级服务发现，这里与前面说的提供者双注册的原理是对等的，提供者默认同时进行应用级注册和接口级注册，消费者对提供者注册的数据来决定使用应用级发现或者接口级发现。这些都是默认的行为，当然对于消费者来说还可以自定义其他的迁移规则，具体的需要我们详细来看逻辑。&lt;/p>
&lt;p>如果说对于迁移过程比较感兴趣可以直接去官网看文档相对来说还是比较清晰:&lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/docs/migration/migration-service-discovery/">https://dubbo.apache.org/zh-cn/docs/migration/migration-service-discovery/&lt;/a>&lt;/p>
&lt;p>这里再借官网的图来用用，迁移过程主要如下所示：
第一个图是提供者双注册的图：
&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/migration/provider-registration.png">&lt;/p>
&lt;p>第二个图是消费者订阅决策的图：
&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/migration/consumer-subscription.png">&lt;/p>
&lt;p>第三个图就是精确到消费者订阅的代码层的逻辑了，消费者服务间调用通过一个Invoker类型对象来进行对象，如下图所示消费者代理对象通过创建一个迁移容错的调用器对象来对应用级或者接口级订阅进行适配如下所示
&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/migration/migration-cluster-invoker.png">&lt;/p>
&lt;p>第二个图和第三个图是重点要关注的这一个文章的内容主要就是说这里的逻辑。&lt;/p>
&lt;p>关于代码位置如果不知道是如何调用到这一块逻辑的可以查看博文&lt;a href="https://blog.elastic.link/2022/07/10/dubbo/21-dubbo-xiao-fei-zhe-yin-yong-fu-wu-de-ru-kou/">《21-Dubbo3消费者引用服务入口》&lt;/a>&lt;/p>
&lt;p>这里直接将代码位置定位到：RegistryProtocol类型的interceptInvoker方法中：
如下所示：&lt;/p>
&lt;p>RegistryProtocol类型的interceptInvoker方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">protected&lt;/span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">interceptInvoker&lt;/span>(ClusterInvoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> invoker, URL url, URL consumerUrl) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//目前存在的扩展类型为RegistryProtocolListener监听器的实现类型MigrationRuleListener &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> List&lt;span style="color:#719e07">&amp;lt;&lt;/span>RegistryProtocolListener&lt;span style="color:#719e07">&amp;gt;&lt;/span> listeners &lt;span style="color:#719e07">=&lt;/span> findRegistryProtocolListeners(url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (CollectionUtils.isEmpty(listeners)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> invoker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (RegistryProtocolListener listener : listeners) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> listener.onRefer(&lt;span style="color:#719e07">this&lt;/span>, invoker, consumerUrl, url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> invoker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>该方法尝试加载所有RegistryProtocolListener定义，这些定义通过与定义的交互来控制调用器的行为，然后使用这些侦听器更改MigrationInvoker的状态和行为。当前可用的监听器是MigrationRuleListener，用于通过动态变化的规则控制迁移行为。&lt;/p>
&lt;h2 id="222-migrationrulelistener-类型的onrefer方法">22.2 MigrationRuleListener 类型的onRefer方法&lt;/h2>
&lt;p>直接来看代码：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">onRefer&lt;/span>(RegistryProtocol registryProtocol, ClusterInvoker&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> invoker, URL consumerUrl, URL registryURL) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//创建一个对应invoker对象的MigrationRuleHandler类型对象 然后将其存放在缓存Map&amp;lt;MigrationInvoker, MigrationRuleHandler&amp;gt;类型对象handles中&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> MigrationRuleHandler&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> migrationRuleHandler &lt;span style="color:#719e07">=&lt;/span> handlers.computeIfAbsent((MigrationInvoker&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span>) invoker, _key &lt;span style="color:#719e07">-&amp;gt;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ((MigrationInvoker&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span>) invoker).setMigrationRuleListener(&lt;span style="color:#719e07">this&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> MigrationRuleHandler&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>((MigrationInvoker&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span>) invoker, consumerUrl);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//迁移规则执行 rule是封装了迁移的配置规则的信息对应类型MigrationRule类型，在初始化对象的时候进行了配置初始化&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> migrationRuleHandler.doMigrate(rule);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>关于这个igrationRule的文可以直接看官方的文档比较详细：&lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/docs/advanced/migration-invoker/#1-%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%8B%E5%8F%91%E6%8E%A8%E8%8D%90">地址迁移规则说明&lt;/a>&lt;/p></description></item><item><title>21-Dubbo3消费者引用服务入口</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/21/21-dubbo3%E6%B6%88%E8%B4%B9%E8%80%85%E5%BC%95%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%85%A5%E5%8F%A3/</link><pubDate>Sun, 21 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/21/21-dubbo3%E6%B6%88%E8%B4%B9%E8%80%85%E5%BC%95%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%85%A5%E5%8F%A3/</guid><description>&lt;h1 id="21-dubbo3消费者引用服务入口">21-Dubbo3消费者引用服务入口&lt;/h1>
&lt;h2 id="211-简介">21.1 简介&lt;/h2>
&lt;p>前面我们通过Demo说了一个服务引用配置的创建。另外也在前面的文章说了服务提供者的启动完整过程，不过在说服务提供者启动的过程中并未提到服务消费者是如何发现服务，如果调用服务的，这里先就不再说关于服务消费者启动的一个细节了，直接来看前面未提到的服务消费者是如何引用到服务提供者提供的服务的。
先来回顾下样例代码：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">ConsumerApplication&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">main&lt;/span>(String&lt;span style="color:#719e07">[]&lt;/span> args) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> runWithBootstrap();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">runWithBootstrap&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ReferenceConfig&lt;span style="color:#719e07">&amp;lt;&lt;/span>DemoService&lt;span style="color:#719e07">&amp;gt;&lt;/span> reference &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ReferenceConfig&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> reference.setInterface(DemoService.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> reference.setGeneric(&lt;span style="color:#2aa198">&amp;#34;true&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> reference.setProtocol(&lt;span style="color:#2aa198">&amp;#34;&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> DubboBootstrap bootstrap &lt;span style="color:#719e07">=&lt;/span> DubboBootstrap.getInstance();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ApplicationConfig applicationConfig &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ApplicationConfig(&lt;span style="color:#2aa198">&amp;#34;dubbo-demo-api-consumer&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> applicationConfig.setQosEnable(&lt;span style="color:#cb4b16">false&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> applicationConfig.setQosPort(&lt;span style="color:#719e07">-&lt;/span>1);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> bootstrap.application(applicationConfig)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .registry(&lt;span style="color:#719e07">new&lt;/span> RegistryConfig(&lt;span style="color:#2aa198">&amp;#34;zookeeper://8.131.79.126:2181&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .protocol(&lt;span style="color:#719e07">new&lt;/span> ProtocolConfig(CommonConstants.DUBBO, &lt;span style="color:#719e07">-&lt;/span>1))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .reference(reference)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .start();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> DemoService demoService &lt;span style="color:#719e07">=&lt;/span> bootstrap.getCache().get(reference);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String message &lt;span style="color:#719e07">=&lt;/span> demoService.sayHello(&lt;span style="color:#2aa198">&amp;#34;dubbo&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> System.out.println(message);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// generic invoke&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> GenericService genericService &lt;span style="color:#719e07">=&lt;/span> (GenericService) demoService;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Object genericInvokeResult &lt;span style="color:#719e07">=&lt;/span> genericService.$invoke(&lt;span style="color:#2aa198">&amp;#34;sayHello&amp;#34;&lt;/span>, &lt;span style="color:#719e07">new&lt;/span> String&lt;span style="color:#719e07">[]&lt;/span>{String.class.getName()},
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">new&lt;/span> Object&lt;span style="color:#719e07">[]&lt;/span>{&lt;span style="color:#2aa198">&amp;#34;dubbo generic invoke&amp;#34;&lt;/span>});
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> System.out.println(genericInvokeResult);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这段代码我们前面详细说了服务引用的配置ReferenceConfig和Dubbo启动器启动应用的过程DubboBootstrap，后面我们直接定位到消费者引用服务的代码位置来看。&lt;/p></description></item><item><title>20-Dubbo3服务引用配置ReferenceConfig</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/20/20-dubbo3%E6%9C%8D%E5%8A%A1%E5%BC%95%E7%94%A8%E9%85%8D%E7%BD%AEreferenceconfig/</link><pubDate>Sat, 20 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/20/20-dubbo3%E6%9C%8D%E5%8A%A1%E5%BC%95%E7%94%A8%E9%85%8D%E7%BD%AEreferenceconfig/</guid><description>&lt;h1 id="20-dubbo3服务引用配置referenceconfig">20-Dubbo3服务引用配置ReferenceConfig&lt;/h1>
&lt;h2 id="201-简介">20.1 简介&lt;/h2>
&lt;p>前面简单介绍了一下消费者的例子，消费者创建的第一步就是先进行消费者信息的配置对应类型为ReferenceConfig，这里详细来看ReferenceConfig包含哪些信息？先简单了解下消费者配置的类型关系如下图所示：引用配置与服务配置类型都是通过继承接口配置来扩展的，在分析生产者的时候详细介绍过服务相关的配置，这里来详细看消费者引用者的相关配置信息.
&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/source-blog/20-refe.png">&lt;/p>
&lt;p>前面例子说了消费者配置对象的创建主要是通过如下代码：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>ReferenceConfig&lt;span style="color:#719e07">&amp;lt;&lt;/span>DemoService&lt;span style="color:#719e07">&amp;gt;&lt;/span> reference &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ReferenceConfig&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个配置类型的对象创建过程并没有太多的逻辑这里主要来说下各种配置信息：
服务消费者引用服务配置。对应的配置类： &lt;code>org.apache.dubbo.config.ReferenceConfig&lt;/code>&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">属性&lt;/th>
 &lt;th style="text-align: left">对应URL参数&lt;/th>
 &lt;th style="text-align: left">类型&lt;/th>
 &lt;th style="text-align: left">是否必填&lt;/th>
 &lt;th style="text-align: left">缺省值&lt;/th>
 &lt;th style="text-align: left">作用&lt;/th>
 &lt;th style="text-align: left">描述&lt;/th>
 &lt;th style="text-align: left">兼容性&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">id&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">&lt;strong>必填&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">配置关联&lt;/td>
 &lt;td style="text-align: left">服务引用BeanId&lt;/td>
 &lt;td style="text-align: left">1.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">interface&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">class&lt;/td>
 &lt;td style="text-align: left">&lt;strong>必填&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务发现&lt;/td>
 &lt;td style="text-align: left">服务接口名&lt;/td>
 &lt;td style="text-align: left">1.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">version&lt;/td>
 &lt;td style="text-align: left">version&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务发现&lt;/td>
 &lt;td style="text-align: left">服务版本，与服务提供者的版本一致&lt;/td>
 &lt;td style="text-align: left">1.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">group&lt;/td>
 &lt;td style="text-align: left">group&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务发现&lt;/td>
 &lt;td style="text-align: left">服务分组，当一个接口有多个实现，可以用分组区分，必需和服务提供方一致&lt;/td>
 &lt;td style="text-align: left">1.0.7以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">timeout&lt;/td>
 &lt;td style="text-align: left">timeout&lt;/td>
 &lt;td style="text-align: left">long&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">缺省使用&lt;code>&amp;lt;dubbo:consumer&amp;gt;&lt;/code>的timeout&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">服务方法调用超时时间(毫秒)&lt;/td>
 &lt;td style="text-align: left">1.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">retries&lt;/td>
 &lt;td style="text-align: left">retries&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">缺省使用&lt;code>&amp;lt;dubbo:consumer&amp;gt;&lt;/code>的retries&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">远程服务调用重试次数，不包括第一次调用，不需要重试请设为0&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">connections&lt;/td>
 &lt;td style="text-align: left">connections&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">缺省使用&lt;code>&amp;lt;dubbo:consumer&amp;gt;&lt;/code>的connections&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">对每个提供者的最大连接数，rmi、http、hessian等短连接协议表示限制连接数，dubbo等长连接协表示建立的长连接个数&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">loadbalance&lt;/td>
 &lt;td style="text-align: left">loadbalance&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">缺省使用&lt;code>&amp;lt;dubbo:consumer&amp;gt;&lt;/code>的loadbalance&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">负载均衡策略，可选值：random,roundrobin,leastactive，分别表示：随机，轮询，最少活跃调用&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">async&lt;/td>
 &lt;td style="text-align: left">async&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">缺省使用&lt;code>&amp;lt;dubbo:consumer&amp;gt;&lt;/code>的async&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">是否异步执行，不可靠异步，只是忽略返回值，不阻塞执行线程&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">generic&lt;/td>
 &lt;td style="text-align: left">generic&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">缺省使用&lt;code>&amp;lt;dubbo:consumer&amp;gt;&lt;/code>的generic&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">是否缺省泛化接口，如果为泛化接口，将返回GenericService&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">check&lt;/td>
 &lt;td style="text-align: left">check&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">缺省使用&lt;code>&amp;lt;dubbo:consumer&amp;gt;&lt;/code>的check&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">启动时检查提供者是否存在，true报错，false忽略&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">url&lt;/td>
 &lt;td style="text-align: left">url&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">点对点直连服务提供者地址，将绕过注册中心&lt;/td>
 &lt;td style="text-align: left">1.0.6以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">stub&lt;/td>
 &lt;td style="text-align: left">stub&lt;/td>
 &lt;td style="text-align: left">class/boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">服务接口客户端本地代理类名，用于在客户端执行本地逻辑，如本地缓存等，该本地代理类的构造函数必须允许传入远程代理对象，构造函数如：public XxxServiceLocal(XxxService xxxService)&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">mock&lt;/td>
 &lt;td style="text-align: left">mock&lt;/td>
 &lt;td style="text-align: left">class/boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">服务接口调用失败Mock实现类名，该Mock类必须有一个无参构造函数，与Local的区别在于，Local总是被执行，而Mock只在出现非业务异常(比如超时，网络异常等)时执行，Local在远程调用之前执行，Mock在远程调用后执行。&lt;/td>
 &lt;td style="text-align: left">Dubbo1.0.13及其以上版本支持&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">cache&lt;/td>
 &lt;td style="text-align: left">cache&lt;/td>
 &lt;td style="text-align: left">string/boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">以调用参数为key，缓存返回结果，可选：lru, threadlocal, jcache等&lt;/td>
 &lt;td style="text-align: left">Dubbo2.1.0及其以上版本支持&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">validation&lt;/td>
 &lt;td style="text-align: left">validation&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">是否启用JSR303标准注解验证，如果启用，将对方法参数上的注解进行校验&lt;/td>
 &lt;td style="text-align: left">Dubbo2.1.0及其以上版本支持&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">proxy&lt;/td>
 &lt;td style="text-align: left">proxy&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">javassist&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">选择动态代理实现策略，可选：javassist, jdk&lt;/td>
 &lt;td style="text-align: left">2.0.2以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">client&lt;/td>
 &lt;td style="text-align: left">client&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">客户端传输类型设置，如Dubbo协议的netty或mina。&lt;/td>
 &lt;td style="text-align: left">Dubbo2.0.0以上版本支持&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">registry&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">缺省将从所有注册中心获服务列表后合并结果&lt;/td>
 &lt;td style="text-align: left">配置关联&lt;/td>
 &lt;td style="text-align: left">从指定注册中心注册获取服务列表，在多个注册中心时使用，值为&lt;code>&amp;lt;dubbo:registry&amp;gt;&lt;/code>的id属性，多个注册中心ID用逗号分隔&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">owner&lt;/td>
 &lt;td style="text-align: left">owner&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">调用服务负责人，用于服务治理，请填写负责人公司邮箱前缀&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">actives&lt;/td>
 &lt;td style="text-align: left">actives&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">0&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">每服务消费者每服务每方法最大并发调用数&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">cluster&lt;/td>
 &lt;td style="text-align: left">cluster&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">failover&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">集群方式，可选：failover/failfast/failsafe/failback/forking&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">filter&lt;/td>
 &lt;td style="text-align: left">reference.filter&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">default&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">服务消费方远程调用过程拦截器名称，多个名称用逗号分隔&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">listener&lt;/td>
 &lt;td style="text-align: left">invoker.listener&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">default&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">服务消费方引用服务监听器名称，多个名称用逗号分隔&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">layer&lt;/td>
 &lt;td style="text-align: left">layer&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">服务调用者所在的分层。如：biz、dao、intl:web、china:acton。&lt;/td>
 &lt;td style="text-align: left">2.0.7以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">init&lt;/td>
 &lt;td style="text-align: left">init&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">false&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">是否在afterPropertiesSet()时饥饿初始化引用，否则等到有人注入或引用该实例时再初始化。&lt;/td>
 &lt;td style="text-align: left">2.0.10以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">protocol&lt;/td>
 &lt;td style="text-align: left">protocol&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">只调用指定协议的服务提供方，其它协议忽略。&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>原文地址：&lt;a href="https://blog.elastic.link/2022/07/10/dubbo/20-dubbo3-fu-wu-yin-yong-pei-zhi-referenceconfig/">20-Dubbo3服务引用配置ReferenceConfig&lt;/a>&lt;/p></description></item><item><title>19 重新来过从一个服务消费者的Demo说起</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/19/19-%E9%87%8D%E6%96%B0%E6%9D%A5%E8%BF%87%E4%BB%8E%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%E7%9A%84demo%E8%AF%B4%E8%B5%B7/</link><pubDate>Fri, 19 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/19/19-%E9%87%8D%E6%96%B0%E6%9D%A5%E8%BF%87%E4%BB%8E%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%E7%9A%84demo%E8%AF%B4%E8%B5%B7/</guid><description>&lt;h1 id="19-重新来过从一个服务消费者的demo说起">19 重新来过从一个服务消费者的Demo说起&lt;/h1>
&lt;p>为了更方便了解原理,我们先来编写一个Demo,从例子中来看源码实现:，前面说了提供者现在已经有服务注册上去了，那接下来我们编写一个消费者的例子来进行服务发现与服务RPC调用。&lt;/p>
&lt;h2 id="191-启动zookeeper">19.1 启动Zookeeper&lt;/h2>
&lt;p>为了Demo可以正常启动,需要我们先在本地启动一个Zookeeper如下图所示:
&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/source-blog/19-zk.png">&lt;/p>
&lt;h2 id="192-服务消费者">19.2 服务消费者&lt;/h2>
&lt;p>接下来给大家贴一下示例源码,这个源码来源于Dubbo源码目录的	dubbo-demo/dubbo-demo-api 目录下面的dubbo-demo-api-consumer子项目,这里我做了删减,方便看核心代码:
首先我们定义一个服务接口如下所示:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> java.util.concurrent.CompletableFuture;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">interface&lt;/span> &lt;span style="color:#268bd2">DemoService&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 同步处理的服务方法
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param name
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String &lt;span style="color:#268bd2">sayHello&lt;/span>(String name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 用于异步处理的服务方法
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param name
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">default&lt;/span> CompletableFuture&lt;span style="color:#719e07">&amp;lt;&lt;/span>String&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">sayHelloAsync&lt;/span>(String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> CompletableFuture.completedFuture(sayHello(name));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>服务实现类如下:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.RpcContext;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.slf4j.Logger;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.slf4j.LoggerFactory;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> java.util.concurrent.CompletableFuture;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">DemoServiceImpl&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> DemoService {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> &lt;span style="color:#268bd2">final&lt;/span> Logger logger &lt;span style="color:#719e07">=&lt;/span> LoggerFactory.getLogger(DemoServiceImpl.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> String &lt;span style="color:#268bd2">sayHello&lt;/span>(String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.info(&lt;span style="color:#2aa198">&amp;#34;Hello &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> name &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, request from consumer: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> RpcContext.getServiceContext().getRemoteAddress());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#2aa198">&amp;#34;Hello &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> name &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, response from provider: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> RpcContext.getServiceContext().getLocalAddress();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> CompletableFuture&lt;span style="color:#719e07">&amp;lt;&lt;/span>String&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">sayHelloAsync&lt;/span>(String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="193-启用服务消费者">19.3 启用服务消费者&lt;/h2>
&lt;p>有了服务接口之后我们来启用服务,启用服务的源码如下:
这里如果要启动消费者,主要要修改QOS端口这里我已经配置可以直接复用&lt;/p></description></item><item><title>18-Dubbo3元数据服务MetadataService的导出</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/18/18-dubbo3%E5%85%83%E6%95%B0%E6%8D%AE%E6%9C%8D%E5%8A%A1metadataservice%E7%9A%84%E5%AF%BC%E5%87%BA/</link><pubDate>Thu, 18 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/18/18-dubbo3%E5%85%83%E6%95%B0%E6%8D%AE%E6%9C%8D%E5%8A%A1metadataservice%E7%9A%84%E5%AF%BC%E5%87%BA/</guid><description>&lt;h1 id="18-dubbo3元数据服务metadataservice的导出">18-Dubbo3元数据服务MetadataService的导出&lt;/h1>
&lt;h2 id="181-简介">18.1 简介&lt;/h2>
&lt;p>MetadataService
此服务用于公开Dubbo进程内的元数据信息。典型用途包括：&lt;/p>
&lt;ul>
&lt;li>使用者查询提供者的元数据信息，以列出接口和每个接口的配置&lt;/li>
&lt;li>控制台（dubbo admin）查询特定进程的元数据，或聚合所有进程的数据。在Dubbo2.x的时候，所有的服务数据都是以接口的形式注册在注册中心.&lt;/li>
&lt;/ul>
&lt;p>Dubbo3将部分数据抽象为元数据的形式来将数据存放在元数据中心，然后元数据由服务提供者提供给消费者而不是再由注册中心进行推送，如下图所示：&lt;/p>
&lt;p>&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/source-blog/18-metadata.png">&lt;/p>
&lt;p>&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/source-blog/18-metadata3.png">
引入 MetadataService 元数据服务服务的好处
• 由中心化推送转向点对点拉取（Consumer - Proroder）
• 易于扩展更多的参数
• 更多的数据量
• 对外暴露更多的治理数据&lt;/p>
&lt;h2 id="182-metadataservice的导出过程">18.2 MetadataService的导出过程&lt;/h2>
&lt;p>了解元数据的到处过程，这个就要继续前面博客往后的代码了前面博客说了一个服务发布之后的服务信息的双注册数据，这里继续看下导出服务之后的代码：
先来简单回顾下模块发布的启动生命周期方法：&lt;/p>
&lt;p>DefaultModuleDeployer类型的start方法：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">synchronized&lt;/span> Future &lt;span style="color:#268bd2">start&lt;/span>() &lt;span style="color:#268bd2">throws&lt;/span> IllegalStateException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ...
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ...
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> onModuleStarting();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// initialize&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> applicationDeployer.initialize();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> initialize();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// export services&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exportServices();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// prepare application instance&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// exclude internal module to avoid wait itself&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (moduleModel &lt;span style="color:#719e07">!=&lt;/span> moduleModel.getApplicationModel().getInternalModule()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> applicationDeployer.prepareInternalModule();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// refer services&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> referServices();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// if no async export/refer services, just set started&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (asyncExportingFutures.isEmpty() &lt;span style="color:#719e07">&amp;amp;&amp;amp;&lt;/span> asyncReferringFutures.isEmpty()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> onModuleStarted();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ....
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> startFuture;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>前面的博客我们已经说了服务提供者导出服务的方法如下：&lt;/p></description></item><item><title>17-Dubbo服务提供者的双注册原理</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/17/17-dubbo%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84%E5%8F%8C%E6%B3%A8%E5%86%8C%E5%8E%9F%E7%90%86/</link><pubDate>Wed, 17 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/17/17-dubbo%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84%E5%8F%8C%E6%B3%A8%E5%86%8C%E5%8E%9F%E7%90%86/</guid><description>&lt;h1 id="17-dubbo服务提供者的双注册原理">17-Dubbo服务提供者的双注册原理&lt;/h1>
&lt;h2 id="171-简介">17.1 简介&lt;/h2>
&lt;p>上个博客&lt;a href="https://blog.elastic.link/2022/07/10/dubbo/15-dubbo-de-san-da-zhong-xin-zhi-yuan-shu-ju-zhong-xin-yuan-ma-jie-xi/">《15-Dubbo的三大中心之元数据中心源码解析》&lt;/a>导出服务端的时候多次提到了元数据中心，注册信息的注册。
Dubbo3出来时间不太长，对于现在的用户来说大部分使用的仍旧是Dubbo2.x，
Dubbo3 比较有特色也是会直接使用到的功能就是&lt;strong>应用级服务发现&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>应用级服务发现
&lt;em>从服务/接口粒度到应用粒度的升级，使得 Dubbo 在集群可伸缩性、连接异构微服务体系上更具优势。应用粒度能以更低的资源消耗支持超百万实例规模集群程； 实现与 Spring Cloud、Kubernetes Service 等异构微服务体系的互联互通。&lt;/em>&lt;/li>
&lt;/ul>
&lt;p>对于直接使用Dubbo3的用户还好，可以仅仅开启应用级注册，但是对于Dubbo2.x的用户升级到Dubbo3的用户来说前期都是要开启双注册来慢慢迁移的，既注册传统的接口信息到注册中心，又注册应用信息到注册中心，同时注册应用与接口关系的元数据信息。
关于双注册与服务迁移的过程的使用可以参考官网：
&lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/docs/migration/migration-service-discovery/">应用级地址发现迁移指南&lt;/a>&lt;/p>
&lt;p>关于官网提供者双注册的图我这里贴一下，方便了解：
&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/migration/provider-registration.png">&lt;/p>
&lt;h2 id="172-双注册配置的读取">17.2 双注册配置的读取&lt;/h2>
&lt;h3 id="1721-注册中心地址作为元数据中心">17.2.1 注册中心地址作为元数据中心&lt;/h3>
&lt;p>这个配置的解析过程在前面的博客介绍元数据中心的时候很详细的说了相关链接：&lt;a href="https://blog.elastic.link/2022/07/10/dubbo/15-dubbo-de-san-da-zhong-xin-zhi-yuan-shu-ju-zhong-xin-yuan-ma-jie-xi/">15-Dubbo的三大中心之元数据中心源码解析&lt;/a>&lt;/p>
&lt;p>对应代码位于：DefaultApplicationDeployer类型的startMetadataCenter()方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">startMetadataCenter&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#586e75">//如果未配置元数据中心的地址等配置则使用注册中心的地址等配置做为元数据中心的配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> useRegistryAsMetadataCenterIfNecessary();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//...省略掉其他代码防止受到干扰&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>具体逻辑是这个方法：
useRegistryAsMetadataCenterIfNecessary&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">useRegistryAsMetadataCenterIfNecessary&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#586e75">//配置缓存中查询元数据配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Collection&lt;span style="color:#719e07">&amp;lt;&lt;/span>MetadataReportConfig&lt;span style="color:#719e07">&amp;gt;&lt;/span> metadataConfigs &lt;span style="color:#719e07">=&lt;/span> configManager.getMetadataConfigs();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//...省略掉空判断&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#586e75">//查询是否有注册中心设置了默认配置isDefault 设置为true的注册中心则为默认注册中心列表,如果没有注册中心设置为默认注册中心,则获取所有未设置默认配置的注册中心列表&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> List&lt;span style="color:#719e07">&amp;lt;&lt;/span>RegistryConfig&lt;span style="color:#719e07">&amp;gt;&lt;/span> defaultRegistries &lt;span style="color:#719e07">=&lt;/span> configManager.getDefaultRegistries();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (defaultRegistries.size() &lt;span style="color:#719e07">&amp;gt;&lt;/span> 0) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//多注册中心遍历&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> defaultRegistries
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .stream()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//筛选符合条件的注册中心 (筛选逻辑就是查看是否有对应协议的扩展支持)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .filter(&lt;span style="color:#719e07">this&lt;/span>::isUsedRegistryAsMetadataCenter)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//注册中心配置映射为元数据中心 映射就是获取需要的配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .map(&lt;span style="color:#719e07">this&lt;/span>::registryAsMetadataCenter)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//将元数据中心配置存储在配置缓存中方便后续使用&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .forEach(metadataReportConfig &lt;span style="color:#719e07">-&amp;gt;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//...省略掉具体的逻辑&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>关于元数据中心地址的获取，主要经过如下逻辑：&lt;/p></description></item><item><title>16-模块发布器发布服务全过程</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/16/16-%E6%A8%A1%E5%9D%97%E5%8F%91%E5%B8%83%E5%99%A8%E5%8F%91%E5%B8%83%E6%9C%8D%E5%8A%A1%E5%85%A8%E8%BF%87%E7%A8%8B/</link><pubDate>Tue, 16 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/16/16-%E6%A8%A1%E5%9D%97%E5%8F%91%E5%B8%83%E5%99%A8%E5%8F%91%E5%B8%83%E6%9C%8D%E5%8A%A1%E5%85%A8%E8%BF%87%E7%A8%8B/</guid><description>&lt;h1 id="16-模块发布器发布服务全过程">16-模块发布器发布服务全过程&lt;/h1>
&lt;h2 id="161-简介">16.1 简介&lt;/h2>
&lt;p>Dubbo做为服务治理框架,比较核心的就是服务相关的概念,这里我先贴个找到的关于Dubbo工作原理的架构图:
&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/source-blog/16-deploy.png">
如果按完整服务启动与订阅的顺序我们可以归结为以下6点:&lt;/p>
&lt;ul>
&lt;li>导出服务(提供者)
&lt;ul>
&lt;li>服务提供方通过指定端口对外暴露服务&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>注册服务(提供者)
&lt;ul>
&lt;li>提供方向注册中心注册自己的信息&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>(服务发现)-订阅服务(消费者)
&lt;ul>
&lt;li>服务调用方通过注册中心订阅自己感兴趣的服务&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>(服务发现)-服务推送(消费者)
&lt;ul>
&lt;li>注册中心向调用方推送地址列表&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>调用服务(消费者调用提供者)
&lt;ul>
&lt;li>调用方选择一个地址发起RPC调用&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>监控服务
&lt;ul>
&lt;li>服务提供方和调用方的统计数据由监控模块收集展示&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>上面的完整的服务启动订阅与调用流程不仅仅适用于Dubbo 同样也适用于其他服务治理与发现的模型, 一般服务发现与服务调用的思路就是这样的,我们将以上内容扩展,暴漏服务可以使用http,tcp,udp等各种协议,注册服务可以注册到Redis,Dns,Etcd,Zookeeper等注册中心中,订阅服务可以主动去注册中心查询服务列表,服务发现可以让注册中心将服务数据动态推送给消费者.Dubbo其实就是基于这种简单的服务模型来扩展出各种功能的支持,来满足服务治理的各种场景,了解了这里可能各位同学就想着自行开发一个简单的微服务框架了。&lt;/p>
&lt;p>回到主题,从以上的服务完整发布调用流程可以看到,所有的功能都是由导出服务(提供者)开始的,只有提供者先提供了服务才可以有真正的服务让消费者调用。&lt;/p>
&lt;p>之前的博客内容 链接:&lt;a href="https://blog.elastic.link/2022/07/10/dubbo/12-quan-ju-shi-ye-lai-kan-dubbo3.0.8-de-fu-wu-qi-dong-sheng-ming-zhou-qi/">&amp;laquo;12-全局视野来看Dubbo3.0.8的服务启动生命周期&amp;raquo;&lt;/a> 我们了解了 DefaultModuleDeployer模块器启动的流程,其中在start代码的模版方法中开始了导出服务的功能,这里我们来详细看下服务发布的全过程:&lt;/p>
&lt;p>入口代码: DefaultModuleDeployer的发布服务方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">exportServices&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 		&lt;span style="color:#586e75">//从配置管缓存中查询缓存的所有的服务配置然后逐个服务发布&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (ServiceConfigBase sc : configManager.getServices()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exportServiceInternal(sc);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="162-导出服务的入口">16.2 导出服务的入口&lt;/h2>
&lt;p>入口代码: DefaultModuleDeployer的发布服务方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">exportServices&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 		&lt;span style="color:#586e75">//从配置管缓存中查询缓存的所有的服务配置然后逐个服务发布&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (ServiceConfigBase sc : configManager.getServices()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exportServiceInternal(sc);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>主要流程为遍历初始化的服务配置列表然后逐个服务开始到处
内部导出服务代码:
exportServiceInternal方法:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">exportServiceInternal&lt;/span>(ServiceConfigBase sc) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> serviceConfig &lt;span style="color:#719e07">=&lt;/span> (ServiceConfig&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span>) sc;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//服务配置刷新 配置优先级覆盖&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (&lt;span style="color:#719e07">!&lt;/span>serviceConfig.isRefreshed()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serviceConfig.refresh();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//服务已经导出过了就直接返回&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (sc.isExported()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//是否异步方式导出 全局配置或者服务级其中一个配置了异步则异步处理&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (exportAsync &lt;span style="color:#719e07">||&lt;/span> sc.shouldExportAsync()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//异步其实就是使用线程来导出服务serviceExportExecutor&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ExecutorService executor &lt;span style="color:#719e07">=&lt;/span> executorRepository.getServiceExportExecutor();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CompletableFuture&lt;span style="color:#719e07">&amp;lt;&lt;/span>Void&lt;span style="color:#719e07">&amp;gt;&lt;/span> future &lt;span style="color:#719e07">=&lt;/span> CompletableFuture.runAsync(() &lt;span style="color:#719e07">-&amp;gt;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (&lt;span style="color:#719e07">!&lt;/span>sc.isExported()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sc.export();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exportedServices.add(sc);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Throwable t) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.error(getIdentifier() &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34; export async catch error : &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> t.getMessage(), t);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }, executor);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> asyncExportingFutures.add(future);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#586e75">//同步导出服务&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (&lt;span style="color:#719e07">!&lt;/span>sc.isExported()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sc.export();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exportedServices.add(sc);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个逻辑里面做了一些基本的操作,可以直接看注释然后调用ServiceConfig的export的来导出服务,继续往后看服务配置的导出服务方法。&lt;/p></description></item><item><title>15-Dubbo的三大中心之元数据中心源码解析</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/15/15-dubbo%E7%9A%84%E4%B8%89%E5%A4%A7%E4%B8%AD%E5%BF%83%E4%B9%8B%E5%85%83%E6%95%B0%E6%8D%AE%E4%B8%AD%E5%BF%83%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/</link><pubDate>Mon, 15 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/15/15-dubbo%E7%9A%84%E4%B8%89%E5%A4%A7%E4%B8%AD%E5%BF%83%E4%B9%8B%E5%85%83%E6%95%B0%E6%8D%AE%E4%B8%AD%E5%BF%83%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/</guid><description>&lt;h1 id="15-dubbo的三大中心之元数据中心源码解析">15-Dubbo的三大中心之元数据中心源码解析&lt;/h1>
&lt;h2 id="151-简介">15.1 简介&lt;/h2>
&lt;p>关于元数据中心的概念对于大部分用户来说是比较陌生的,配置中心的话我们还好理解,对于元数据中心是什么,我们来看下我从官网拷贝过来的一段文字:&lt;/p>
&lt;p>元数据中心在2.7.x版本开始支持，随着应用级别的服务注册和服务发现在Dubbo中落地，&lt;strong>元数据中心也变的越来越重要&lt;/strong>。在以下几种情况下会需要部署元数据中心：&lt;/p>
&lt;ul>
&lt;li>对于一个原先采用老版本Dubbo搭建的应用服务，在迁移到Dubbo 3时，Dubbo 3 会需要一个&lt;strong>元数据中心来维护RPC服务与应用的映射关系（即接口与应用的映射关系）&lt;/strong>，因为如果采用了&lt;strong>应用级别的服务发现和服务注册&lt;/strong>，在注册中心中将&lt;strong>采用“应用 —— 实例列表”结构&lt;/strong>的数据组织形式，&lt;strong>不再是以往的“接口 —— 实例列表”结构的数据组织形式&lt;/strong>，而以往用接口级别的服务注册和服务发现的应用服务在&lt;strong>迁移到应用级别&lt;/strong>时，&lt;strong>得不到接口与应用之间的对应关系&lt;/strong>，从而无法从注册中心得到实例列表信息，所以&lt;strong>Dubbo为了兼容这种场景，在Provider端启动时，会往元数据中心存储接口与应用的映射关系&lt;/strong>。&lt;/li>
&lt;li>为了让&lt;strong>注册中心更加聚焦与地址的发现和推送能力&lt;/strong>，&lt;strong>减轻注册中心的负担&lt;/strong>，元数据中心承载了所有的服务元数据、大量接口/方法级别配置信息等，无论是接口粒度还是应用粒度的服务发现和注册，元数据中心都起到了重要的作用。&lt;/li>
&lt;li>如果有以上两种需求，都可以选择部署元数据中心，并通过Dubbo的配置来集成该元数据中心。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>元数据中心并不依赖于注册中心和配置中心&lt;/strong>，用户可以自由选择是否集成和部署元数据中心，如下图所示：&lt;/p>
&lt;p>&lt;img alt="/imgs/v3/concepts/centers-metadata.png" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/concepts/centers-metadata.png">&lt;/p>
&lt;p>该图中不配备配置中心，意味着可以不需要全局管理配置的能力。该图中不配备注册中心，意味着可能采用了Dubbo mesh的方案，也可能不需要进行服务注册，仅仅接收直连模式的服务调用。
官网参考文章地址:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/docs/concepts/registry-configcenter-metadata/">部署架构（注册中心 配置中心 元数据中心&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/docs/references/metadata/">元数据参考手册&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>综上所述可以用几句话概括下:&lt;/p>
&lt;ul>
&lt;li>元数据中心来维护RPC服务与应用的映射关系（即接口与应用的映射关系）来兼容接口与应用之间的对应关系&lt;/li>
&lt;li>让注册中心更加聚焦与地址的发现和推送能力&lt;/li>
&lt;/ul>
&lt;p>元数据中心的启动是在DefaultApplicationDeployer中的初始化方法 initialize() 中:如下所示&lt;/p>
&lt;p>这里只看下 startMetadataCenter();方法即可&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">initialize&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (initialized) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// Ensure that the initialization is completed when concurrent calls&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">synchronized&lt;/span> (startLock) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (initialized) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// register shutdown hook&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> registerShutdownHook();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> startConfigCenter();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> loadApplicationConfigs();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> initModuleDeployers();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// @since 2.7.8&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> startMetadataCenter();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> initialized &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#cb4b16">true&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (logger.isInfoEnabled()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.info(getIdentifier() &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34; has been initialized!&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="152-深入探究元数据中心的启动过程">15.2 深入探究元数据中心的启动过程&lt;/h2>
&lt;h3 id="1521-启动元数据中心的代码全貌">15.2.1 启动元数据中心的代码全貌&lt;/h3>
&lt;p>关于元数据中心我们看下 startMetadataCenter()方法来大致了解下整个流程&lt;/p></description></item><item><title>14-Dubbo配置加载全解析</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/14/14-dubbo%E9%85%8D%E7%BD%AE%E5%8A%A0%E8%BD%BD%E5%85%A8%E8%A7%A3%E6%9E%90/</link><pubDate>Sun, 14 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/14/14-dubbo%E9%85%8D%E7%BD%AE%E5%8A%A0%E8%BD%BD%E5%85%A8%E8%A7%A3%E6%9E%90/</guid><description>&lt;h1 id="14-dubbo配置加载全解析">14-Dubbo配置加载全解析&lt;/h1>
&lt;h2 id="141-回到启动器的初始化过程">14.1 回到启动器的初始化过程&lt;/h2>
&lt;p>在应用程序启动的时候会调用发布器的启动方法 ,然后调用初始化方法,在发布器DefaultApplicationDeployer中的初始化方法initialize() 如下:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">initialize&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (initialized) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// Ensure that the initialization is completed when concurrent calls&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">synchronized&lt;/span> (startLock) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (initialized) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// register shutdown hook&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> registerShutdownHook();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> startConfigCenter();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> loadApplicationConfigs();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> initModuleDeployers();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// @since 2.7.8&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> startMetadataCenter();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> initialized &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#cb4b16">true&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (logger.isInfoEnabled()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.info(getIdentifier() &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34; has been initialized!&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>初始化过程中会先启动配置中心配置信息处理,然后 调用加载初始化应用程序配置方法loadApplicationConfigs();进行配置加载
关于配置的官方文档链接为 &lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/docs/references/configuration/overview/">配置概述&lt;/a>&lt;/p></description></item><item><title>13-Dubbo的三大中心之配置中心</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/13/13-dubbo%E7%9A%84%E4%B8%89%E5%A4%A7%E4%B8%AD%E5%BF%83%E4%B9%8B%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83/</link><pubDate>Sat, 13 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/13/13-dubbo%E7%9A%84%E4%B8%89%E5%A4%A7%E4%B8%AD%E5%BF%83%E4%B9%8B%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83/</guid><description>&lt;h1 id="13-dubbo的三大中心之配置中心">13-Dubbo的三大中心之配置中心&lt;/h1>
&lt;h2 id="131-配置中心简介">13.1 配置中心简介&lt;/h2>
&lt;p>百度了一段不错的文字来介绍配置中心，我看了下肯定比我写的好多了，那我就直接拷贝过来一起看：&lt;/p>
&lt;p>&lt;em>对于传统的单体应用而言，常使用配置文件来管理所有配置，比如SpringBoot的application.yml文件，但是在微服务架构中全部手动修改的话很麻烦而且不易维护。微服务的配置管理一般有以下需求：&lt;/em>&lt;/p>
&lt;ul>
&lt;li>&lt;em>&lt;strong>集中配置管理&lt;/strong>，一个微服务架构中可能有成百上千个微服务，所以集中配置管理是很重要的。&lt;/em>&lt;/li>
&lt;li>&lt;em>&lt;strong>不同环境不同配置&lt;/strong>，比如数据源配置在不同环境（开发，生产，测试）中是不同的。&lt;/em>&lt;/li>
&lt;li>&lt;em>&lt;strong>运行期间可动态调整&lt;/strong>。例如，可根据各个微服务的负载情况，动态调整数据源连接池大小等。&lt;/em>&lt;/li>
&lt;li>&lt;em>&lt;strong>配置修改后可自动更新&lt;/strong>。如配置内容发生变化，微服务可以自动更新配置。&lt;/em>&lt;/li>
&lt;/ul>
&lt;p>综上所述对于微服务架构而言，一套统一的，通用的管理配置机制是不可缺少的主要组成部分。常见的做法就是通过配置服务器进行管理。&lt;/p>
&lt;p>不过对于来看这个文章的小伙伴应该大部分对配置中心都会比较了解，分布式配置中心实现简单一点就是借助Zookeeper来协助存储，变更推送，不过为了实现各种不同的业务需求，市面上已经有很多很可靠的配置中心可用了，比如我从其他地方拷贝过来的图（虽然不是最新的但是可以供大家参考下）：&lt;/p>
&lt;p>&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/source-blog/register.png">&lt;/p>
&lt;p>每个配置中心都有自己的实现，如果对配置中心感兴趣的小伙伴可以自行去对应开源项目官网查看，我们这里来看Dubbo对配置中心的支持&lt;/p>
&lt;p>&lt;em>&lt;strong>多配置中心：&lt;/strong> Dubbo支持多配置中心，来 &lt;strong>保证其中一个配置中心集群出现不可用时能够切换到另一个配置中心集群&lt;/strong> ，保证能够正常从配置中心获取全局的配置、路由规则等信息。这也能够满足配置中心在部署上适应各类高可用的部署架构模式。-来自官网&lt;/em>&lt;/p>
&lt;p>做中间件可能考虑更多的的不仅仅是性能，还要过多的考虑高可用，高可用怎么做呢，其实就是失效转移，主备切换，降级，降级再降级这些理论的运用，多多考虑某一个服务挂了怎么办，Dubbo的多配置中心支持增加了复杂性，不过降低了服务不可用的风险，有一定的人手的公司还是值得做的。&lt;/p>
&lt;p>关于Dubbo的配置中心这里我来贴个官网的图:
&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/concepts/centers-config.png">
关于官网的介绍可以自行去官网看详细内容: &lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/docs/concepts/registry-configcenter-metadata/">部署架构(注册中心、配置中心、元数据中心&lt;/a>&lt;/p>
&lt;h2 id="132-启动配置中心">13.2 启动配置中心&lt;/h2>
&lt;p>在上一个博客中说到了&lt;a href="https://blog.elastic.link/2022/07/10/dubbo/12-quan-ju-shi-ye-lai-kan-dubbo3.0.8-de-fu-wu-qi-dong-sheng-ming-zhou-qi/">《12-全局视野来看Dubbo3.0.8的服务启动生命周期》&lt;/a>Dubbo应用的启动过程DefaultApplicationDeployer的initialize()方法的全生命周期，在初始化方法中通过调用startConfigCenter();方法来启动配置中心的加载。后面就来详细看下：&lt;/p>
&lt;p>DefaultApplicationDeployer类型的startConfigCenter()代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">startConfigCenter&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// load application config&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//加载应用程序配置 （配置可能有多个地方可以配置需要遵循Dubbo约定的优先级进行设置，也可能是多应用，多注册中心这样的配置）&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// try set model name&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (StringUtils.isBlank(applicationModel.getModelName())) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//设置一下模块名字和模块描述（我们再Debug里面经常会看到这个描述信息 toString直接返回了Dubbo为我们改造的对象信息）&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> applicationModel.setModelName(applicationModel.tryGetApplicationName());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// load config centers&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//加载配置中心配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//配置可能有多个地方可以配置需要遵循Dubbo约定的优先级进行设置，也可能是多应用，多注册中心这样的配置）&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> configManager.loadConfigsOfTypeFromProps(ConfigCenterConfig.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#586e75">//出于兼容性目的，如果没有明确指定配置中心，并且registryConfig的UseAConfigCenter为null或true，请使用registry作为默认配置中心&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> useRegistryAsConfigCenterIfNecessary();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// check Config Center&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//配置管理器中获取配置中心&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Collection&lt;span style="color:#719e07">&amp;lt;&lt;/span>ConfigCenterConfig&lt;span style="color:#719e07">&amp;gt;&lt;/span> configCenters &lt;span style="color:#719e07">=&lt;/span> configManager.getConfigCenters();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//配置中心配置不为空则刷新配置中心配置将其放入配置管理器中&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//下面开始刷新配置中心配置,如果配置中心配置为空则执行空刷新&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (CollectionUtils.isEmpty(configCenters)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//配置中心不存在的配置刷新&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ConfigCenterConfig configCenterConfig &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ConfigCenterConfig();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> configCenterConfig.setScopeModel(applicationModel);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> configCenterConfig.refresh();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//验证配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (configCenterConfig.isValid()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//配置合法则将配置放入配置管理器中&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> configManager.addConfigCenter(configCenterConfig);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> configCenters &lt;span style="color:#719e07">=&lt;/span> configManager.getConfigCenters();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//一个或者多个配置中心配置存在的情况下的配置刷新&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (ConfigCenterConfig configCenterConfig : configCenters) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> configCenterConfig.refresh();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//验证配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#586e75">//配置中心配置不为空则将配置中心配置添加到environment中&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (CollectionUtils.isNotEmpty(configCenters)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//多配置中心本地动态配置对象创建CompositeDynamicConfiguration&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CompositeDynamicConfiguration compositeDynamicConfiguration &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> CompositeDynamicConfiguration();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//获取配置中心的相关配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (ConfigCenterConfig configCenter : configCenters) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// Pass config from ConfigCenterBean to environment&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//将配置中心的外部化配置,更新到环境里面&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> environment.updateExternalConfigMap(configCenter.getExternalConfiguration());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//将配置中心的应用配置,添加到环境里面&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> environment.updateAppExternalConfigMap(configCenter.getAppExternalConfiguration());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// Fetch config from remote config center&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//从配置中心拉取配置添加到组合配置中&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//将配置中心中的动态配置信息 设置到environment的动态配置属性中&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> environment.setDynamicConfiguration(compositeDynamicConfiguration);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="1321-配置管理器加载配置">13.2.1 配置管理器加载配置&lt;/h3>
&lt;p>前面我们看到了配置管理器会从系统属性中加载配置这里我们来详细看下，配置往往是我们使用者比较关注的内容，&lt;/p></description></item><item><title>12 全局视野来看Dubbo3的服务启动生命周期</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/12/12-%E5%85%A8%E5%B1%80%E8%A7%86%E9%87%8E%E6%9D%A5%E7%9C%8Bdubbo3%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</link><pubDate>Fri, 12 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/12/12-%E5%85%A8%E5%B1%80%E8%A7%86%E9%87%8E%E6%9D%A5%E7%9C%8Bdubbo3%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</guid><description>&lt;h1 id="12-全局视野来看dubbo3的服务启动生命周期">12 全局视野来看Dubbo3的服务启动生命周期&lt;/h1>
&lt;h2 id="121-启动方法简介">12.1 启动方法简介&lt;/h2>
&lt;p>在说启动方法之前先把视野拉回第一章&lt;a href="https://blog.elastic.link/2022/07/10/dubbo/1-cong-yi-ge-demo-shuo-qi/">《1-从一个服务提供者的Demo说起》&lt;/a>我们的Demo代码,下面只贴一下核心代码:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">Application&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">main&lt;/span>(String&lt;span style="color:#719e07">[]&lt;/span> args) &lt;span style="color:#268bd2">throws&lt;/span> Exception {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> startWithBootstrap();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">startWithBootstrap&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#586e75">//前面的文章都在说这个服务配置对象的创建,中间又说了分层域模型,扩展加载机制&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;&lt;/span>DemoServiceImpl&lt;span style="color:#719e07">&amp;gt;&lt;/span> service &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//为服务配置下服务接口和服务实现,下面两行用来初始化对象就不详细说了&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> service.setInterface(DemoService.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> service.setRef(&lt;span style="color:#719e07">new&lt;/span> DemoServiceImpl());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//这一个篇章主要说这里:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> DubboBootstrap bootstrap &lt;span style="color:#719e07">=&lt;/span> DubboBootstrap.getInstance();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//初始化应用配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> bootstrap.application(&lt;span style="color:#719e07">new&lt;/span> ApplicationConfig(&lt;span style="color:#2aa198">&amp;#34;dubbo-demo-api-provider&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//初始化注册中心配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .registry(&lt;span style="color:#719e07">new&lt;/span> RegistryConfig(&lt;span style="color:#2aa198">&amp;#34;zookeeper://127.0.0.1:2181&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//初始化协议配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .protocol(&lt;span style="color:#719e07">new&lt;/span> ProtocolConfig(CommonConstants.DUBBO, &lt;span style="color:#719e07">-&lt;/span>1))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//初始化服务配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .service(service)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//启动&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .start()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .await();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>前面我们介绍了Dubbo启动器DubboBootstrap类型对象的创建,又介绍了为DubboBootstrap启动器初始化各种配置信息,这一个博客就开始到了分析启动方法的位置了,Dubbo启动器借助Deployer发布器来启动和发布服务,发布器的启动过程包含了启动配置中心,加载配置,启动元数据中心,启动服务等操作都是比较重要又比较复杂的过程,这里我们先来看下启动过程的生命周期来为后面的内容做好铺垫。&lt;/p>
&lt;h2 id="122-启动器启动方法的调用逻辑start">12.2 启动器启动方法的调用逻辑start()&lt;/h2>
&lt;p>这里我们就直接来看DubboBootstrap的start()方法:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> DubboBootstrap &lt;span style="color:#268bd2">start&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 		&lt;span style="color:#586e75">//调用重载的方法进行启动参数代表是否等待启动结束&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">this&lt;/span>.start(&lt;span style="color:#cb4b16">true&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">this&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我们再来看重载的start方法:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> DubboBootstrap &lt;span style="color:#268bd2">start&lt;/span>(&lt;span style="color:#dc322f">boolean&lt;/span> wait) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#586e75">//这个发布器是在ApplicationModel对象创建之后初始化的时候进行初始化的具体类型为DefaultApplicationDeployer&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Future future &lt;span style="color:#719e07">=&lt;/span> applicationDeployer.start();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (wait) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//等待异步启动的结果&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> future.get();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Exception e) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#586e75">//启动失败则抛出一个异常&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(&lt;span style="color:#2aa198">&amp;#34;await dubbo application start finish failure&amp;#34;&lt;/span>, e);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">this&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="123-应用程序发布器defaultapplicationdeployer的启动方法">12.3 应用程序发布器DefaultApplicationDeployer的启动方法&lt;/h2>
&lt;p>发布器是帮助我们发布服务和引用服务的,在Dubbo3中不论是服务提供者还是服务消费者如果想要启动服务都需要走这个启动方法的逻辑,所以务必重视&lt;/p></description></item><item><title>11-Dubbo启动器DubboBootstrap添加协议配置信息ProtocolConfig</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/11/11-dubbo%E5%90%AF%E5%8A%A8%E5%99%A8dubbobootstrap%E6%B7%BB%E5%8A%A0%E5%8D%8F%E8%AE%AE%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AFprotocolconfig/</link><pubDate>Thu, 11 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/11/11-dubbo%E5%90%AF%E5%8A%A8%E5%99%A8dubbobootstrap%E6%B7%BB%E5%8A%A0%E5%8D%8F%E8%AE%AE%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AFprotocolconfig/</guid><description>&lt;h1 id="11-dubbo启动器dubbobootstrap添加协议配置信息protocolconfig">11-Dubbo启动器DubboBootstrap添加协议配置信息ProtocolConfig&lt;/h1>
&lt;h2 id="111-简介">11.1 简介&lt;/h2>
&lt;p>先贴个代码用来参考:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> DubboBootstrap bootstrap &lt;span style="color:#719e07">=&lt;/span> DubboBootstrap.getInstance();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> bootstrap.application(&lt;span style="color:#719e07">new&lt;/span> ApplicationConfig(&lt;span style="color:#2aa198">&amp;#34;dubbo-demo-api-provider&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .registry(&lt;span style="color:#719e07">new&lt;/span> RegistryConfig(&lt;span style="color:#2aa198">&amp;#34;zookeeper://127.0.0.1:2181&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .protocol(&lt;span style="color:#719e07">new&lt;/span> ProtocolConfig(CommonConstants.DUBBO, &lt;span style="color:#719e07">-&lt;/span>1))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .service(service)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .start()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .await();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上个博客我们说了 RegistryConfig对象的创建,启动器对象在启动之前是要初始化一些配置信息的,这里我们来看这一行代码协议配置信息:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>.protocol(&lt;span style="color:#719e07">new&lt;/span> ProtocolConfig(CommonConstants.DUBBO, &lt;span style="color:#719e07">-&lt;/span>1))
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="112--协议的配置相关">11.2 协议的配置相关&lt;/h2>
&lt;p>下面的配置来源于官网&lt;/p>
&lt;p>服务提供者协议配置。对应的配置类： org.apache.dubbo.config.ProtocolConfig。同时，如果需要支持多协议，可以声明多个 &lt;code>&amp;lt;dubbo:protocol&amp;gt;&lt;/code> 标签，并在 &lt;code>&amp;lt;dubbo:service&amp;gt;&lt;/code> 中通过 protocol 属性指定使用的协议。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">属性&lt;/th>
 &lt;th style="text-align: left">对应URL参数&lt;/th>
 &lt;th style="text-align: left">类型&lt;/th>
 &lt;th style="text-align: left">是否必填&lt;/th>
 &lt;th style="text-align: left">缺省值&lt;/th>
 &lt;th style="text-align: left">作用&lt;/th>
 &lt;th style="text-align: left">描述&lt;/th>
 &lt;th style="text-align: left">兼容性&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">id&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">dubbo&lt;/td>
 &lt;td style="text-align: left">配置关联&lt;/td>
 &lt;td style="text-align: left">协议BeanId，可以在&amp;lt;dubbo:service protocol=&amp;quot;&amp;quot;&amp;gt;中引用此ID，如果ID不填，缺省和name属性值一样，重复则在name后加序号。&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">name&lt;/td>
 &lt;td style="text-align: left">&lt;protocol>&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">&lt;strong>必填&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">dubbo&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">协议名称&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">port&lt;/td>
 &lt;td style="text-align: left">&lt;port>&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">dubbo协议缺省端口为20880，rmi协议缺省端口为1099，http和hessian协议缺省端口为80；如果&lt;strong>没有&lt;/strong>配置port，则自动采用默认端口，如果配置为**-1**，则会分配一个没有被占用的端口。Dubbo 2.4.0+，分配的端口在协议缺省端口的基础上增长，确保端口段可控。&lt;/td>
 &lt;td style="text-align: left">服务发现&lt;/td>
 &lt;td style="text-align: left">服务端口&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">host&lt;/td>
 &lt;td style="text-align: left">&lt;host>&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">自动查找本机IP&lt;/td>
 &lt;td style="text-align: left">服务发现&lt;/td>
 &lt;td style="text-align: left">-服务主机名，多网卡选择或指定VIP及域名时使用，为空则自动查找本机IP，-建议不要配置，让Dubbo自动获取本机IP&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">threadpool&lt;/td>
 &lt;td style="text-align: left">threadpool&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">fixed&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">线程池类型，可选：fixed/cached&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">threads&lt;/td>
 &lt;td style="text-align: left">threads&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">200&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">服务线程池大小(固定大小)&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">iothreads&lt;/td>
 &lt;td style="text-align: left">threads&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">cpu个数+1&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">io线程池大小(固定大小)&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">accepts&lt;/td>
 &lt;td style="text-align: left">accepts&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">0&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">服务提供方最大可接受连接数&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">payload&lt;/td>
 &lt;td style="text-align: left">payload&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">8388608(=8M)&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">请求及响应数据包大小限制，单位：字节&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">codec&lt;/td>
 &lt;td style="text-align: left">codec&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">dubbo&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">协议编码方式&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">serialization&lt;/td>
 &lt;td style="text-align: left">serialization&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">dubbo协议缺省为hessian2，rmi协议缺省为java，http协议缺省为json&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">协议序列化方式，当协议支持多种序列化方式时使用，比如：dubbo协议的dubbo,hessian2,java,compactedjava，以及http协议的json等&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">accesslog&lt;/td>
 &lt;td style="text-align: left">accesslog&lt;/td>
 &lt;td style="text-align: left">string/boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">设为true，将向logger中输出访问日志，也可填写访问日志文件路径，直接把访问日志输出到指定文件&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">path&lt;/td>
 &lt;td style="text-align: left">&lt;path>&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务发现&lt;/td>
 &lt;td style="text-align: left">提供者上下文路径，为服务path的前缀&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">transporter&lt;/td>
 &lt;td style="text-align: left">transporter&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">dubbo协议缺省为netty&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">协议的服务端和客户端实现类型，比如：dubbo协议的mina,netty等，可以分拆为server和client配置&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">server&lt;/td>
 &lt;td style="text-align: left">server&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">dubbo协议缺省为netty，http协议缺省为servlet&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">协议的服务器端实现类型，比如：dubbo协议的mina,netty等，http协议的jetty,servlet等&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">client&lt;/td>
 &lt;td style="text-align: left">client&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">dubbo协议缺省为netty&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">协议的客户端实现类型，比如：dubbo协议的mina,netty等&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">dispatcher&lt;/td>
 &lt;td style="text-align: left">dispatcher&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">dubbo协议缺省为all&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">协议的消息派发方式，用于指定线程模型，比如：dubbo协议的all, direct, message, execution, connection等&lt;/td>
 &lt;td style="text-align: left">2.1.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">queues&lt;/td>
 &lt;td style="text-align: left">queues&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">0&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">线程池队列大小，当线程池满时，排队等待执行的队列大小，建议不要设置，当线程池满时应立即失败，重试其它服务提供机器，而不是排队，除非有特殊需求。&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">charset&lt;/td>
 &lt;td style="text-align: left">charset&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">UTF-8&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">序列化编码&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">buffer&lt;/td>
 &lt;td style="text-align: left">buffer&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">8192&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">网络读写缓冲区大小&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">heartbeat&lt;/td>
 &lt;td style="text-align: left">heartbeat&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">0&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">心跳间隔，对于长连接，当物理层断开时，比如拔网线，TCP的FIN消息来不及发送，对方收不到断开事件，此时需要心跳来帮助检查连接是否已断开&lt;/td>
 &lt;td style="text-align: left">2.0.10以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">telnet&lt;/td>
 &lt;td style="text-align: left">telnet&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">所支持的telnet命令，多个命令用逗号分隔&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">register&lt;/td>
 &lt;td style="text-align: left">register&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">true&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">该协议的服务是否注册到注册中心&lt;/td>
 &lt;td style="text-align: left">2.0.8以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">contextpath&lt;/td>
 &lt;td style="text-align: left">contextpath&lt;/td>
 &lt;td style="text-align: left">String&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">缺省为空串&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">2.0.6以上版本&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>同样官网提供的参数里面并未包含所有的属性 下面我就将其余的属性列举一下方便学习参考:&lt;/p></description></item><item><title>10-Dubbo启动器DubboBootstrap添加注册中心配置信息RegistryConfig</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/10/10-dubbo%E5%90%AF%E5%8A%A8%E5%99%A8dubbobootstrap%E6%B7%BB%E5%8A%A0%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AFregistryconfig/</link><pubDate>Wed, 10 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/10/10-dubbo%E5%90%AF%E5%8A%A8%E5%99%A8dubbobootstrap%E6%B7%BB%E5%8A%A0%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AFregistryconfig/</guid><description>&lt;h1 id="10-dubbo启动器dubbobootstrap添加注册中心配置信息registryconfig">10-Dubbo启动器DubboBootstrap添加注册中心配置信息RegistryConfig&lt;/h1>
&lt;h2 id="101-简介">10.1 简介&lt;/h2>
&lt;p>先贴个代码用来参考:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> DubboBootstrap bootstrap &lt;span style="color:#719e07">=&lt;/span> DubboBootstrap.getInstance();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> bootstrap.application(&lt;span style="color:#719e07">new&lt;/span> ApplicationConfig(&lt;span style="color:#2aa198">&amp;#34;dubbo-demo-api-provider&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .registry(&lt;span style="color:#719e07">new&lt;/span> RegistryConfig(&lt;span style="color:#2aa198">&amp;#34;zookeeper://127.0.0.1:2181&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .protocol(&lt;span style="color:#719e07">new&lt;/span> ProtocolConfig(CommonConstants.DUBBO, &lt;span style="color:#719e07">-&lt;/span>1))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .service(service)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .start()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .await();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上个博客我们说了启动器ApplicationConfig对象的创建,启动器对象在启动之前是要初始化一些配置信息的,这里我们来看这一行代码注册中心配置信息:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>registry(&lt;span style="color:#719e07">new&lt;/span> RegistryConfig(&lt;span style="color:#2aa198">&amp;#34;zookeeper://127.0.0.1:2181&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="102--注册中心的配置相关">10.2 注册中心的配置相关&lt;/h2>
&lt;p>下面的配置来源于官网&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">属性&lt;/th>
 &lt;th style="text-align: left">对应URL参数&lt;/th>
 &lt;th style="text-align: left">类型&lt;/th>
 &lt;th style="text-align: left">是否必填&lt;/th>
 &lt;th style="text-align: left">缺省值&lt;/th>
 &lt;th style="text-align: left">作用&lt;/th>
 &lt;th style="text-align: left">描述&lt;/th>
 &lt;th style="text-align: left">兼容性&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">id&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">配置关联&lt;/td>
 &lt;td style="text-align: left">注册中心引用BeanId，可以在&amp;lt;dubbo:service registry=&amp;quot;&amp;quot;&amp;gt;或&amp;lt;dubbo:reference registry=&amp;quot;&amp;quot;&amp;gt;中引用此ID&lt;/td>
 &lt;td style="text-align: left">1.0.16以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">address&lt;/td>
 &lt;td style="text-align: left">&lt;code>&amp;lt;host:port&amp;gt; &lt;/code>&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">&lt;strong>必填&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务发现&lt;/td>
 &lt;td style="text-align: left">注册中心服务器地址，如果地址没有端口缺省为9090，同一集群内的多个地址用逗号分隔，如：ip:port,ip:port，不同集群的注册中心，请配置多个&lt;code>&amp;lt;dubbo:registry&amp;gt;&lt;/code>标签&lt;/td>
 &lt;td style="text-align: left">1.0.16以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">protocol&lt;/td>
 &lt;td style="text-align: left">&lt;protocol>&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">dubbo&lt;/td>
 &lt;td style="text-align: left">服务发现&lt;/td>
 &lt;td style="text-align: left">注册中心地址协议，支持&lt;code>dubbo&lt;/code>, &lt;code>multicast&lt;/code>, &lt;code>zookeeper&lt;/code>, &lt;code>redis&lt;/code>, &lt;code>consul(2.7.1)&lt;/code>, &lt;code>sofa(2.7.2)&lt;/code>, &lt;code>etcd(2.7.2)&lt;/code>, &lt;code>nacos(2.7.2)&lt;/code>等协议&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">port&lt;/td>
 &lt;td style="text-align: left">&lt;port>&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">9090&lt;/td>
 &lt;td style="text-align: left">服务发现&lt;/td>
 &lt;td style="text-align: left">注册中心缺省端口，当address没有带端口时使用此端口做为缺省值&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">username&lt;/td>
 &lt;td style="text-align: left">&lt;username>&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">登录注册中心用户名，如果注册中心不需要验证可不填&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">password&lt;/td>
 &lt;td style="text-align: left">&lt;password>&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">登录注册中心密码，如果注册中心不需要验证可不填&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">transport&lt;/td>
 &lt;td style="text-align: left">registry.transporter&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">netty&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">网络传输方式，可选mina,netty&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">timeout&lt;/td>
 &lt;td style="text-align: left">registry.timeout&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">5000&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">注册中心请求超时时间(毫秒)&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">session&lt;/td>
 &lt;td style="text-align: left">registry.session&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">60000&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">注册中心会话超时时间(毫秒)，用于检测提供者非正常断线后的脏数据，比如用心跳检测的实现，此时间就是心跳间隔，不同注册中心实现不一样。&lt;/td>
 &lt;td style="text-align: left">2.1.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">file&lt;/td>
 &lt;td style="text-align: left">registry.file&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">使用文件缓存注册中心地址列表及服务提供者列表，应用重启时将基于此文件恢复，注意：两个注册中心不能使用同一文件存储&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">wait&lt;/td>
 &lt;td style="text-align: left">registry.wait&lt;/td>
 &lt;td style="text-align: left">int&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">0&lt;/td>
 &lt;td style="text-align: left">性能调优&lt;/td>
 &lt;td style="text-align: left">停止时等待通知完成时间(毫秒)&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">check&lt;/td>
 &lt;td style="text-align: left">check&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">true&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">注册中心不存在时，是否报错&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">register&lt;/td>
 &lt;td style="text-align: left">register&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">true&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">是否向此注册中心注册服务，如果设为false，将只订阅，不注册&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">subscribe&lt;/td>
 &lt;td style="text-align: left">subscribe&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">true&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">是否向此注册中心订阅服务，如果设为false，将只注册，不订阅&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">dynamic&lt;/td>
 &lt;td style="text-align: left">dynamic&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">true&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">服务是否动态注册，如果设为false，注册后将显示为disable状态，需人工启用，并且服务提供者停止时，也不会自动取消注册，需人工禁用。&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">group&lt;/td>
 &lt;td style="text-align: left">group&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">dubbo&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">服务注册分组，跨组的服务不会相互影响，也无法相互调用，适用于环境隔离。&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">simplified&lt;/td>
 &lt;td style="text-align: left">simplified&lt;/td>
 &lt;td style="text-align: left">boolean&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">false&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">注册到注册中心的URL是否采用精简模式的（与低版本兼容）&lt;/td>
 &lt;td style="text-align: left">2.7.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">extra-keys&lt;/td>
 &lt;td style="text-align: left">extraKeys&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">在simplified=true时，extraKeys允许你在默认参数外将额外的key放到URL中，格式：“interface,key1,key2”。&lt;/td>
 &lt;td style="text-align: left">2.7.0以上版本&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>同样官网提供的参数里面并未包含所有的属性 下面我就将其余的属性列举一下方便学习参考:&lt;/p></description></item><item><title>9-Dubbo启动器DubboBootstrap添加应用程序的配置信息ApplicationConfig</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/09/9-dubbo%E5%90%AF%E5%8A%A8%E5%99%A8dubbobootstrap%E6%B7%BB%E5%8A%A0%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%9A%84%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AFapplicationconfig/</link><pubDate>Tue, 09 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/09/9-dubbo%E5%90%AF%E5%8A%A8%E5%99%A8dubbobootstrap%E6%B7%BB%E5%8A%A0%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%9A%84%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AFapplicationconfig/</guid><description>&lt;h1 id="9-dubbo启动器dubbobootstrap添加应用程序的配置信息applicationconfig">9-Dubbo启动器DubboBootstrap添加应用程序的配置信息ApplicationConfig&lt;/h1>
&lt;h2 id="91-简介">9.1 简介&lt;/h2>
&lt;p>先贴个代码用来参考:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> DubboBootstrap bootstrap &lt;span style="color:#719e07">=&lt;/span> DubboBootstrap.getInstance();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> bootstrap.application(&lt;span style="color:#719e07">new&lt;/span> ApplicationConfig(&lt;span style="color:#2aa198">&amp;#34;dubbo-demo-api-provider&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .registry(&lt;span style="color:#719e07">new&lt;/span> RegistryConfig(&lt;span style="color:#2aa198">&amp;#34;zookeeper://127.0.0.1:2181&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .protocol(&lt;span style="color:#719e07">new&lt;/span> ProtocolConfig(CommonConstants.DUBBO, &lt;span style="color:#719e07">-&lt;/span>1))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .service(service)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .start()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .await();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上个博客我们说了启动器对象的创建,启动器对象在启动之前是要初始化一些配置信息的,这里我们来看这一行代码:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>bootstrap.application(&lt;span style="color:#719e07">new&lt;/span> ApplicationConfig(&lt;span style="color:#2aa198">&amp;#34;dubbo-demo-api-provider&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="92-应用程序applicationconfig的配置信息">9.2 应用程序ApplicationConfig的配置信息&lt;/h2>
&lt;p>ApplicationConfig的构造器比较简单就是为他的成员变量name赋值来标识这个应用程序的名字
下面我们直接参考下官网的配置表格:&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">属性&lt;/th>
 &lt;th style="text-align: left">对应URL参数&lt;/th>
 &lt;th style="text-align: left">类型&lt;/th>
 &lt;th style="text-align: left">是否必填&lt;/th>
 &lt;th style="text-align: left">缺省值&lt;/th>
 &lt;th style="text-align: left">作用&lt;/th>
 &lt;th style="text-align: left">描述&lt;/th>
 &lt;th style="text-align: left">兼容性&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">name&lt;/td>
 &lt;td style="text-align: left">application&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">&lt;strong>必填&lt;/strong>&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">当前应用名称，用于注册中心计算应用间依赖关系，注意：消费者和提供者应用名不要一样，此参数不是匹配条件，你当前项目叫什么名字就填什么，和提供者消费者角色无关，比如：kylin应用调用了morgan应用的服务，则kylin项目配成kylin，morgan项目配成morgan，可能kylin也提供其它服务给别人使用，但kylin项目永远配成kylin，这样注册中心将显示kylin依赖于morgan&lt;/td>
 &lt;td style="text-align: left">1.0.16以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">version&lt;/td>
 &lt;td style="text-align: left">application.version&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">当前应用的版本&lt;/td>
 &lt;td style="text-align: left">2.2.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">owner&lt;/td>
 &lt;td style="text-align: left">owner&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">应用负责人，用于服务治理，请填写负责人公司邮箱前缀&lt;/td>
 &lt;td style="text-align: left">2.0.5以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">organization&lt;/td>
 &lt;td style="text-align: left">organization&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">组织名称(BU或部门)，用于注册中心区分服务来源，此配置项建议不要使用autoconfig，直接写死在配置中，比如china,intl,itu,crm,asc,dw,aliexpress等&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">architecture&lt;/td>
 &lt;td style="text-align: left">architecture&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">用于服务分层对应的架构。如，intl、china。不同的架构使用不同的分层。&lt;/td>
 &lt;td style="text-align: left">2.0.7以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">environment&lt;/td>
 &lt;td style="text-align: left">environment&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">应用环境，如：develop/test/product，不同环境使用不同的缺省值，以及作为只用于开发测试功能的限制条件&lt;/td>
 &lt;td style="text-align: left">2.0.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">compiler&lt;/td>
 &lt;td style="text-align: left">compiler&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">javassist&lt;/td>
 &lt;td style="text-align: left">性能优化&lt;/td>
 &lt;td style="text-align: left">Java字节码编译器，用于动态类的生成，可选：jdk或javassist&lt;/td>
 &lt;td style="text-align: left">2.1.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">logger&lt;/td>
 &lt;td style="text-align: left">logger&lt;/td>
 &lt;td style="text-align: left">string&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">slf4j&lt;/td>
 &lt;td style="text-align: left">性能优化&lt;/td>
 &lt;td style="text-align: left">日志输出方式，可选：slf4j,jcl,log4j,log4j2,jdk&lt;/td>
 &lt;td style="text-align: left">2.2.0以上版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">metadata-type&lt;/td>
 &lt;td style="text-align: left">metadata-type&lt;/td>
 &lt;td style="text-align: left">String&lt;/td>
 &lt;td style="text-align: left">可选&lt;/td>
 &lt;td style="text-align: left">local&lt;/td>
 &lt;td style="text-align: left">服务治理&lt;/td>
 &lt;td style="text-align: left">metadata 传递方式，是以 Provider 视角而言的，Consumer 侧配置无效，可选值有： remote - Provider 把 metadata 放到远端注册中心，Consumer 从注册中心获取 local - Provider 把 metadata 放在本地，Consumer 从 Provider 处直接获取&lt;/td>
 &lt;td style="text-align: left">2.7.6以上版本&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>官网的配置很详细了上面有一些属性是值得注意的比如这个name,compiler,logger,metadata-type 我们可能要多看下默认值是什么,方便我们在使用过程中遇到问题的排查&lt;/p></description></item><item><title>8-Dubbo启动器DubboBootstrap借助双重校验锁的单例模式进行对象的初始化</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/08/8-dubbo%E5%90%AF%E5%8A%A8%E5%99%A8dubbobootstrap%E5%80%9F%E5%8A%A9%E5%8F%8C%E9%87%8D%E6%A0%A1%E9%AA%8C%E9%94%81%E7%9A%84%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%E8%BF%9B%E8%A1%8C%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96/</link><pubDate>Mon, 08 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/08/8-dubbo%E5%90%AF%E5%8A%A8%E5%99%A8dubbobootstrap%E5%80%9F%E5%8A%A9%E5%8F%8C%E9%87%8D%E6%A0%A1%E9%AA%8C%E9%94%81%E7%9A%84%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%E8%BF%9B%E8%A1%8C%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96/</guid><description>&lt;h1 id="8-dubbo启动器dubbobootstrap借助双重校验锁的单例模式进行对象的初始化">8-Dubbo启动器DubboBootstrap借助双重校验锁的单例模式进行对象的初始化&lt;/h1>
&lt;h2 id="81-启动器简介">8.1 启动器简介&lt;/h2>
&lt;p>在说启动器之前先把视野拉回第一章&lt;a href="https://blog.elastic.link/2022/07/10/dubbo/1-cong-yi-ge-demo-shuo-qi/">《1-从一个服务提供者的Demo说起》&lt;/a>我们的Demo代码,下面只贴一下核心代码:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">Application&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">main&lt;/span>(String&lt;span style="color:#719e07">[]&lt;/span> args) &lt;span style="color:#268bd2">throws&lt;/span> Exception {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> startWithBootstrap();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">startWithBootstrap&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#586e75">//前面的文章都在说这个服务配置对象的创建,中间又说了分层域模型,扩展加载机制&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;&lt;/span>DemoServiceImpl&lt;span style="color:#719e07">&amp;gt;&lt;/span> service &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//为服务配置下服务接口和服务实现,下面两行用来初始化对象就不详细说了&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> service.setInterface(DemoService.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> service.setRef(&lt;span style="color:#719e07">new&lt;/span> DemoServiceImpl());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//这一个篇章主要说这里:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> DubboBootstrap bootstrap &lt;span style="color:#719e07">=&lt;/span> DubboBootstrap.getInstance();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> bootstrap.application(&lt;span style="color:#719e07">new&lt;/span> ApplicationConfig(&lt;span style="color:#2aa198">&amp;#34;dubbo-demo-api-provider&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .registry(&lt;span style="color:#719e07">new&lt;/span> RegistryConfig(&lt;span style="color:#2aa198">&amp;#34;zookeeper://127.0.0.1:2181&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .protocol(&lt;span style="color:#719e07">new&lt;/span> ProtocolConfig(CommonConstants.DUBBO, &lt;span style="color:#719e07">-&lt;/span>1))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .service(service)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .start()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .await();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Dubbo3 往云原生的方向走自然要针对云原生应用的应用启动,应用运行,应用发布等信息做一些建模,这个DubboBootstrap就是用来启动Dubbo服务的.类似于Netty的Bootstrap类型和ServerBootstrap启动器&lt;/p>
&lt;h2 id="82-双重校验锁的单例模式创建启动器对象的">8.2 双重校验锁的单例模式创建启动器对象的&lt;/h2>
&lt;p>Dubbo的bootstrap类为啥要用单例模式:&lt;/p>
&lt;p>通过调用静态方法getInstance()获取单例实例。之所以设计为单例，是因为Dubbo中的一些类（如ExtensionLoader）只为每个进程设计一个实例。&lt;/p>
&lt;p>下面就来直接看代码吧,代码胜千言:
对象的调用代码如下:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>DubboBootstrap bootstrap &lt;span style="color:#719e07">=&lt;/span> DubboBootstrap.getInstance(); 
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>DubboBootstrap获取对象的getInstance()方法:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> DubboBootstrap &lt;span style="color:#268bd2">getInstance&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 		&lt;span style="color:#586e75">//双重校验锁第一次判断空&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (instance &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#586e75">//为空都进行排队&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">synchronized&lt;/span> (DubboBootstrap.class) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//双重校验锁第二次判断空 上面为空的都排队了这里得判断下&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (instance &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#586e75">//调用重载方法获取对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> instance &lt;span style="color:#719e07">=&lt;/span> DubboBootstrap.getInstance(ApplicationModel.defaultModel());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> instance;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>DubboBootstrap获取对象重载的getInstance(ApplicationModel applicationModel)方法:&lt;/p></description></item><item><title>7-Dubbo的SPI扩展机制之自动激活扩展Activate源码解析</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/07/7-dubbo%E7%9A%84spi%E6%89%A9%E5%B1%95%E6%9C%BA%E5%88%B6%E4%B9%8B%E8%87%AA%E5%8A%A8%E6%BF%80%E6%B4%BB%E6%89%A9%E5%B1%95activate%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/</link><pubDate>Sun, 07 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/07/7-dubbo%E7%9A%84spi%E6%89%A9%E5%B1%95%E6%9C%BA%E5%88%B6%E4%B9%8B%E8%87%AA%E5%8A%A8%E6%BF%80%E6%B4%BB%E6%89%A9%E5%B1%95activate%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/</guid><description>&lt;h1 id="7-dubbo的spi扩展机制之自动激活扩展activate源码解析">7-Dubbo的SPI扩展机制之自动激活扩展Activate源码解析&lt;/h1>
&lt;h2 id="71-activate扩展的说明">7.1 Activate扩展的说明&lt;/h2>
&lt;p>此注解对于使用给定条件自动激活某些扩展非常有用，例如：@Activate可用于在有多个实现时加载某些筛选器扩展。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>group()&lt;/strong> 指定组条件。框架SPI定义了有效的组值。&lt;/li>
&lt;li>&lt;strong>value()&lt;/strong> 指定URL条件中的参数键。&lt;/li>
&lt;/ul>
&lt;p>SPI提供程序可以调用ExtensionLoader。getActivateExtension(URL、String、String)方法以查找具有给定条件的所有已激活扩展。&lt;/p>
&lt;p>比如后面我们会说到的&lt;strong>过滤器扩展对象&lt;/strong>的获取,如下通过调用&lt;strong>getActivateExtension方法的&lt;/strong>代码:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> List&lt;span style="color:#719e07">&amp;lt;&lt;/span>Filter&lt;span style="color:#719e07">&amp;gt;&lt;/span> filters;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> filters &lt;span style="color:#719e07">=&lt;/span> ScopeModelUtil.getExtensionLoader(Filter.class, moduleModels.get(0)).getActivateExtension(url, key, group);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="72-获取自动激活扩展的源码">7.2 获取自动激活扩展的源码&lt;/h2>
&lt;p>前面我们看了激活扩展是通过调用getActivateExtension方法来获取对象的,那接下来就来看下这个方法做了什么操作:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">* @param url 服务的url
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">* @param key 用于获取扩展点名称的url参数键 比如监听器:exporter.listener,过滤器:params-filter,telnet处理器:telnet
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">*/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> List&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">getActivateExtension&lt;/span>(URL url, String key) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> getActivateExtension(url, key, &lt;span style="color:#cb4b16">null&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>继续调用重载的方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param url 服务的url
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param key 用于获取扩展点名称的url参数键 比如监听器:exporter.listener,过滤器:params-filter,telnet处理器:telnet
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param group group 用于筛选的分组,比如过滤器中使用此参数来区分消费者使用这个过滤器还是提供者使用这个过滤器他们的group参数分表为consumer,provider
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return 已激活的扩展列表。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> List&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">getActivateExtension&lt;/span>(URL url, String key, String group) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 		&lt;span style="color:#586e75">//从参数中获取url指定的值&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String value &lt;span style="color:#719e07">=&lt;/span> url.getParameter(key);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//调用下个重载的方法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> getActivateExtension(url, StringUtils.isEmpty(value) &lt;span style="color:#719e07">?&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span> : COMMA_SPLIT_PATTERN.split(value), group);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面的重载方法都是用来转换参数的,下面这个方法才是真正的逻辑&lt;/p></description></item><item><title>06-Dubbo的SPI扩展机制之普通扩展对象的创建与Wrapper机制的源码解析</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/06/06-dubbo%E7%9A%84spi%E6%89%A9%E5%B1%95%E6%9C%BA%E5%88%B6%E4%B9%8B%E6%99%AE%E9%80%9A%E6%89%A9%E5%B1%95%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9B%E5%BB%BA%E4%B8%8Ewrapper%E6%9C%BA%E5%88%B6%E7%9A%84%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/</link><pubDate>Sat, 06 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/06/06-dubbo%E7%9A%84spi%E6%89%A9%E5%B1%95%E6%9C%BA%E5%88%B6%E4%B9%8B%E6%99%AE%E9%80%9A%E6%89%A9%E5%B1%95%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9B%E5%BB%BA%E4%B8%8Ewrapper%E6%9C%BA%E5%88%B6%E7%9A%84%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/</guid><description>&lt;h1 id="6-dubbo的spi扩展机制之普通扩展对象的创建与wrapper机制的源码解析">6 Dubbo的SPI扩展机制之普通扩展对象的创建与Wrapper机制的源码解析&lt;/h1>
&lt;h2 id="61-普通扩展对象的加载与创建">6.1 普通扩展对象的加载与创建&lt;/h2>
&lt;p>这里我们要分析的是ExtensionLoader类型的getExtension(String name)方法, 有了前面自适应扩展的铺垫,这里就更容易来看了getExtension是根据扩展名字获取具体扩展的通用方法,我们来根据某个类型来获取扩展的时候就是走的这里,比如在这个博客开头的介绍:&lt;/p>
&lt;ul>
&lt;li>ApplicationModel中获取配置管理器对象&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> configManager &lt;span style="color:#719e07">=&lt;/span> (ConfigManager) &lt;span style="color:#719e07">this&lt;/span>.getExtensionLoader(ApplicationExt.class)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .getExtension(ConfigManager.NAME);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="611-getextension方法源码">6.1.1 getExtension方法源码&lt;/h3>
&lt;p>先来看下getExtension方法的源码,根据扩展名字查询扩展对象&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-cpp" data-lang="cpp">&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">public&lt;/span> T &lt;span style="color:#268bd2">getExtension&lt;/span>(String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#586e75">//这里并不能看到什么,只多传了个参数wrap为true调用另外一个重载的方法
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&lt;/span> T extension &lt;span style="color:#719e07">=&lt;/span> getExtension(name, &lt;span style="color:#b58900">true&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (extension &lt;span style="color:#719e07">==&lt;/span> null) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalArgumentException(&lt;span style="color:#2aa198">&amp;#34;Not find extension: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> extension;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> T &lt;span style="color:#268bd2">getExtension&lt;/span>(String name, &lt;span style="color:#dc322f">boolean&lt;/span> wrap) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#586e75">//检查扩展加载器是否已被销毁&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> checkDestroyed();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (StringUtils.isEmpty(name)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalArgumentException(&lt;span style="color:#2aa198">&amp;#34;Extension name == null&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//扩展名字为true则加载默认扩展&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (&lt;span style="color:#2aa198">&amp;#34;true&amp;#34;&lt;/span>.equals(name)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> getDefaultExtension();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//非wrap类型则将缓存的扩展名字key加上_origin后缀&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//wrap是aop机制 俗称切面,这个origin在aop里面可以称为切点,下面的wrap扩展可以称为增强通知的类型,普通扩展和wrap扩展的扩展名字是一样的&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String cacheKey &lt;span style="color:#719e07">=&lt;/span> name;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (&lt;span style="color:#719e07">!&lt;/span>wrap) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cacheKey &lt;span style="color:#719e07">+=&lt;/span> &lt;span style="color:#2aa198">&amp;#34;_origin&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//从cachedInstances缓存中查询&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">final&lt;/span> Holder&lt;span style="color:#719e07">&amp;lt;&lt;/span>Object&lt;span style="color:#719e07">&amp;gt;&lt;/span> holder &lt;span style="color:#719e07">=&lt;/span> getOrCreateHolder(cacheKey);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Object instance &lt;span style="color:#719e07">=&lt;/span> holder.get();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//缓存中不存在则创建扩展对象 双重校验锁&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (instance &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">synchronized&lt;/span> (holder) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#586e75">//双重校验锁的方式&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> instance &lt;span style="color:#719e07">=&lt;/span> holder.get();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (instance &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#586e75">//创建扩展对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> instance &lt;span style="color:#719e07">=&lt;/span> createExtension(name, wrap);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> holder.set(instance);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> (T) instance;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我们先来看一下默认扩展的加载代码:&lt;/p></description></item><item><title>05-自适应扩展对象的创建getAdaptiveExtension方法</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/05/05-%E8%87%AA%E9%80%82%E5%BA%94%E6%89%A9%E5%B1%95%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9B%E5%BB%BAgetadaptiveextension%E6%96%B9%E6%B3%95/</link><pubDate>Fri, 05 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/05/05-%E8%87%AA%E9%80%82%E5%BA%94%E6%89%A9%E5%B1%95%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9B%E5%BB%BAgetadaptiveextension%E6%96%B9%E6%B3%95/</guid><description>&lt;h2 id="5-自适应扩展对象的创建getadaptiveextension方法">5 自适应扩展对象的创建getAdaptiveExtension方法&lt;/h2>
&lt;p>自适应扩展又称为动态扩展,可以在运行时生成扩展对象&lt;/p>
&lt;p>ExtensionLoader中的getAdaptiveExtension()方法,这个方法也是我们看到的第一个获取扩展对象的方法. ,这个方法可以帮助我们通过SPI机制从扩展文件中找到需要的扩展类型并创建它的对象,
&lt;strong>自适应扩展:&lt;strong>如果对设计模式比较了解的可能会联想到&lt;/strong>适配器模式&lt;/strong>,自适应扩展其实就是适配器模式的思路,自适应扩展有两种策略:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>一种是我们自己实现自适应扩展:然后使用@Adaptive修饰这个时候适配器的逻辑由我们自己实现,当扩展加载器去查找具体的扩展的时候可以通过找到我们这个对应的适配器扩展,然后适配器扩展帮忙去查询真正的扩展,这个比如我们下面要举的扩展注入器的例子,具体扩展通过扩展注入器适配器,注入器适配器来查询具体的注入器扩展实现来帮忙查找扩展。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>还有一种方式是我们未实现这个自适应扩展,Dubbo在运行时通过字节码动态代理的方式在运行时生成一个适配器,使用这个适配器映射到具体的扩展. 第二种情况往往用在比如 Protocol、Cluster、LoadBalance 等。有时，有些拓展并不想在框架启动阶段被加载，而是希望在拓展方法被调用时，根据运行时参数进行加载。(如果还不了解可以考虑看下@Adaptive注解加载方法上面的时候扩展是如何加载的)&lt;/p>
&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> T &lt;span style="color:#268bd2">getAdaptiveExtension&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 		&lt;span style="color:#586e75">//检查当前扩展加载器是否已经被销毁&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> checkDestroyed();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//从自适应扩展缓存中查询扩展对象如果存在就直接返回,这个自适应扩展类型只会有一个扩展实现类型如果是多个的话根据是否可以覆盖参数决定扩展实现类是否可以相互覆盖&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Object instance &lt;span style="color:#719e07">=&lt;/span> cachedAdaptiveInstance.get();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//这个if判断不太优雅 容易多层嵌套,上面instance不为空就可以直接返回了&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (instance &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#586e75">//创建异常则抛出异常直接返回(多线程场景下可能第一个线程异常了第二个线程进来之后走到这里)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (createAdaptiveInstanceError &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(&lt;span style="color:#2aa198">&amp;#34;Failed to create adaptive instance: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> createAdaptiveInstanceError.toString(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> createAdaptiveInstanceError);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>			&lt;span style="color:#586e75">//加锁排队 (单例模式创建对象的思想 双重校验锁)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">synchronized&lt;/span> (cachedAdaptiveInstance) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#586e75">//加锁的时候对象都是空的,进来之后先判断下防止重复创建&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> instance &lt;span style="color:#719e07">=&lt;/span> cachedAdaptiveInstance.get();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//只有第一个进来锁的对象为空开始创建扩展对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (instance &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#586e75">//根据SPI机制获取类型,创建对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> instance &lt;span style="color:#719e07">=&lt;/span> createAdaptiveExtension();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">//存入缓存&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cachedAdaptiveInstance.set(instance);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Throwable t) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> createAdaptiveInstanceError &lt;span style="color:#719e07">=&lt;/span> t;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(&lt;span style="color:#2aa198">&amp;#34;Failed to create adaptive instance: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> t.toString(), t);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> (T) instance;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>前面使用单例思想来调用创建自适应扩展对象的方法,下面就让我们深入探究下创建自适应扩展对象的整个过程createAdaptiveExtension();方法:&lt;/p></description></item><item><title>04-Dubbo的扩展机制</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/04/04-dubbo%E7%9A%84%E6%89%A9%E5%B1%95%E6%9C%BA%E5%88%B6/</link><pubDate>Thu, 04 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/04/04-dubbo%E7%9A%84%E6%89%A9%E5%B1%95%E6%9C%BA%E5%88%B6/</guid><description>&lt;h1 id="4-dubbo的扩展机制">4-Dubbo的扩展机制&lt;/h1>
&lt;h2 id="41-回顾我们前面使用到扩展场景">4.1 回顾我们前面使用到扩展场景&lt;/h2>
&lt;p>在上一章中我们初始化应用模型对象的时候,了解到有几个地方用到了扩展机制来创建对象,这一章我们会详细来讲一下这个扩展对象的加载过程,这里我们先来回顾下哪些地方用到了扩展机制:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">// 使用扩展机制获取TypeBuilder&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Set&lt;span style="color:#719e07">&amp;lt;&lt;/span>TypeBuilder&lt;span style="color:#719e07">&amp;gt;&lt;/span> tbs &lt;span style="color:#719e07">=&lt;/span> model.getExtensionLoader(TypeBuilder.class).getSupportedExtensionInstances();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">//获取域模型初始化器ScopeModelInitializer扩展对象,执行初始化方法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ExtensionLoader&lt;span style="color:#719e07">&amp;lt;&lt;/span>ScopeModelInitializer&lt;span style="color:#719e07">&amp;gt;&lt;/span> initializerExtensionLoader &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">this&lt;/span>.getExtensionLoader(ScopeModelInitializer.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Set&lt;span style="color:#719e07">&amp;lt;&lt;/span>ScopeModelInitializer&lt;span style="color:#719e07">&amp;gt;&lt;/span> initializers &lt;span style="color:#719e07">=&lt;/span> initializerExtensionLoader.getSupportedExtensionInstances();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">// OrderedPropertiesConfiguration 中获取有序配置提供器对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ExtensionLoader&lt;span style="color:#719e07">&amp;lt;&lt;/span>OrderedPropertiesProvider&lt;span style="color:#719e07">&amp;gt;&lt;/span> propertiesProviderExtensionLoader &lt;span style="color:#719e07">=&lt;/span> moduleModel.getExtensionLoader(OrderedPropertiesProvider.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">// ApplicationModel中获取配置管理器对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> configManager &lt;span style="color:#719e07">=&lt;/span> (ConfigManager) &lt;span style="color:#719e07">this&lt;/span>.getExtensionLoader(ApplicationExt.class)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .getExtension(ConfigManager.NAME);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">//ModuleModel中获取模块扩展对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Set&lt;span style="color:#719e07">&amp;lt;&lt;/span>ModuleExt&lt;span style="color:#719e07">&amp;gt;&lt;/span> exts &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">this&lt;/span>.getExtensionLoader(ModuleExt.class).getSupportedExtensionInstances();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">// ApplicationModel中获Environment对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>environment &lt;span style="color:#719e07">=&lt;/span> (Environment) &lt;span style="color:#719e07">this&lt;/span>.getExtensionLoader(ApplicationExt.class)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .getExtension(Environment.NAME);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">// ApplicationModel中获取应用初始化监听器ApplicationInitListener扩展对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ExtensionLoader&lt;span style="color:#719e07">&amp;lt;&lt;/span>ApplicationInitListener&lt;span style="color:#719e07">&amp;gt;&lt;/span> extensionLoader &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">this&lt;/span>.getExtensionLoader(ApplicationInitListener.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Set&lt;span style="color:#719e07">&amp;lt;&lt;/span>String&lt;span style="color:#719e07">&amp;gt;&lt;/span> listenerNames &lt;span style="color:#719e07">=&lt;/span> extensionLoader.getSupportedExtensions();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">//ScopeModel中创建扩展访问器:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">this&lt;/span>.extensionDirector &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ExtensionDirector(parent &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span> &lt;span style="color:#719e07">?&lt;/span> parent.getExtensionDirector() : &lt;span style="color:#cb4b16">null&lt;/span>, scope, &lt;span style="color:#719e07">this&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>有了以上的应用场景我们可以来看下扩展机制了&lt;/p>
&lt;h2 id="42-为什么要用到扩展机制">4.2 为什么要用到扩展机制?&lt;/h2>
&lt;p>为什么要用到扩展这个想必每个编程人员都比较了解,一个好的程序是要遵循一定的设计规范比如设计模式中的&lt;strong>开闭原则&lt;/strong> 英文全称是 Open Closed Principle，简写为 OCP,对扩展开放、对修改关闭:&lt;/p>
&lt;p>&lt;strong>对扩展开放：&lt;/strong> 指的是我们系统中的模块、类、方法对它们的提供者（开发者）应该是开放的，提供者可以对系统进行扩展（新增）新的功能。&lt;/p></description></item><item><title>03-框架,应用程序,模块领域模型Model对象的初始化</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/03/03-%E6%A1%86%E6%9E%B6%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E6%A8%A1%E5%9D%97%E9%A2%86%E5%9F%9F%E6%A8%A1%E5%9E%8Bmodel%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96/</link><pubDate>Wed, 03 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/03/03-%E6%A1%86%E6%9E%B6%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E6%A8%A1%E5%9D%97%E9%A2%86%E5%9F%9F%E6%A8%A1%E5%9E%8Bmodel%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96/</guid><description>&lt;h1 id="3-框架应用程序模块领域模型model对象的初始化">3-框架,应用程序,模块领域模型Model对象的初始化&lt;/h1>
&lt;p>在上一章中我们详细看了服务配置ServiceConfig类型的初始化，不过我们跳过了AbstractMethodConfig的构造器中创建模块模型对象的过程，那这一章我们就来看下模块模型对象的初始化过程:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">AbstractMethodConfig&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">super&lt;/span>(ApplicationModel.defaultModel().getDefaultModule());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>那为什么会在Dubbo3的新版本中加入这个域模型呢&lt;/strong>，主要有如下原因
之前dubbo都是只有一个作用域的，通过静态类 属性共享
增加域模型是为了:&lt;/p>
&lt;ol>
&lt;li>让Dubbo支持多应用的部署，这块一些大企业有诉求&lt;/li>
&lt;li>从架构设计上，解决静态属性资源共享、清理的问题&lt;/li>
&lt;li>分层模型将应用的管理和服务的管理分开&lt;/li>
&lt;/ol>
&lt;p>可能比较抽象，可以具体点来看。Dubbo3中在启动时候需要启动配置中心、元数据中心，这个配置中心和元数据中心可以归应用模型来管理。Dubbo作为RPC框架又需要启动服务和引用服务，服务级别的管理就交给了这个模块模型来管理。分层次的管理方便我们理解和处理逻辑，父子级别的模型又方便了数据传递。&lt;/p>
&lt;p>了解过JVM类加载机制的同学应该就比较清楚JVM类加载过程中的数据访问模型。子类加载器先交给父类加载器查找，找不到再从子类加载器中查找。Dubbo的分层模型类似这样一种机制，这一章先来简单了解下，后面用到时候具体细说。&lt;/p>
&lt;h2 id="31-模型对象的关系">3.1 模型对象的关系&lt;/h2>
&lt;p>为了不增加复杂性，我们这里仅仅列出模型对象类型类型之间的继承关系如下所示:
&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/source-blog/3-model.png">&lt;/p>
&lt;center>图3.1 模型对象的继承关系&lt;/center>
&lt;p>模型对象一共有4个，公共的属性和操作放在了域模型类型中，下面我们来详细说下这几个模型类型:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>ExtensionAccessor&lt;/strong> 扩展的统一访问器&lt;/p>
&lt;ul>
&lt;li>用于获取扩展加载管理器ExtensionDirector对象&lt;/li>
&lt;li>&lt;strong>获取扩展对象ExtensionLoader&lt;/strong>&lt;/li>
&lt;li>根据扩展名字&lt;strong>获取具体扩展对象&lt;/strong>&lt;/li>
&lt;li>获取自适应扩展对象&lt;/li>
&lt;li>获取默认扩展对象&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>ScopeModel&lt;/strong> 模型对象的公共抽象父类型&lt;/p>
&lt;ul>
&lt;li>内部id用于表示模型树的层次结构&lt;/li>
&lt;li>公共模型名称，可以被用户设置&lt;/li>
&lt;li>描述信息&lt;/li>
&lt;li>类加载器管理&lt;/li>
&lt;li>父模型管理parent&lt;/li>
&lt;li>当前模型的所属域ExtensionScope有:&lt;strong>FRAMEWORK(框架)&lt;/strong>，&lt;strong>APPLICATION(应用)&lt;/strong>，&lt;strong>MODULE(模块)&lt;/strong>，&lt;strong>SELF(自给自足&lt;/strong>，为每个作用域创建一个实例，用于特殊的SPI扩展，如ExtensionInjector)&lt;/li>
&lt;li>具体的扩展加载程序管理器对象的管理:&lt;strong>ExtensionDirector&lt;/strong>&lt;/li>
&lt;li>域Bean工厂管理，一个内部共享的Bean工厂&lt;strong>ScopeBeanFactory&lt;/strong>&lt;/li>
&lt;li>等等&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>FrameworkModel&lt;/strong> dubbo框架模型，可与多个应用程序共享&lt;/p>
&lt;ul>
&lt;li>FrameworkModel实例对象集合，allInstances&lt;/li>
&lt;li>所有ApplicationModel实例对象集合，applicationModels&lt;/li>
&lt;li>发布的ApplicationModel实例对象集合pubApplicationModels&lt;/li>
&lt;li>框架的服务存储库&lt;strong>FrameworkServiceRepository&lt;/strong>类型对象(数据存储在内存中)&lt;/li>
&lt;li>内部的应用程序模型对象internalApplicationModel&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>ApplicationModel&lt;/strong> 表示正在使用Dubbo的应用程序，并存储基本&lt;strong>元数据信息&lt;/strong>，以便在RPC调用过程中使用。
ApplicationModel包括许多关于&lt;strong>发布服务&lt;/strong>的ProviderModel和许多关于订阅服务的Consumer Model。&lt;/p>
&lt;ul>
&lt;li>ExtensionLoader、DubboBootstrap和这个类目前被设计为单例或静态（本身完全静态或使用一些静态字段）。因此，从它们返回的实例属于流程范围。如果想在一个进程中支持多个dubbo服务器，可能需要重构这三个类。&lt;/li>
&lt;li>&lt;strong>所有ModuleModel实例&lt;/strong>对象集合moduleModels&lt;/li>
&lt;li>&lt;strong>发布的ModuleModel实例&lt;/strong>对象集合pubModuleModels&lt;/li>
&lt;li>&lt;strong>环境信息Environment实例&lt;/strong>对象environment&lt;/li>
&lt;li>&lt;strong>配置管理ConfigManager实例&lt;/strong>对象configManager&lt;/li>
&lt;li>&lt;strong>服务存储库ServiceRepository实例&lt;/strong>对象serviceRepository&lt;/li>
&lt;li>&lt;strong>应用程序部署器ApplicationDeployer实例&lt;/strong>对象deployer&lt;/li>
&lt;li>&lt;strong>所属框架FrameworkModel实例&lt;/strong>对象frameworkModel&lt;/li>
&lt;li>&lt;strong>内部的模块模型ModuleModel实例&lt;/strong>对象internalModule&lt;/li>
&lt;li>&lt;strong>默认的模块模型ModuleModel实例&lt;/strong>对象defaultModule&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>ModuleModel&lt;/strong> 服务模块的模型&lt;/p>
&lt;ul>
&lt;li>&lt;strong>所属应用程序模型ApplicationModel实例&lt;/strong>对象applicationModel&lt;/li>
&lt;li>&lt;strong>模块环境信息ModuleEnvironment实例&lt;/strong>对象moduleEnvironment&lt;/li>
&lt;li>&lt;strong>模块服务存储库ModuleServiceRepository实例&lt;/strong>对象serviceRepository&lt;/li>
&lt;li>&lt;strong>模块的服务配置管理ModuleConfigManager实例&lt;/strong>对象moduleConfigManager&lt;/li>
&lt;li>&lt;strong>模块部署器ModuleDeployer实例&lt;/strong>对象deployer用于导出和引用服务&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>了解了这几个模型对象的关系我们可以了解到这几个模型对象的管理层级从框架到应用程序，然后到模块的管理(FrameworkModel-&amp;gt;ApplicationModel-&amp;gt;ModuleModel)，他们主要用来针对框架，应用程序，模块的&lt;strong>存储&lt;/strong>，&lt;strong>发布管理，&lt;/strong>，&lt;strong>配置管理&lt;/strong>&lt;/p>
&lt;p>看来Dubbo3 针对应用服务治理与运维这一块也是在努力尝试.&lt;/p></description></item><item><title>02-启动服务前服务配置ServiceConfig类型是如何初始化的?</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/02/02-%E5%90%AF%E5%8A%A8%E6%9C%8D%E5%8A%A1%E5%89%8D%E6%9C%8D%E5%8A%A1%E9%85%8D%E7%BD%AEserviceconfig%E7%B1%BB%E5%9E%8B%E6%98%AF%E5%A6%82%E4%BD%95%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9A%84/</link><pubDate>Tue, 02 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/02/02-%E5%90%AF%E5%8A%A8%E6%9C%8D%E5%8A%A1%E5%89%8D%E6%9C%8D%E5%8A%A1%E9%85%8D%E7%BD%AEserviceconfig%E7%B1%BB%E5%9E%8B%E6%98%AF%E5%A6%82%E4%BD%95%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9A%84/</guid><description>&lt;h1 id="2-启动服务前服务配置serviceconfig类型是如何初始化的">2-启动服务前服务配置ServiceConfig类型是如何初始化的?&lt;/h1>
&lt;h2 id="21-示例源码回顾">2.1 示例源码回顾:&lt;/h2>
&lt;p>为了方便我们理解记忆,这里先来回顾下上一章我们说的示例代码,如下所示:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">Application&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">main&lt;/span>(String&lt;span style="color:#719e07">[]&lt;/span> args) &lt;span style="color:#268bd2">throws&lt;/span> Exception {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> startWithBootstrap();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">startWithBootstrap&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;&lt;/span>DemoServiceImpl&lt;span style="color:#719e07">&amp;gt;&lt;/span> service &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> service.setInterface(DemoService.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> service.setRef(&lt;span style="color:#719e07">new&lt;/span> DemoServiceImpl());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> DubboBootstrap bootstrap &lt;span style="color:#719e07">=&lt;/span> DubboBootstrap.getInstance();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> bootstrap.application(&lt;span style="color:#719e07">new&lt;/span> ApplicationConfig(&lt;span style="color:#2aa198">&amp;#34;dubbo-demo-api-provider&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .registry(&lt;span style="color:#719e07">new&lt;/span> RegistryConfig(&lt;span style="color:#2aa198">&amp;#34;zookeeper://127.0.0.1:2181&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .protocol(&lt;span style="color:#719e07">new&lt;/span> ProtocolConfig(CommonConstants.DUBBO, &lt;span style="color:#719e07">-&lt;/span>1))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .service(service)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .start()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .await();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面这几行代码虽然看似简单,仅仅几行的启动,但是完全掌握也得下一翻大功夫,接下来我们重点看启动代码中的第一行,创建一个服务配置对象:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>ServiceConfig&lt;span style="color:#719e07">&amp;lt;&lt;/span>DemoServiceImpl&lt;span style="color:#719e07">&amp;gt;&lt;/span> service &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ServiceConfig&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="22-了解一下服务配置的建模">2.2 了解一下服务配置的建模&lt;/h2>
&lt;p>下面是一个简单的UML继承关系图,当然这个图很是简单的,这里仅仅列出了当前服务提供者的相关服务配置继承关系, 服务提供者独有的配置标注颜色为蓝色,一些可能与服务引用配置所共有的父类型我们用红色背景,当然这里为了简便起见不会提起服务引用相关的配置类型,这里列举了如下服务提供者类型,他们各司其职:
&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/source-blog/2-ServiceConfig.png">&lt;/p>
&lt;center>图2.1 服务引用类继承关系UML&lt;/center>
&lt;ul>
&lt;li>AbstractConfig
&lt;ul>
&lt;li>&lt;strong>抽象的配置类型&lt;/strong>,也是最顶层的服务配置类型,封装着解析配置的实用方法和公共方法,比如服务id的设置,服务标签名字的处理,服务参数的添加,属性的提取等等&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>AbstractMethodConfig
&lt;ul>
&lt;li>&lt;strong>抽象的方法配置&lt;/strong>,同样这个类型也是见名知意,服务方法的相关配置处理,这个类型主要用于对服务方法的一些配置信息建模比如服务方法的调用超时时间,重试次数,最大并发调用数,负载均衡策略,是否异步调用,是否确认异步发送等等配置信息.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>AbstractInterfaceConfig
&lt;ul>
&lt;li>&lt;strong>抽象的接口配置&lt;/strong>,与前面介绍的方法配置类似,这个类型是对服务接口的建模,主要的配置信息有暴漏服务的接口名字,服务接口的版本号,客户/提供方将引用的远程服务分组,&lt;strong>服务元数据&lt;/strong>,服务接口的本地impl类名,服务监控配置,对于生成动态代理的策略，可以选择两种策略：jdk和javassist,容错类型等等配置&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>AbstractServiceConfig
&lt;ul>
&lt;li>&lt;strong>抽象的服务配置&lt;/strong>,这个就与我们的服务提供者有了具体的关系了,主要记录了一些服务提供者的公共配置,如服务版本,服务分组,服务延迟注册毫秒数,是否暴漏服务,服务权重,是否为动态服务,服务协议类型,是否注册等等.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>ServiceConfigBase
&lt;ul>
&lt;li>&lt;strong>服务的基础配置类&lt;/strong>,这个类型仍旧是个抽象的类型提取了一些基础的配置:导出服务的接口类,服务名称,接口实现的引用类型,提供者配置,是否是通用服务GenericService&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>ServiceConfig
&lt;ul>
&lt;li>&lt;strong>服务配置实现类&lt;/strong>, 上面的类型都是抽象类型不能做为具体存在的事物,这个类型是我们出现的第一个服务配置实现类型,服务配置实现类已经从父类型中继承了这么多的属性,这里主要为实现服务提供了一些配置如服务的协议配置,服务的代理工厂JavassistProxyFactory是将生成导出服务代理的ProxyFactory实现，是其默认实现,服务提供者模型,是否导出服务,导出的服务列表,服务监听器等等.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>ServiceBean
&lt;ul>
&lt;li>&lt;strong>服务工厂Bean&lt;/strong>	,这个主要是Spring模块来简化配置的一个服务工厂Bean这里就先不详细介绍Spring相关的配置.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="23-serviceconfig构造器的初始化调用链">2.3 ServiceConfig构造器的初始化调用链&lt;/h2>
&lt;p>有了上面的类型继承关系我们就比较好分析了,接下来我们开始创建服务配置对象如下代码所示:&lt;/p></description></item><item><title>01 从一个服务提供者的Demo说起</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/01/01-%E4%BB%8E%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84demo%E8%AF%B4%E8%B5%B7/</link><pubDate>Mon, 01 Aug 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/08/01/01-%E4%BB%8E%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84demo%E8%AF%B4%E8%B5%B7/</guid><description>&lt;h1 id="1-从一个服务提供者的demo说起">1 从一个服务提供者的Demo说起&lt;/h1>
&lt;p>为了更方便了解原理,我们先来编写一个Demo,从例子中来看源码实现:&lt;/p>
&lt;h2 id="11-启动zookeeper">1.1 启动Zookeeper&lt;/h2>
&lt;p>为了Demo可以正常启动,需要我们先在本地启动一个Zookeeper如下图所示:
&lt;img alt="在这里插入图片描述" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/source-blog/1-zookeeper.png">&lt;/p>
&lt;h2 id="12-服务提供者">1.2 服务提供者&lt;/h2>
&lt;p>接下来给大家贴一下示例源码,这个源码来源于Dubbo源码目录的	dubbo-demo/dubbo-demo-api 目录下面的dubbo-demo-api-provider子项目,这里我做了删减,方便看核心代码:
首先我们定义一个服务接口如下所示:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> java.util.concurrent.CompletableFuture;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">interface&lt;/span> &lt;span style="color:#268bd2">DemoService&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 同步处理的服务方法
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param name
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String &lt;span style="color:#268bd2">sayHello&lt;/span>(String name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 用于异步处理的服务方法
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param name
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">default&lt;/span> CompletableFuture&lt;span style="color:#719e07">&amp;lt;&lt;/span>String&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">sayHelloAsync&lt;/span>(String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> CompletableFuture.completedFuture(sayHello(name));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>服务实现类如下:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.RpcContext;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.slf4j.Logger;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.slf4j.LoggerFactory;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> java.util.concurrent.CompletableFuture;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">DemoServiceImpl&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> DemoService {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#268bd2">static&lt;/span> &lt;span style="color:#268bd2">final&lt;/span> Logger logger &lt;span style="color:#719e07">=&lt;/span> LoggerFactory.getLogger(DemoServiceImpl.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> String &lt;span style="color:#268bd2">sayHello&lt;/span>(String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.info(&lt;span style="color:#2aa198">&amp;#34;Hello &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> name &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, request from consumer: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> RpcContext.getServiceContext().getRemoteAddress());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#2aa198">&amp;#34;Hello &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> name &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, response from provider: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> RpcContext.getServiceContext().getLocalAddress();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> CompletableFuture&lt;span style="color:#719e07">&amp;lt;&lt;/span>String&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">sayHelloAsync&lt;/span>(String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="13-启用服务">1.3 启用服务&lt;/h2>
&lt;p>有了服务接口之后我们来启用服务,启用服务的源码如下:&lt;/p></description></item><item><title>浅析 Dubbo 3.0 中接口级地址推送性能的优化</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/06/23/%E6%B5%85%E6%9E%90-dubbo-3.0-%E4%B8%AD%E6%8E%A5%E5%8F%A3%E7%BA%A7%E5%9C%B0%E5%9D%80%E6%8E%A8%E9%80%81%E6%80%A7%E8%83%BD%E7%9A%84%E4%BC%98%E5%8C%96/</link><pubDate>Thu, 23 Jun 2022 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2022/06/23/%E6%B5%85%E6%9E%90-dubbo-3.0-%E4%B8%AD%E6%8E%A5%E5%8F%A3%E7%BA%A7%E5%9C%B0%E5%9D%80%E6%8E%A8%E9%80%81%E6%80%A7%E8%83%BD%E7%9A%84%E4%BC%98%E5%8C%96/</guid><description>&lt;h2 id="url-简介">URL 简介&lt;/h2>
&lt;p>在阐述地址推送性能的具体优化之前，我们有必要先了解一下与之息息相关的内容 &amp;mdash; URL。&lt;/p>
&lt;h3 id="定义">定义&lt;/h3>
&lt;p>在不谈及 dubbo 时，我们大多数人对 URL 这个概念并不会感到陌生。统一资源定位器 (&lt;a href="https://www.ietf.org/rfc/rfc1738.txt">RFC1738&lt;/a>――Uniform Resource Locators (URL))应该是最广为人知的一个 RFC 规范，它的定义也非常简单。&lt;/p>
&lt;blockquote>
&lt;p>因特网上的可用资源可以用简单字符串来表示，该文档就是描述了这种字符串的语法和语 义。而这些字符串则被称为：“统一资源定位器”（URL）&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>一个标准的 URL 格式&lt;/strong>至多可以包含如下的几个部分&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>protocol://username:password@host:port/path?key=value&amp;amp;key=value
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>一些典型 URL&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>http://www.facebook.com/friends?param1=value1&amp;amp;amp;param2=value2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>https://username:password@10.20.130.230:8080/list?version=1.0.0
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ftp://username:password@192.168.1.7:21/1/read.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>当然，也有一些&lt;strong>不太符合常规的 URL&lt;/strong>，也被归类到了 URL 之中&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>192.168.1.3:20880
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = null, url host = 192.168.1.3, port = 20880, url path = null
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>file:///home/user1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = file, url host = null, url path = home/user1/router.js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>file://home/user1/router.js?type=script&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = file, url host = home, url path = user1/router.js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>file:///D:/1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = file, url host = null, url path = D:/1/router.js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>file:/D:/1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>同上 file:///D:/1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/home/user1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = null, url host = null, url path = home/user1/router.js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>home/user1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = null, url host = home, url path = user1/router.js
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="dubbo-中的-url">Dubbo 中的 URL&lt;/h3>
&lt;p>在 dubbo 中，也使用了类似的 URL，主要用于在各个扩展点之间传递数据，组成此 URL 对象的具体参数如下:&lt;/p></description></item><item><title>Dubbo3 应用级服务发现</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2021/06/02/dubbo3-%E5%BA%94%E7%94%A8%E7%BA%A7%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0/</link><pubDate>Wed, 02 Jun 2021 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2021/06/02/dubbo3-%E5%BA%94%E7%94%A8%E7%BA%A7%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0/</guid><description>&lt;h2 id="1-服务发现service-discovery-概述">1 服务发现（Service Discovery） 概述&lt;/h2>
&lt;p>从 Internet 刚开始兴起，如何动态感知后端服务的地址变化就是一个必须要面对的问题，为此人们定义了 DNS 协议，基于此协议，调用方只需要记住由固定字符串组成的域名，就能轻松完成对后端服务的访问，而不用担心流量最终会访问到哪些机器 IP，因为有代理组件会基于 DNS 地址解析后的地址列表，将流量透明的、均匀的分发到不同的后端机器上。&lt;/p>
&lt;p>在使用微服务构建复杂的分布式系统时，如何感知 backend 服务实例的动态上下线，也是微服务框架最需要关心并解决的问题之一。业界将这个问题称之为 - 微服务的地址发现（Service Discovery），业界比较有代表性的微服务框架如 SpringCloud、Dubbo 等都抽象了强大的动态地址发现能力，并且为了满足微服务业务场景的需求，绝大多数框架的地址发现都是基于自己设计的一套机制来实现，因此在能力、灵活性上都要比传统 DNS 丰富得多。如 SpringCloud 中常用的 Eureka， Dubbo 中常用的 Zookeeper、Nacos 等，这些注册中心实现不止能够传递地址（IP + Port），还包括一些微服务的 Metadata 信息，如实例序列化类型、实例方法列表、各个方法级的定制化配置等。&lt;/p>
&lt;p>下图是微服务中 Service Discovery 的基本工作原理图，微服务体系中的实例大概可分为三种角色：服务提供者（Provider）、服务消费者（Consumer）和注册中心（Registry）。而不同框架实现间最主要的区别就体现在注册中心数据的组织：地址如何组织、以什么粒度组织、除地址外还同步哪些数据？&lt;/p>
&lt;p>&lt;img alt="img1" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/service-discovery-1.png">&lt;/p>
&lt;p>我们今天这篇文章就是围绕这三个角色展开，重点看下 Dubbo 中对于服务发现方案的设计，包括之前老的服务发现方案的优势和缺点，以及 Dubbo 3.0 中正在设计、开发中的全新的&lt;strong>面向应用粒度的地址发现方案&lt;/strong>，我们期待这个新的方案能做到：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>支持几十万/上百万级集群实例的地址发现&lt;/strong>&lt;/li>
&lt;li>&lt;strong>与不同的微服务体系（如 Spring Cloud）实现在地址发现层面的互通&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h2 id="2-dubbo-地址发现机制解析">2 Dubbo 地址发现机制解析&lt;/h2>
&lt;p>我们先以一个 DEMO 应用为例，来快速的看一下 Dubbo “接口粒度”服务发现与“应用粒度”服务发现体现出来的区别。这里我们重点关注 Provider 实例是如何向注册中心注册的，并且，为了体现注册中心数据量变化，我们观察的是两个 Provider 实例的场景。&lt;/p>
&lt;p>&lt;strong>应用 DEMO 提供的服务列表如下：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:service&lt;/span> interface=&lt;span style="color:#2aa198">&amp;#34;org.apache.dubbo.samples.basic.api.DemoService&amp;#34;&lt;/span> ref=&lt;span style="color:#2aa198">&amp;#34;demoService&amp;#34;&lt;/span>&lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:service&lt;/span> interface=&lt;span style="color:#2aa198">&amp;#34;org.apache.dubbo.samples.basic.api.GreetingService&amp;#34;&lt;/span> ref=&lt;span style="color:#2aa198">&amp;#34;greetingService&amp;#34;&lt;/span>&lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我们示例注册中心实现采用的是 Zookeeper ，启动 192.168.0.103 和 192.168.0.104 两个实例后，以下是两种模式下注册中心的实际数据&lt;/p></description></item><item><title>dubbo-go源码笔记（二）客户端调用过程</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2021/01/15/dubbo-go%E6%BA%90%E7%A0%81%E7%AC%94%E8%AE%B0%E4%BA%8C%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%B0%83%E7%94%A8%E8%BF%87%E7%A8%8B/</link><pubDate>Fri, 15 Jan 2021 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2021/01/15/dubbo-go%E6%BA%90%E7%A0%81%E7%AC%94%E8%AE%B0%E4%BA%8C%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%B0%83%E7%94%A8%E8%BF%87%E7%A8%8B/</guid><description>&lt;p>随着微服务架构的流行，许多高性能 rpc 框架应运而生，由阿里开源的 dubbo 框架 go 语言版本的 dubbo-go 也成为了众多开发者不错的选择。本文将介绍 dubbo-go 框架的基本使用方法，以及从 export 调用链的角度进行 server 端源码导读，希望能引导读者进一步认识这款框架。&lt;/p>
&lt;h2 id="前言">前言&lt;/h2>
&lt;p>有了上一篇文章&lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2021/01/14/dubbo-go-%E6%BA%90%E7%A0%81%E7%AC%94%E8%AE%B0%E4%B8%80server-%E7%AB%AF%E5%BC%80%E5%90%AF%E6%9C%8D%E5%8A%A1%E8%BF%87%E7%A8%8B/">《dubbo-go 源码笔记（一）Server服务暴露过程详解》&lt;/a> 的铺垫，可以大致上类比客户端服务类似于服务端启动过程。其中最大的区别是服务端通过zk注册服务，发布自己的ivkURL并订阅事件开启监听；而服务端应该是通过zk注册组件，&lt;strong>拿到需要调用的serviceURL&lt;/strong>，&lt;strong>更新invoker&lt;/strong>并&lt;strong>重写用户的RPCService&lt;/strong>，从而实现对远程过程调用细节的封装。&lt;/p>
&lt;h2 id="1-配置文件和客户端源码">1. 配置文件和客户端源码&lt;/h2>
&lt;h4 id="11-client配置文件">1.1 client配置文件&lt;/h4>
&lt;p>helloworld提供的demo：profiles/client.yaml&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">registries &lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#2aa198">&amp;#34;demoZk&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">protocol&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;zookeeper&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">timeout &lt;/span>: &lt;span style="color:#2aa198">&amp;#34;3s&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">address&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;127.0.0.1:2181&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">username&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">password&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">references&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#2aa198">&amp;#34;UserProvider&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75"># 可以指定多个registry，使用逗号隔开;不指定默认向所有注册中心注册&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">registry&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;demoZk&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">protocol &lt;/span>: &lt;span style="color:#2aa198">&amp;#34;dubbo&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">interface &lt;/span>: &lt;span style="color:#2aa198">&amp;#34;com.ikurento.user.UserProvider&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">cluster&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;failover&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">methods &lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#268bd2">name&lt;/span>: &lt;span style="color:#2aa198">&amp;#34;GetUser&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">retries&lt;/span>: &lt;span style="color:#2aa198">3&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>可看到配置文件与之前讨论过的server端非常类似，其refrences部分字段就是对当前服务要主调的服务的配置，其中详细说明了调用协议、注册协议、接口id、调用方法、集群策略等，这些配置都会在之后与注册组件交互，重写ivk、调用的过程中使用到。&lt;/p>
&lt;h4 id="12-客户端使用框架源码">1.2 客户端使用框架源码&lt;/h4>
&lt;p>user.go&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">func&lt;/span> &lt;span style="color:#268bd2">init&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> config.&lt;span style="color:#268bd2">SetConsumerService&lt;/span>(userProvider)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hessian.&lt;span style="color:#268bd2">RegisterPOJO&lt;/span>(&lt;span style="color:#719e07">&amp;amp;&lt;/span>User{})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>main.go&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">func&lt;/span> &lt;span style="color:#268bd2">main&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hessian.&lt;span style="color:#268bd2">RegisterPOJO&lt;/span>(&lt;span style="color:#719e07">&amp;amp;&lt;/span>User{})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> config.&lt;span style="color:#268bd2">Load&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> time.&lt;span style="color:#268bd2">Sleep&lt;/span>(&lt;span style="color:#2aa198">3e9&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#b58900">println&lt;/span>(&lt;span style="color:#2aa198">&amp;#34;\n\n\nstart to test dubbo&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> user &lt;span style="color:#719e07">:=&lt;/span> &lt;span style="color:#719e07">&amp;amp;&lt;/span>User{}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> err &lt;span style="color:#719e07">:=&lt;/span> userProvider.&lt;span style="color:#268bd2">GetUser&lt;/span>(context.&lt;span style="color:#268bd2">TODO&lt;/span>(), []&lt;span style="color:#268bd2">interface&lt;/span>{}{&lt;span style="color:#2aa198">&amp;#34;A001&amp;#34;&lt;/span>}, user)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> err &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">nil&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#b58900">panic&lt;/span>(err)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#b58900">println&lt;/span>(&lt;span style="color:#2aa198">&amp;#34;response result: %v\n&amp;#34;&lt;/span>, user)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">initSignal&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>官网提供的helloworld demo的源码。可看到与服务端类似，在user.go内注册了rpc-service，以及需要rpc传输的结构体user。&lt;/p></description></item><item><title>Dubbo-go 源码笔记（一）Server 端开启服务过程</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2021/01/14/dubbo-go-%E6%BA%90%E7%A0%81%E7%AC%94%E8%AE%B0%E4%B8%80server-%E7%AB%AF%E5%BC%80%E5%90%AF%E6%9C%8D%E5%8A%A1%E8%BF%87%E7%A8%8B/</link><pubDate>Thu, 14 Jan 2021 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2021/01/14/dubbo-go-%E6%BA%90%E7%A0%81%E7%AC%94%E8%AE%B0%E4%B8%80server-%E7%AB%AF%E5%BC%80%E5%90%AF%E6%9C%8D%E5%8A%A1%E8%BF%87%E7%A8%8B/</guid><description>&lt;p>随着微服务架构的流行，许多高性能 rpc 框架应运而生，由阿里开源的 dubbo 框架 go 语言版本的 dubbo-go 也成为了众多开发者不错的选择。本文将介绍 dubbo-go 框架的基本使用方法，以及从 export 调用链的角度进行 server 端源码导读，希望能引导读者进一步认识这款框架。&lt;/p>
&lt;p>当拿到一款框架之后，一种不错的源码阅读方式大致如下：从运行最基础的 helloworld demo 源码开始 —&amp;gt; 再查看配置文件 —&amp;gt; 开启各种依赖服务（比如zk、consul） —&amp;gt; 开启服务端 —&amp;gt; 再到通过 client 调用服务端 —&amp;gt; 打印完整请求日志和回包。调用成功之后，再根据框架的设计模型，从配置文件解析开始，自顶向下递阅读整个框架的调用栈。&lt;/p>
&lt;p>对于 C/S 模式的 rpc 请求来说，整个调用栈被拆成了 client 和 server 两部分，所以可以分别从 server 端的配置文件解析阅读到 server 端的监听启动，从 client 端的配置文件解析阅读到一次 invoker Call 调用。这样一次完整请求就明晰了起来。&lt;/p>
&lt;h2 id="运行官网提供的-helloworld-demo">运行官网提供的 helloworld-demo&lt;/h2>
&lt;p>&lt;strong>官方 demo 相关链接&lt;/strong>：https://github.com/dubbogo/dubbo-samples/tree/master/golang/helloworld/dubbo&lt;/p>
&lt;h3 id="1-dubbo-go-27-版本-quickstart">1. dubbo-go 2.7 版本 QuickStart&lt;/h3>
&lt;h4 id="1开启一个-go-server-服务">1）开启一个 go-server 服务&lt;/h4>
&lt;ul>
&lt;li>将仓库 clone 到本地&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ git clone https://github.com/dubbogo/dubbo-samples.git
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>进入 dubbo 目录&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#b58900">cd&lt;/span> dubbo-samples/golang/helloworld/dubbo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>进入目录后可看到四个文件夹，分别支持 go 和 java 的 client 以及 server，我们尝试运行一个 go 的 server。进入 app 子文件夹内，可以看到里面保存了 go 文件。&lt;/p></description></item><item><title>Dubbo 中的 URL 统一模型</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2019/10/17/dubbo-%E4%B8%AD%E7%9A%84-url-%E7%BB%9F%E4%B8%80%E6%A8%A1%E5%9E%8B/</link><pubDate>Thu, 17 Oct 2019 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/blog/2019/10/17/dubbo-%E4%B8%AD%E7%9A%84-url-%E7%BB%9F%E4%B8%80%E6%A8%A1%E5%9E%8B/</guid><description>&lt;h3 id="定义">定义&lt;/h3>
&lt;p>在不谈及 dubbo 时，我们大多数人对 URL 这个概念并不会感到陌生。统一资源定位器 (&lt;a href="https://www.ietf.org/rfc/rfc1738.txt">RFC1738&lt;/a>――Uniform Resource Locators (URL)）应该是最广为人知的一个 RFC 规范，它的定义也非常简单&lt;/p>
&lt;blockquote>
&lt;p>因特网上的可用资源可以用简单字符串来表示，该文档就是描述了这种字符串的语法和语
义。而这些字符串则被称为：“统一资源定位器”（URL）&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>一个标准的 URL 格式&lt;/strong>至多可以包含如下的几个部分&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>protocol://username:password@host:port/path?key=value&amp;amp;key=value
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>一些典型 URL&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>http://www.facebook.com/friends?param1=value1&amp;amp;amp;param2=value2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>https://username:password@10.20.130.230:8080/list?version=1.0.0
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ftp://username:password@192.168.1.7:21/1/read.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>当然，也有一些&lt;strong>不太符合常规的 URL&lt;/strong>，也被归类到了 URL 之中&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>192.168.1.3:20880
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = null, url host = 192.168.1.3, port = 20880, url path = null
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>file:///home/user1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = file, url host = null, url path = home/user1/router.js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>file://home/user1/router.js?type=script&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = file, url host = home, url path = user1/router.js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>file:///D:/1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = file, url host = null, url path = D:/1/router.js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>file:/D:/1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>同上 file:///D:/1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/home/user1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = null, url host = null, url path = home/user1/router.js
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>home/user1/router.js?type=script
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>url protocol = null, url host = home, url path = user1/router.js
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="dubbo-中的-url">Dubbo 中的 URL&lt;/h3>
&lt;p>在 dubbo 中，也使用了类似的 URL，主要用于在各个扩展点之间传递数据，组成此 URL 对象的具体参数如下:&lt;/p></description></item></channel></rss>