<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Mercy Ma</title>
    <description>关于程序、设计以及架构 | 小马哥，Javaer ，Software Engineer</description>
    <link>https://weibo.com/mercyblitz/</link>
    <atom:link href="https://weibo.com/mercyblitz/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Thu, 09 Feb 2023 08:00:23 +0000</pubDate>
    <lastBuildDate>Thu, 09 Feb 2023 08:00:23 +0000</lastBuildDate>
    <generator>Jekyll v3.9.3</generator>
    
      <item>
        <title>《深入理解 spring cloud 与实战》序</title>
        <description>&lt;h1 id=&quot;深入理解-spring-cloud-与实战序&quot;&gt;《深入理解 Spring Cloud 与实战》序&lt;/h1&gt;

&lt;p&gt;2017 年，我与作者在国内开源社区相识，那时给人的印象是，他是一名乐于分享并且积极上进的青年。后来，得知他入职阿里巴巴中间件部门，并一同参与了 Spring Cloud 与阿里巴巴以及阿里云的技术整合项目，也就是后来的 Spring Cloud Alibaba。&lt;/p&gt;

&lt;p&gt;作为一名资深开发人员，作者的职业素养具备专业、严谨、热情和强烈的责任心。记得 2018 年 11 月，我们一起参加 Spring One Tour 2018 北京峰会。会后，作者给 Spring Cloud Leader Spencer 提出了不少关于 Spring Cloud 实现上的建议。有趣的是，刚走出会议大厅，作者又接到来自社区贡献者军哥（nepxion.com 项目发起人）的电话，反馈 Spring Cloud Alibaba 孵化版本中的问题。经过技术排查，问题的确存在。数次电话沟通中，作者面漏歉意，并承诺尽快将问题修复。我想，大多数工程师都经历过这种情况。晚间，我们来到 Josh Long（Spring Developer Advocate）下塔的酒店，作者向对方演示 Spring Cloud Alibaba RocketMQ 在本地和阿里云环境的操作。时间不知不觉已是凌晨四点。后来，Josh 录制了相关的视频，分享在 YouTube 上。&lt;/p&gt;

&lt;p&gt;作为一名 Spring Cloud Alibaba 项目负责人，作者除了代码贡献之外，更多的精力投入在社区运营、维护与 Spring 官方沟通上，进过一年多的不懈地努力，2019 月 7 月 24 日，Spring 官方宣布 Spring Cloud Alibaba 毕业，仓库迁移至 Alibaba Github OSS 下。这意味着 Spring Cloud Alibaba 是国内首个进入 Spring 社区的开源项目。&lt;/p&gt;

&lt;p&gt;作为一名技术布道者，作者身体力行，2018 至 2019 年，走遍全国 IT 重镇，分享 Spring Cloud 以及 Spring Cloud Alibaba 等技术。几乎每场分享过后，将自己的技术心得和体会以博文的方式发布。尽管网上已有不少的相关技术文章，然而作者文章的技术深度和广度是有过之而无不及的。同时，作者意识到单凭技术文章很难系统性的探讨技术细节，由此萌生了写书的念头。于是，作者与我讨论写书一些技巧和注意事项。&lt;/p&gt;

&lt;p&gt;写书的过程必然是漫长而曲折的，尤其需要在繁忙的日常工作中整合零散的时间。更棘手的是，写作期间 Spring Cloud 的内核也在不断的变化，这也给内容增添的难度，不得不与时俱进，及时作出调整，时间轴被迫拉长。不过，个人认为这样的等待是值得的，尽管作者是 Spring Cloud Alibaba 的核心开发人员，然而本书并非专题讨论 Spring Cloud Alibaba，并且本书也不是单纯地指导读者如何使用 Spring Cloud，而是从宏观和微观的视角，深入地讨论 Spring Cloud 架构发展，以及各个组件之间的特性和联系。所以，本书不仅适合 Spring Cloud 初探者，也为资深从业人员提供参考，并且本书的行文通俗，章节之间的关联紧密，阅读体验友好，故推荐之。&lt;/p&gt;

&lt;p&gt;正值中美全面竞争的时代，个人认为，彼此在软件技术的差距虽在不断缩小，但绝对值仍旧存在。全球化的进程开阔了我们的视野，然而商业化的运作却使得行业进程迟缓。尽管中国式的互联网是我们常引以为傲的话题，然而大多数场景还停留在技术运用的阶段，中间偶尔出现一些技术创新，还谈不上技术创造。许多从业人员理想的职位是软件架构师或者 CTO，难免过多地关注于软件架构，而忽视了设计思想和代码实现的重要性。我想，任何基础学科的积累都是枯燥和繁琐的，时代的特殊性，导致了行业的局限性。或许本书不是尽善尽美之物，个人希望读者在阅读后，意识到细节的力量。同时，也期盼更多的同仁志士积极参与开源建设，群策群力，促进行业良性循环。&lt;/p&gt;

&lt;p&gt;小马哥（mercyblitz）&lt;/p&gt;

&lt;p&gt;2020 年 10 月 28 日&lt;/p&gt;
</description>
        <pubDate>Wed, 28 Oct 2020 00:00:00 +0000</pubDate>
        <link>https://weibo.com/mercyblitz/2020/10/28/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3-Spring-Cloud-%E4%B8%8E%E5%AE%9E%E6%88%98-%E5%BA%8F/</link>
        <guid isPermaLink="true">https://weibo.com/mercyblitz/2020/10/28/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3-Spring-Cloud-%E4%B8%8E%E5%AE%9E%E6%88%98-%E5%BA%8F/</guid>
        
        
      </item>
    
      <item>
        <title>Apache dubbo 服务自省架构设计</title>
        <description>&lt;h1 id=&quot;背景&quot;&gt;背景&lt;/h1&gt;

&lt;p&gt;随着微服务架构的推广和普及，服务之间的耦合度在逐步降低。在演化的过程中，伴随着应用组织架构的变化以及基础设施的衍进，服务和应用之间的边界变得更为模糊。Java 作为一门面向对象的编程语言，Java 接口（interface）作为服务之间通讯的一等公民，配合文档（JavaDoc）便于开发人员理解和维护。基于相同的编程哲学，Apache Dubbo 作为传统的 RPC 服务治理框架，通过接口实现分布式服务。然而对于微服务治理而言，应用（或“服务”）才是基础设施的核心要素。面对云原生（Cloud Native）技术的兴起，传统的 Dubbo 架构不断地面临着新的的挑战。下面内容将以 Apache Dubbo 2.7.5 为基础，介绍全新架构 - Apache Dubbo 服务自省（后文简称“服务自省”），了解 Dubbo 传统架构所面临的现实挑战，以及服务自省架构的设计和解决之道。&lt;/p&gt;

&lt;h1 id=&quot;术语约定&quot;&gt;术语约定&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Service：SOA 或微服务中的“服务”，或称之为“应用”，具有全局唯一的名称&lt;/li&gt;
  &lt;li&gt;Service Name: 服务名称，或应用名称&lt;/li&gt;
  &lt;li&gt;Servce Instance：服务实例，或称为应用实例（Application Instance），表示单个 Dubbo 应用进程&lt;/li&gt;
  &lt;li&gt;Registry：注册中心&lt;/li&gt;
  &lt;li&gt;Dubbo 服务：又称之为“Dubbo 业务服务”，包含 Java 接口、通讯协议，版本（version）和分组（group）等元信息&lt;/li&gt;
  &lt;li&gt;Dubbo 服务 ID：唯一鉴定 Dubbo 服务的元数据，用于 Dubbo 服务暴露（发布）和订阅&lt;/li&gt;
  &lt;li&gt;Provider：Dubbo 服务提供方&lt;/li&gt;
  &lt;li&gt;Consumer：Dubbo 服务消费方&lt;/li&gt;
  &lt;li&gt;Dubbo 服务暴露：也称之为 Dubbo 服务发布，或英文中的“export”、”exported”&lt;/li&gt;
  &lt;li&gt;Dubbo 应用服务：也称之为 Dubbo 业务服务，或业务 Dubbo 服务&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;使用场景&quot;&gt;使用场景&lt;/h1&gt;

&lt;p&gt;服务自省是 Dubbo 应用在运行时处理和分析 Dubbo 服务元信息（Metadata）的过程，如当前应用暴露 的Dubbo 服务以及各自的通讯协议等。期间会伴随着事件的广播和处理，如服务暴露事件。Dubbo 服务自省架构是其传统架的一种补充，更是未来 Dubbo 架构，它更适合以下使用场景：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;超大规模 Dubbo 服务治理场景&lt;/li&gt;
  &lt;li&gt;微服务架构和元原生应用&lt;/li&gt;
  &lt;li&gt;Dubbo 元数据架构的基石&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;超大规模-dubbo-服务治理场景&quot;&gt;超大规模 Dubbo 服务治理场景&lt;/h2&gt;

&lt;p&gt;如果 Dubbo 集群规模超过一千以上，或者集群扩缩容已无法自如地执行，如 Zookeeper 管理数万 Dubbo 服务，服务自省可极大化减轻注册中心的压力，尤其在内存足迹、网络传输以及变更通知上体现。&lt;/p&gt;

&lt;h2 id=&quot;微服务架构和元原生应用&quot;&gt;微服务架构和元原生应用&lt;/h2&gt;

&lt;p&gt;如果想要 Dubbo 应用更好地微服务化，或者更接近于云原生应用，那么服务自省是一种不错的选择，它能够提供已应用为粒度的服务注册与发现模型，全面地支持最流行的 Spring Cloud 和 Kubernetes 注册中心，并且能与 Spring Cloud 或 Spring Boot 应用交互。&lt;/p&gt;

&lt;h2 id=&quot;dubbo-元数据架构的基石&quot;&gt;Dubbo 元数据架构的基石&lt;/h2&gt;

&lt;p&gt;Dubbo 元数据架构是围绕 Dubbo DevOps 而引入，包括 Dubbo 配置元数据（如：属性配置、路由规则等）和结构元数据（如：Java 注解、接口和文档等）。服务自省作为 Dubbo 元数据的基础设施，不仅支持所有元数据的存储和平滑升级，而且不会对注册中心、配置中心和元数据中心产生额外的负担。&lt;/p&gt;

&lt;h1 id=&quot;传统架构&quot;&gt;传统架构&lt;/h1&gt;

&lt;p&gt;Apache Dubbo 是一款面向接口代理的高性能 RPC 框架，提供服务注册与发现的特性，其基础架构如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/dubbo/2020-05-11/1.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(图 1）&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Provider&lt;/strong&gt; 为服务提供方，提供 Java 服务接口的实现，并将其元信息注册到 Dubbo 注册中心（过程 1.register 所示）&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Consumer&lt;/strong&gt; 为服务消费端，从 Dubbo 注册中心检索订阅的 Java 服务接口的元信息（过程 2.subscribe 所示），通过框架处理后，生成代理程序执行远程方法调用（过程 4.invoke 所示）&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Registry&lt;/strong&gt; 为注册中心，属于注册元信息中心化基础设施（如 Apache Zookeeper 或 Alibaba Nacos），为 Provider 提供注册通道，为 Cosumer 提供订阅渠道。同时，注册中心支持注册元信息变更通知，通知 Consumer 上游 Provider 节点的变化（如扩容或缩容）。而注册元信息均以 Dubbo URL 的形式存储&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Monitor&lt;/strong&gt; 为服务治理平台，提供开发和运维人员服务查询、路由规则、服务 Mock 和测试等治理能力&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;综上所述，&lt;strong&gt;Dubbo 注册与发现的对象是 Dubbo 服务（Java 接口&lt;/strong&gt;&lt;strong&gt;），而其载体为&lt;/strong&gt;&lt;strong&gt;注册元信息，即&lt;/strong&gt; &lt;strong&gt;Dubbo URL&lt;/strong&gt;，如：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo://192.168.1.2:20880/com.foo.BarService?version=1.0.0&amp;amp;group=default&lt;/code&gt;，通常包含必须信息，如服务提供方 IP 和端口、 Java 接口，可选包含版本（version）和分组（group）等。服务 URL 所包含的信息能够唯一界别服务提供方的进程。&lt;/p&gt;

&lt;h1 id=&quot;现实挑战&quot;&gt;现实挑战&lt;/h1&gt;

&lt;p&gt;为了更好地符合 Java 开发人员的编程习惯，Dubbo 以 Java 服务接口作为注册对象，所面临的现实挑战主要有：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;如何解决或缓解注册中心压力过载&lt;/li&gt;
  &lt;li&gt;如何支持以应用为粒度的服务注册与发现&lt;/li&gt;
  &lt;li&gt;如何精简 Dubbo URL 元数据&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;如何解决或缓解注册中心压力过载&quot;&gt;如何解决或缓解注册中心压力过载&lt;/h2&gt;

&lt;h3 id=&quot;注册中心内存压力&quot;&gt;注册中心内存压力&lt;/h3&gt;

&lt;p&gt;Dubbo 注册中心是中心化的基础设施，大多数注册中心的实现为内存型存储，比如 Zookeeper、Nacos 或 Consul、Eureka。注册中心的内存消耗与 Dubbo 服务注册的数量成正比，任一 Dubbo Provider 允许注册 N 个 Dubbo 服务接口，当 N 越大，注册中心的负载越重。根据不完全统计，Dubbo 核心 Provider 用通常会暴露 20 ~ 50 个服务接口。注册中心是中心化的基础设施，其稳定性面临严峻考验。尽管微服务架构不断地深化，然而现实情况是，更多开发者仍旧愿意在单一 Provider 上不断地增加 Dubbo 服务接口，而非更细粒度的 Dubbo Provider 组织。&lt;/p&gt;

&lt;h3 id=&quot;注册中心网络压力&quot;&gt;注册中心网络压力&lt;/h3&gt;

&lt;p&gt;为了避免单点故障，主流的注册中心均提供高可用方案。为解决集群环境数据同步的难题，内建一致性协议，如 Zookeeper 使用的 Zab 协议，Consul 采用的 Raft 协议。无论哪种方式，当 Dubbo URL 数量变化频繁时，网络和 CPU 压力也会面临考验。如果注册中心与客户端之间维持长连接状态的话，如 Zookeeper，注册中心的网络负担会更大。&lt;/p&gt;

&lt;h3 id=&quot;注册中心通知压力&quot;&gt;注册中心通知压力&lt;/h3&gt;

&lt;p&gt;假设某个 Dubbo Provider 注册了 N 个 Dubbo 服务接口，当它扩容或缩容 M 个实例（节点）时，N 数量越大，注册中心至少有 M * N 个 Dubbo URL 注册或移除。同时，大多数注册中心实现支持注册变化通知，如 Zookeeper 节点变化通知。当 Dubbo Consumer 订阅该 Provider 的 Dubbo 服务接口数为 X 时，X 数值越大，通知的次数也就越多。实际上，对于来自同一 Provider 的服务接口集合而言，X-1 次通知是重复和无价值的。&lt;/p&gt;

&lt;p&gt;如果 Dubbo 注册实体不再是服务 URL，而是 Dubbo Provider 节点的话，那么上述情况所描述的注册中心压力将得到很大程度的缓解。（负载只有过去的 1/N 甚至更少），然而 Dubbo 如何以应用为粒度来注册又是一个新的挑战。&lt;/p&gt;

&lt;h2 id=&quot;如何支持以应用为粒度的服务注册与发现&quot;&gt;如何支持以应用为粒度的服务注册与发现&lt;/h2&gt;

&lt;p&gt;尽管 Dubbo 也存在应用（Application）的概念，不过传统的使用场景并非核心要素，仅在 Dubbo Monitor 或 Dubbo Admin 场景下做辨识之用。随着微服务架构和云原生技术的兴起，以应用为粒度的注册模型已是大势所趋，如 Spring Cloud 和 Kubernetes 服务注册与发现模型。注册中心所管理的对象通常与业务无关，甚至不具备 RPC 的语义。在术语上，微服务架构中的“服务”（Services）与云原生中“应用”（Applications）是相同的概念，属于逻辑名称，而它们的成员则以服务实例（Service Instances）体现，服务和服务实例的数量关系为 1:N。&lt;/p&gt;

&lt;p&gt;单个服务实例代表一个服务进程，而多个 Dubbo 服务 URL 可隶属一个 Dubbo Provider 进程，因此，Dubbo URL 与服务实例的数量关系是 N : 1。假设一个 Dubbo Provider 进程仅提供一个 Dubbo 服务（接口）的话，即 N = 1 的情况，虽然以应用为粒度的服务注册与发现能够基于 Dubbo 传统的 Registry SPI 实现，不过对于现有 Dubbo 应用而言，将存在巨大的应用微服务化工作。&lt;/p&gt;

&lt;h3 id=&quot;支持-spring-cloud-服务注册与发现模型&quot;&gt;支持 Spring Cloud 服务注册与发现模型&lt;/h3&gt;

&lt;p&gt;Spring Cloud 是 VMware 公司（前为 Pivotal）推出的，一套以 Spring 为技术栈的云原生（Cloud-Native）解决方案，在 Java 微服务领域具备得天独厚的优势，拥有超大规模的全球用户。Spring Cloud 官方支持三种注册中心实现，包括：Eureka、Zookeeper 和 Consul，Spring Cloud Alibaba 扩展了 Nacos 注册中心实现。 尽管 Zookeeper、Consul 和 Nacos 也被 Apache Dubbo 官方支持，然而两者的服务注册与发现的机制不尽相同。&lt;/p&gt;

&lt;p&gt;若要 Dubbo 支持 Spring Cloud 服务注册与发现模型，Dubbo 则需基于 Dubbo Registry SPI 实现，否则底层的变化和兼容性存在风险。&lt;/p&gt;

&lt;h3 id=&quot;支持-kubernetes-服务注册与发现模型&quot;&gt;支持 Kubernetes 服务注册与发现模型&lt;/h3&gt;

&lt;p&gt;Kubernetes 源自 Google 15 年生产环境的运维经验，是一个可移植的、可扩展的开源平台，用于管理容器化的工作负载和服务。Kubernetes 原生服务发现手段主要包括：DNS 和 API Server。DNS 服务发现是一种服务地址的通用方案，不过对于相对复杂 Dubbo 元数据而言，这种服务发现机制或许无法直接被 Dubbo Registry SPI 适配。相反，API Server 所支持相对更便利，毕竟 &lt;a href=&quot;https://github.com/spring-cloud/spring-cloud-kubernetes&quot;&gt;Spring Cloud Kubernetes&lt;/a&gt; 同样基于此机制实现，并已在生产环境得到验证。换言之，只要 Dubbo 支持 Spring Cloud 服务注册与发现模型，那么基于 Kubernetes API Server 的支持也能实现。&lt;/p&gt;

&lt;h3 id=&quot;兼容-dubbo-传统服务注册与发现模型&quot;&gt;兼容 Dubbo 传统服务注册与发现模型&lt;/h3&gt;

&lt;p&gt;所谓兼容 Dubbo 传统服务注册与发现模型，包含两层含义：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;基于 Dubbo Registry SPI 同时支持 Spring Cloud 和 Kubernetes 服务注册与发现模型&lt;/li&gt;
  &lt;li&gt;传统和新的 Dubbo 服务注册与发现模型之间能够相互发现&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;如何精简-dubbo-url-元数据&quot;&gt;如何精简 Dubbo URL 元数据&lt;/h2&gt;

&lt;p&gt;Dubbo 从 2.7.0 开始增加了简化 URL 元数据的特性，被“简化”的数据存放至&lt;a href=&quot;http://dubbo.apache.org/en-us/docs/user/references/metadata/introduction.html&quot;&gt;元数据中心&lt;/a&gt;。由于 Dubbo 传统服务注册与发现模型并未减少 Dubbo 服务 URL 注册数量。因此，精简后的 URL 并未明显地减少注册中心所承受的压力。同时，Dubbo URL 元数据精简模式存在一定的限制，即所有的 Dubbo Provider 节点必须是无状态的，每个节点中的 URL 元信息均是一致的，现实中，这个要求非常难以保证，尤其在同一 Provider 节点存在不同的版本或配置的情况下。综上所述，Dubbo URL 元数据需要进一步精简，至少压力应该避免聚集在注册中心之上。&lt;/p&gt;

&lt;h1 id=&quot;架构设计&quot;&gt;架构设计&lt;/h1&gt;

&lt;p&gt;架构上，Dubbo 服务自省不仅要解决上述挑战，而且实际场景则更为复杂，因此，架构细节也将循序渐进地展开讨论，整体架构可由以下子架构组成：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;服务注册与发现架构&lt;/li&gt;
  &lt;li&gt;元数据服务架构&lt;/li&gt;
  &lt;li&gt;事件驱动架构&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;服务注册与发现架构&quot;&gt;服务注册与发现架构&lt;/h2&gt;

&lt;p&gt;Dubbo 服务自省首要需求是减轻注册中心的承载的压力，同时，以应用为粒度的服务注册与发现模型不但能够最大化的减少 Dubbo 服务元信息注册数量，而且还能支持 Spring Cloud 和 Kubernetes 环境，可谓是一举两得，架构图如下所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/dubbo/2020-05-11/2.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(图 2）&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;注册实体&quot;&gt;注册实体&lt;/h3&gt;

&lt;p&gt;图中所示，从 Provider 和 Consumer 向注册中心注册的实体不再是 Dubbo URL，而是服务实例（Service Instance），一个服务实例代表一个 Provider 或 Consumer Dubbo 应用进程。服务实例属性包括：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;服务名（Service Name）：该名称必须在注册中心全局唯一&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;注：名称规则架构上不做约束，不过不同注册中心的规则存在差异&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;主机地址（Host/IP）：能够被解析的主机名或者 TCP IP 地址&lt;/li&gt;
  &lt;li&gt;服务端口（Port）：应用进程所暴露的 Dubbo 协议端口，如 Dubbo 默认端口 20880&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;注：如果应用进程暴露多个 Dubbo 协议端口，如 dubbo 和 rest，那么，服务端口随机挑选其一，架构上不强制检验端口是否可用&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;元数据（Metadata）：服务实例的附加信息，用于存储 Dubbo 元信息，类似于通讯协议头或附件&lt;/li&gt;
  &lt;li&gt;激活状态（Enabled）：用于标记当前实例是否对外提供服务&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;上述&lt;strong&gt;服务实例模型的支持依赖于注册中心的实现&lt;/strong&gt;。换言之，并非所有注册中心实现满足服务自省架构的要求。&lt;/p&gt;

&lt;h3 id=&quot;注册中心&quot;&gt;注册中心&lt;/h3&gt;

&lt;p&gt;除了满足服务实例模型的要求之外，注册中心还得具备以下能力：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;服务实例变化通知（Notification）：如上图步骤 4 所示，当 Consumer 订阅的 Provider 的服务实例发生变化时，注册中心能够实时地通知 Consumer&lt;/li&gt;
  &lt;li&gt;心跳检测（Heartbeats）：注册中心能够检测失效的服务实例，并且合理地移除它们&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;业界主流的注册中心中满足上述要求的有：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Apache &lt;a href=&quot;https://zookeeper.apache.org/&quot;&gt;Zookeeper&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;HashiCorp &lt;a href=&quot;https://www.consul.io/&quot;&gt;Consul&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Netflix &lt;a href=&quot;https://github.com/netflix/Eureka&quot;&gt;Eureka&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Alibaba &lt;a href=&quot;https://nacos.io/&quot;&gt;Nacos&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Kubernetes API Server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;总之，&lt;strong&gt;Spring Cloud 与&lt;/strong&gt; &lt;strong&gt;Kubernetes&lt;/strong&gt; &lt;strong&gt;注册中心均符合服务自省对注册中心的要求&lt;/strong&gt;。不过，在 Dubbo 传统 RPC 使用场景中，Provider 和 Consumer 关注的是 Dubbo 服务接口，而非 Service 或服务实例。假设需要将现有的 Dubbo 应用迁移至服务自省架构，Provider 和 Consumer 做大量的代码调整是不现实的。理想的情况下，两端实现代码均无变化，仅修改少量配置，就能达到迁移的效果。那么，Dubbo 服务接口是如何与 Service 进行映射的呢？&lt;/p&gt;

&lt;h3 id=&quot;dubbo-服务与-service-映射&quot;&gt;Dubbo 服务与 Service 映射&lt;/h3&gt;

&lt;p&gt;前文曾讨论，单个 Dubbo Service 能够发布多个 Dubbo 服务，所以，Dubbo 服务与 Service 的数量关系是 N 对 1。不过，Dubbo 服务与 Dubbo Service 之间并不存在强绑定关系，换言之，某个 Dubbo 服务也能部署在多个 Dubbo Services 中，因此，Dubbo 服务与 Service 数量关系是 N 对 M（N, M &amp;gt;= 1），如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/dubbo/2020-05-11/3.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(图 3）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;上图中 P1 Service 到 P3 Service 为 Dubbo Service，com.acme.Interface1 到 com.acme.InterfaceN 则为 Dubbo 服务接口全称限定名（QFN）。值得注意的是，Dubbo 服务的 Java 接口（interface）允许不同的版本（version）或分组（group），所以仅凭 Java 接口无法唯一标识某个 Dubbo 服务，还需要增加通讯协议（protocol）方可，映射关系更新如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/dubbo/2020-05-11/4.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(图 4）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dubbo 服务 ID 字符表达模式为： &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${protocol}:${interface}:${version}:${group}&lt;/code&gt; , 其中，版本（version）或分组（group）是可选的。当 Dubbo Consumer 订阅 Dubbo 服务时，构建对应 ID，通过这个 ID 来查询 Dubbo Provider 的 Service 名称列表。&lt;/p&gt;

&lt;p&gt;由于 Dubbo 服务与 Service 的映射关系取决于业务场景，架构层面无从预判。因此，这种映射关系只能在 Dubbo 服务暴露时（运行时）才能确定，否则，Dubbo 服务能被多个 Consumer 应用订阅时，Consumer 无法定位 Provider Service 名称，进而无法完成服务发现。同时，映射关系的数据通常采用配置的方式来存储，服务自省提供两种配置实现，即 “中心化映射配置” 和 “本地化映射配置”。&lt;/p&gt;

&lt;h4 id=&quot;中心化映射配置&quot;&gt;中心化映射配置&lt;/h4&gt;

&lt;p&gt;明显地，注册中心来扮演动态映射配置的角色并不适合，不然，Dubbo Service 与映射关系在注册中心是平级的，无论在理解上，还是设计上是混乱的。结合 Dubbo 现有基础设施分析，这个存储设施可由 Dubbo 配置中心承担。&lt;/p&gt;

&lt;p&gt;其中 Dubbo 2.7.5 动态配置 API（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DynamicConfiguration&lt;/code&gt; ）支持二级结构，即：group 和 key，其中，group 存储 Dubbo 服务 ID，而 key 则关联对应的 Dubbo Service 名称，对应的 “图 4” 的数据结构则是：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/dubbo/2020-05-11/5.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(图 5）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;如此设计的原因如下：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;获取 Dubbo 服务对应 Services&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;利用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DynamicConfiguration#getConfigKeys(String group)&lt;/code&gt; 方法，能够轻松地通过 Dubbo 服务 ID 获取其发布的所有 Dubbo Services，结合服务发现接口获取服务所部署的 Service 实例集合，最终转化为  Dubbo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;URL&lt;/code&gt; 列表。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;避免 Dubbo Services 配置相互覆盖&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;以 Dubbo 服务 ID &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo:com.acme.Interface1:default&lt;/code&gt; 为例，它的提供者 Dubbo Services 分别：P1 Service 和 P2 Service。假设配置 Group 为 “default”（任意名字均可）， Key 为 “dubbo:com.acme.Interface1:default”，而内容则是 Dubbo Service 名称的话。当 P1 Service 和 P2 Service 同时启动时，无论哪个 Services 最后完成 Dubbo 服务暴露，那么，该配置内容必然是二选其一，无论配置中心是否支持原子操作。即使配置中心支持内容追加的特性，由于两个 Service 服务实例过程不确定，配置内容可能会出现重复，如：“P1 Service,P2 Service,P1 Service”。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;获取 Dubbo 服务发布的 timestamp&lt;/li&gt;
&lt;/ol&gt;

&lt;h5 id=&quot;配置中心潜在的压力&quot;&gt;配置中心潜在的压力&lt;/h5&gt;

&lt;p&gt;假设当 P1 Service 存在 5 个服务实例，当 Dubbo 服务 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo:com.acme.Interface1:default&lt;/code&gt;（ID）发布时，配置所关联的 key 就是当前 Dubbo Service 名称，即（P1 Service），而内容则是最后发布该 Dubbo 服务的时间戳（timestamp）。当服务实例越多时，配置中心和网络传输所承受的写入压力也就越大。当然架构设计上，服务自省也希望避免重复推送配置，比如在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DynamicConfiguration&lt;/code&gt; API 增加类似于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;publishConfigIfAbsent&lt;/code&gt; 这样的方法，不过目前大多数配置中心产品（如：Nacos、Consul）不支持这样的操作，所以未来服务自省架构会有针对性的提供支持（如：Zookeeper）。&lt;/p&gt;

&lt;h5 id=&quot;注册中心作为配置中心&quot;&gt;注册中心作为配置中心&lt;/h5&gt;

&lt;p&gt;由于服务自省架构必须依赖注册中心，同时动态映射配置又依赖配置中心的话，应用的架构复杂度和维护成本均有所提升，不过 Apache Dubbo 所支持的部分注册中心也可作为配置中心使用，情况如下所示：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;基础软件&lt;/th&gt;
      &lt;th&gt;注册中心&lt;/th&gt;
      &lt;th&gt;配置中心&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Apache &lt;a href=&quot;https://zookeeper.apache.org/&quot;&gt;Zookeeper&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;HashiCorp &lt;a href=&quot;https://www.consul.io/&quot;&gt;Consul&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Alibaba &lt;a href=&quot;https://nacos.io/&quot;&gt;Nacos&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Netflix &lt;a href=&quot;https://github.com/netflix/Eureka&quot;&gt;Eureka&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Kubernetes API Server&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;其中，&lt;a href=&quot;https://zookeeper.apache.org/&quot;&gt;Zookeeper&lt;/a&gt;、&lt;a href=&quot;https://www.consul.io/&quot;&gt;Consul&lt;/a&gt; 和 &lt;a href=&quot;https://nacos.io/&quot;&gt;Nacos&lt;/a&gt; 是目前业界流行的注册中心，这对于大多数选择开源产品的应用无疑是一个福音。&lt;/p&gt;

&lt;h4 id=&quot;本地化映射配置&quot;&gt;本地化映射配置&lt;/h4&gt;

&lt;p&gt;如果开发人员认为配置中心的引入增加了架构的复杂性，那么，静态映射配置或许是一种解决方案。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;该特性并未在最新 Dubbo 2.7.6 全面发布，部分特性已在 &lt;a href=&quot;https://github.com/alibaba/spring-cloud-alibaba/wiki/Dubbo-Spring-Cloud&quot;&gt;Dubbo Spring Cloud&lt;/a&gt; 中发布&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5 id=&quot;接口映射配置&quot;&gt;接口映射配置&lt;/h5&gt;

&lt;p&gt;在 Dubbo 传统的编程模型中， 常以 Java 注解 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Reference&lt;/code&gt; 或 XML 元素 `` 订阅目标 Dubbo 服务。服务自省架构在此基础上增加 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;service&lt;/code&gt; 属性的映射一个或多个 Dubbo Service 名称，如：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&amp;lt;reference services=&quot;P1 Service,P2 Service&quot; interface=&quot;com.acme.Interface1&quot; /&amp;gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;或&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;@Reference(services=&quot;P1 Service,P2 Service&quot;) 
private com.acme.Interface1 interface1;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如此配置后，Dubbo 服务 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.acme.Interface1&lt;/code&gt; 将向 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p1-service&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p2-service&lt;/code&gt; 订阅服务。如果开发人员认为这种方式会侵入到代码，服务自省还提供外部化配置方式配置映射。&lt;/p&gt;

&lt;h5 id=&quot;外部化映射配置&quot;&gt;外部化映射配置&lt;/h5&gt;

&lt;p&gt;服务自省架构支持外部化配置的方式声明“Dubbo 服务与 Service 映射”，配置格式为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Properties&lt;/code&gt; ，以图 4 为例，内容如下：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;dubbo\:com.acme.Interface1\:default = P1 Service,P2 Service
thirft\:com.acme.InterfaceX = P1 Service,P3 Service
rest\:com.acme.interfaceN = P1 Service
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;应用级别映射配置&quot;&gt;应用级别映射配置&lt;/h5&gt;

&lt;p&gt;除此之外，&lt;a href=&quot;https://github.com/alibaba/spring-cloud-alibaba/wiki/Dubbo-Spring-Cloud&quot;&gt;Dubbo Spring Cloud&lt;/a&gt; 提供应用级别的 Dubbo 服务映射配置，即 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.cloud.subscribed-services&lt;/code&gt; ，例如：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;dubbo:
    cloud:
    subscribed-services: P1 Service,P3 Service
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;总之，无论是映射配置的方式是中心化还是本地化，服务 Consumer 依赖这些数据来定位 Dubbo Provider Services，再通过服务发现 API 结合 Service 名称（列表）获取服务实例集合，为合成 Dubbo URL 做准备：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/dubbo/2020-05-11/6.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(图 6）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;不过，映射关系并非是一种强约束，Dubbo Provider 的服务是否可用的检验方法是探测目标 Dubbo Service 是否存在，并需确认订阅的 Dubbo 服务在目标 Services 是否真实暴露，因此，服务自省引入了 Dubbo 元数据服务架构，来完成 Dubbo 服务 URL 的存储。&lt;/p&gt;

&lt;h2 id=&quot;元数据服务架构&quot;&gt;元数据服务架构&lt;/h2&gt;

&lt;p&gt;Dubbo 元数据服务是一个常规的 Dubbo 服务，为服务订阅端提供 Dubbo 元数据的服务目录，类似于 WebServices 中的 &lt;a href=&quot;https://en.wikipedia.org/wiki/Web_Services_Description_Language&quot;&gt;WDSL&lt;/a&gt; 或 REST 中的 &lt;a href=&quot;https://en.wikipedia.org/wiki/HATEOAS&quot;&gt;HATEOAS&lt;/a&gt;，帮助 Dubbo Consumer 获取订阅的 Dubbo 服务的 URL 列表。元数据服务架构无法独立于服务注册与发现架构而存在，下面通过“整体架构”的讨论，了解两者之间的关系。&lt;/p&gt;

&lt;h3 id=&quot;整体架构&quot;&gt;整体架构&lt;/h3&gt;

&lt;p&gt;架构上，无论 Dubbo Service 属于 Provider 还是 Consumer，甚至是两者的混合，每个 Dubbo （Service）服务实例有且仅有一个 Dubbo 元数据服务。换言之，Dubbo Service 不存在纯粹的 Consumer，即使它不暴露任何业务服务，那么它也可能是 Dubbo 运维平台（如 Dubbo Admin）的 Provider。不过出于行文的习惯，Consumer 仍旧被定义为 Dubbo 服务消费者（应用）。由于每个 Dubbo Service 均发布自身的 Dubbo 元数据服务，那么，架构不会为不同的 Dubbo Service 设计独立的元数据服务接口（Java）。换言之，所有的 Dubbo Service 元数据服务接口是统一的，命名为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 。&lt;/p&gt;

&lt;h4 id=&quot;微观架构&quot;&gt;微观架构&lt;/h4&gt;

&lt;p&gt;从 Dubbo 服务（URL）注册与发现的视角， &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 扮演着传统 Dubbo 注册中心的角色。综合服务注册与发现架构（Dubbo Service 级别），微观架构如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/dubbo/2020-05-11/7.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(图 7）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;**
**&lt;/p&gt;

&lt;p&gt;对于 Provider（服务提供者）而言，Dubbo 应用服务暴露与传统方式无异，而 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 的暴露时机必须在它们完成后，同时， &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 需要收集这些 Dubbo 服务的 URL（存储细节将在“元数据服务存储模式“ 小节讨论）。假设某个 Provider 的 Dubbo 应用服务暴露数量为 N，那么，它所有的 Dubbo 服务暴露数量为 N + 1。&lt;/p&gt;

&lt;p&gt;对于 Consumer（服务消费者）而言，获 Dubbo 应用服务订阅 URL 列表后，Dubbo 服务调用的方式与传统方式是相同的。不过在此之前，Consumer 需要通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 合成订阅 Dubbo 服务的 URL。该过程之所以称之为“合成”，而非“获取，是因为一次 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 服务调用仅在其 Provider 中的一台服务实例上执行，而该 Provider 可能部署了 N 个服务实例。具体“合成”的细节需要结合“宏观架构”来说明。&lt;/p&gt;

&lt;h4 id=&quot;宏观架构&quot;&gt;宏观架构&lt;/h4&gt;

&lt;p&gt;元数据服务的宏观架构依赖于服务注册与发现架构，如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/dubbo/2020-05-11/8.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(图 8）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;图 8 中 p 和 c 分别代表 Provider 和 Consumer 的执行动作，后面紧跟的数字表示动作的次序，从 0 开始计数。执行动作是串行的，并属于 Fast-Fail 设计，如果前阶段执行失败，后续动作将不会发生。之所以如此安排是为了确保 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 能够暴露和消费。首先从 Provider 执行流程开始说明。&lt;/p&gt;

&lt;h5 id=&quot;provider-执行流程&quot;&gt;Provider 执行流程&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;p0：发布所有的 Dubbo 应用服务，声明和定义方式与传统方式完全相同。&lt;/li&gt;
  &lt;li&gt;p1：暴露 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; ，该步骤完全由框架自行处理，无论是否 p0 是否暴露 Dubbo 服务&lt;/li&gt;
  &lt;li&gt;p2：在服务实例注册之前， 框架将触发并处理事件（Event），将 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 的元数据先同步到服务实例（Service Instance）的元数据。随后，执行服务实例注册&lt;/li&gt;
  &lt;li&gt;p3：建立所有的 Dubbo 应用服务与当前 Dubbo Service 名称的映射，并同步到配置源（抽象）&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&quot;consumer-执行流程&quot;&gt;Consumer 执行流程&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;c0：注册当前 Dubbo Service 的服务实例，可选步骤，架构允许 Consumer 不进行服务注册&lt;/li&gt;
  &lt;li&gt;c1：通过订阅 Dubbo 服务元信息查找配置源，获取对应 Dubbo Services 名称（列表）&lt;/li&gt;
  &lt;li&gt;c2：利用已有 Dubbo Service 名称（可能存在多个），通过服务发现 API 获取 Provider 服务实例集合。假设 Service 名称 P，服务实例数量为 N&lt;/li&gt;
  &lt;li&gt;c3：&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;ol&gt;
      &lt;li&gt;随机选择 Provider 一台服务实例 Px，从中获取 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 的元数据&lt;/li&gt;
      &lt;li&gt;将元数据组装 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; Dubbo 调用客户端（代理）&lt;/li&gt;
      &lt;li&gt;发起 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; Dubbo 调用，获取该服务实例 Px 所暴露的 Dubbo 应用服务 URL 列表&lt;/li&gt;
      &lt;li&gt;从 Dubbo 应用服务 URL 列表过滤出当前订阅 Dubbo 应用服务的 URL&lt;/li&gt;
      &lt;li&gt;理论上，步骤 c 和 d 还需要执行 N-1 次才能获取 P 所有服务实例的 Dubbo URL 列表。为了减少调用次数，步骤 d 的结果作为模板，克隆其他 N-1 台服务实例 URL 列表&lt;/li&gt;
      &lt;li&gt;将所有订阅 Dubbo 应用服务的 URL 同步到 Dubbo 客户端（与传统方式是相同的）&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
  &lt;li&gt;c4：发起 Dubbo 应用服务调用（与传统方式是相同的）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;不难看出，上述架构以及流程结合了“服务注册与发现”与“元数据服务”双架构，步骤之间会触发相关 Dubbo 事件，如“服务实例注册前事件”等。换言之，三种架构综合体也就是服务自省架构。&lt;/p&gt;

&lt;p&gt;至此，关于 Dubbo 服务自省架构设计方面，还存在一些细节亟待说明，比如：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;不同的 Dubbo Service 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 怎样体现差异呢？&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 作为一个常规的 Dubbo 服务，它的注册元信息存放在何处？&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 作为服务目录，它管理的 Dubbo 应用服务 URL 是如何存储的？&lt;/li&gt;
  &lt;li&gt;在 Consumer 执行流程的 c3.e 中，克隆 N - 1 条 URL 的前提是该 Provider 的所有服务实例均部署了相同 Dubbo 应用服务。如果 Provider 处于升级的部署过程，同一 Dubbo 应用服务接口在不同的服务实例上存在差异，那么该服务的 URL 应该如何获取？&lt;/li&gt;
  &lt;li&gt;除了 Dubbo 服务 URL 发现之外，元数据服务还支持哪些元数据类型呢？&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;元数据服务-metadata&quot;&gt;元数据服务 Metadata&lt;/h3&gt;

&lt;p&gt;元数据服务 Metadata，称之为“元数据服务的元数据”，主要包括：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;inteface：Dubbo 元数据服务所暴露的接口，即 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;serviceName : 当前 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 所部署的 Dubbo Service 名称，作为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 分组信息&lt;/li&gt;
  &lt;li&gt;group：当前 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 分组，数据使用 serviceName&lt;/li&gt;
  &lt;li&gt;version：当前 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 的版本，版本号通常在接口层面声明，不同的 Dubbo 发行版本 version 可能相同，比如 Dubbo 2.7.5 和 2.7.6 中的 version 均为 1.0.0。理论上，version 版本越高，支持元信息类型更丰富&lt;/li&gt;
  &lt;li&gt;protocol： &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 所暴露协议，为了确保 Provider 和 Consumer 通讯兼容性，默认协议为：“dubbo”，也可以支持其他协议。&lt;/li&gt;
  &lt;li&gt;port：协议所使用的网络端口&lt;/li&gt;
  &lt;li&gt;host：当前 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 所在的服务实例主机或 IP&lt;/li&gt;
  &lt;li&gt;params：当前 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 暴露后 URL 中的参数信息&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;不难得出，凭借以上元数据服务的 Metadata，可将元数据服务的 Dubbo 服务 ID 确定，辅助 Provider 服务暴露和 Consumer 服务订阅 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 。不过对于 Provider，这些元信息都是已知的，而对 Consumer 而言，它们直接能获取的元信息仅有：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;serviceName：通过“Dubbo 接口与 Service 映射”关系，可得到 Provider Service 名称&lt;/li&gt;
  &lt;li&gt;interface：即 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; ，因为 Provider 和 Consumer 公用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 接口&lt;/li&gt;
  &lt;li&gt;group：即 serviceName&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;不过 Consumer 合成 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; Dubbo URL 还需获取 version、host、port、protocol 以及 params：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;version：尽管 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 接口是统一接口，然而 Provider 和 Consumer 可能引入的 Dubbo 版本不同，从而它们使用的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; version 也会不同，所以这个信息需要 Provider 在暴露&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 时，同步到服务实例的 Metadata 中，方便 Consumer 从 Metadata 中获取&lt;/li&gt;
  &lt;li&gt;host：由于 Consumer 已得到 serviceName，可通过服务发现 API 获取服务实例对象，该对象包含 host 属性，直接被 Consumer 获取即可。&lt;/li&gt;
  &lt;li&gt;port：与 version 类似，从 Provider 服务实例中的 Metadata 中获取&lt;/li&gt;
  &lt;li&gt;params：同上&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;通过元数据服务 Metadata 的描述，解释了不同 Dubbo Services 是怎样体现差异性的，并且说明了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 元信息的存储介质，这也就是服务自省架构为什么强依赖支持 Metadata 的注册中心的原因。下个小节将讨论 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 所存储 Dubbo 应用服务 URL 存放在何处。&lt;/p&gt;

&lt;h3 id=&quot;元数据服务存储模式&quot;&gt;元数据服务存储模式&lt;/h3&gt;

&lt;p&gt;Dubbo 2.7.5 在引入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 的同时，也为其设计了两种存储方式，适用于不同的场景，即“本地存储模式”和“远程存储模式”。其中，本地存储模式是默认选项。&lt;/p&gt;

&lt;h4 id=&quot;元数据服务本地存储模式&quot;&gt;元数据服务本地存储模式&lt;/h4&gt;

&lt;p&gt;本地存储模式又称之为内存存储模式（In-Memory），如 Dubbo 应用服务发现和注册场景中，暴露和订阅的 URL 直接存储在内存中。架构上，本地存储模式的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 相当于去中心化的 Dubbo 应用服务的注册中心。&lt;/p&gt;

&lt;h4 id=&quot;元数据服务远程存储模式&quot;&gt;元数据服务远程存储模式&lt;/h4&gt;

&lt;p&gt;远程存储模式，与去中心化的本地存储模式相反，采用 Dubbo 元数据中心来管理 Dubbo 元信息，又称之为元中心化存储模式（Metadata Center)。&lt;/p&gt;

&lt;h4 id=&quot;选择存储模式&quot;&gt;选择存储模式&lt;/h4&gt;

&lt;p&gt;为了减少负载压力和维护成本，服务自省中的元数据服务推荐使用&lt;strong&gt;“&lt;/strong&gt;&lt;strong&gt;本&lt;/strong&gt;&lt;strong&gt;地存储模式”&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;回顾前文“Consumer 执行流程”中的步骤 c3.e，为了减少 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 调用次数，服务自省将第一次的调用结果作为模板，再结合其他 N-1 服务实例的元信息，合成完整的 N 台服务实例的 Dubbo 元信息。假设，Dubbo Service 服务实例中部署的 Dubbo 服务数量和内容不同，那么，c3.e 的执行步骤是存在问题的。因此，服务自省引入“&lt;strong&gt;Dubbo 服务修订版本&lt;/strong&gt;”的机制来解决不对等部署的问题。&lt;/p&gt;

&lt;p&gt;尽管“Dubbo 服务修订版本”机制能够介绍 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 整体消费次数，然而当新修订版本的服务实例过少，并且 Consumer 过多时，如新的版本 Provider 应用分批部署，每批的服务实例为 1 台，而其 Consumer 服务实例成千上万。为了确保这类场景的稳定性，Provider 和 Consumer 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 可选择“&lt;strong&gt;远程存储模式&lt;/strong&gt;”，避免消费热点的发生。&lt;/p&gt;

&lt;h3 id=&quot;dubbo-服务修订版本&quot;&gt;Dubbo 服务修订版本&lt;/h3&gt;

&lt;p&gt;当业务出现变化时，Dubbo Service 的 Dubbo 服务也会随之升级。通常，Provider 先行升级，Consumer 随后跟进。&lt;/p&gt;

&lt;p&gt;考虑以下场景，Provider “P1” 线上已发布 interface 为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.acme.Interface1&lt;/code&gt;，group 为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;group&lt;/code&gt; , version 为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v1&lt;/code&gt; ，即 Dubbo 服务 ID 为：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo:com.acme.Interface1:v1:default&lt;/code&gt; 。P1 可能出现升级的情况有：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Dubbo 服务 interface 升级&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;由于 Dubbo 基于 Java 接口来暴露服务，同时 Java 接口通常在 Dubbo 微服务中又是唯一的。如果 interface 的全类名调整的话，那么，相当于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.acme.Interface1&lt;/code&gt; 做下线处理，Consumer 将无法消费到该 Dubbo 服务，这种情况不予考虑。如果是 Provider 新增服务接口的话，那么 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.acme.Interface1&lt;/code&gt; 则并没有变化，也无需考虑。所以，有且仅有一种情况考虑，即“&lt;strong&gt;Dubbo interface 方法声明升级&lt;/strong&gt;”，包括：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;增加服务方法&lt;/li&gt;
  &lt;li&gt;删除服务方法&lt;/li&gt;
  &lt;li&gt;修改方法签名&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
  &lt;li&gt;Dubbo 服务 group、version 和 protocol 升级&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;假设 P1 在升级过程中，新的服务实例部署仅存在调整 group 后的 Dubbo 服务，如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo:com.acme.Interface1:v1:test&lt;/code&gt; ，那么这种升级就是不兼容升级，在新老交替过程中，Consumer 仅能消费到老版本的 Dubbo 服务。当新版本完全部署完成后，Consumer 将无法正常服务调用。如果，新版本中 P1 同时部署了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo:com.acme.Interface1:v1:default&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo:com.acme.Interface1:v1:test&lt;/code&gt; 的话，相当于 group 并无变化。同理，version 和 protocol 变化，相当于 Dubbo 服务 ID 变化，&lt;strong&gt;这类情况无需处理&lt;/strong&gt;。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Dubbo 服务元数据升级&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这是一种比较特殊的升级方法，即 Provider 所有服务实例 Dubbo 服务 ID 相同，然而 Dubbo 服务的参数在不同版本服务实例存在差异，假设 Dubbo Service P1 部署 5 台服务，其中 3 台服务实例设置 timeout 为 1000 ms，其余 2 台 timeout 为 3000 ms。换言之，P1 拥有两个版本（状态）的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 。&lt;/p&gt;

&lt;p&gt;综上所述，无论是 Dubbo interface 方法声明升级，还是 Dubbo 服务元数据升级，均可认为是 Dubbo 服务升级的因子，这些因子所计算出来的数值称之为“Dubbo 服务修订版本”，服务自省架构将其命名为“&lt;strong&gt;revision&lt;/strong&gt;”。架构设设计上，当 Dubbo Service 增加或删除服务方法、修改方法签名以及调整 Dubbo 服务元数据，revision 也会随之变化，revision 数据将存放在其 Dubbo 服务实例的 metadata 中。当 Consumer 订阅 Provider Dubbo 服务元信息时，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 远程调用的次数取决于服务实例列表中出现 revision 的个数，整体执行流程如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/dubbo/2020-05-11/9.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(图 9）&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Consumer 通过服务发现 API 向注册中心获取 Provider 服务实例列表&lt;/li&gt;
  &lt;li&gt;注册中心返回 6 台服务实例，其中 revision 为 1 的服务实例为 Instance 1 到 3, revision 为 2 的服务实例是 Instance 4 和 Instance 5，revision 为 3 的服务实例仅有 Instance 6&lt;/li&gt;
  &lt;li&gt;Consumer 在这 6 台服务实例中随机选择一台，如图中 Instance 3&lt;/li&gt;
  &lt;li&gt;Consumer 向 Instance 3 发起 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 的远程调用，获得 Dubbo URL 列表，并建立 revision 为 1 的 URL 列表缓存，用 cache = { 1:urls(r1) } 表示&lt;/li&gt;
  &lt;li&gt;（重复步骤 4）Consumer 再从剩余的 5 台服务实例中随机选择一台，如图中的 Instance 5，由于 Instance 5 与 Instance 3 的 revision 分为为 2 和 1，此时缓存 cache = { 1:urls(r1) } 未命中，所以 Consumer 将再次发起远程调用，获取新的 Dubbo URL 列表，并更新缓存，即 cache = { 1:urls(r1) , 2:urls(r2) }&lt;/li&gt;
  &lt;li&gt;（重复步骤 4）Consumer 再从剩余的 4 台服务实例中随机选择一台，假设服务实例是 Instance 6，由于此时 revision 为3，所以缓存 cache = { 1:urls(r1) , 2:urls(r2) } 再次未命中，再次发起远程调用，并更新缓存 cache = { 1:urls(r1) , 2:urls(r2) , 3:urls(r3) }&lt;/li&gt;
  &lt;li&gt;（重复步骤 4）由于缓存 cache = { 1:urls(r1) , 2:urls(r2) , 3:urls(r3) } 已覆盖三个 revision 场景，如果该步骤选择服务实例落在 revision 为 1 的子集中，只需克隆 urls(r1)，并根据具体服务实例替换部分 host 和 port 等少量元信息即可，组成成新的 Dubbo URL 列表，依次类推，计算直到剩余服务实例为 0。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;大多数情况，revision 的数量不会超过 2，换言之，Consumer 发起 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 的远程调用不会超过 2次。无论 revision 数量的大小，架构能够保证获取 Dubbo 元信息的正确性。&lt;/p&gt;

&lt;p&gt;当然  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 并非仅支持 Dubbo URL 元数据，还有其他类型的支持。&lt;/p&gt;

&lt;h3 id=&quot;元数据类型&quot;&gt;元数据类型&lt;/h3&gt;

&lt;p&gt;架构上，元数据服务（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt;）未来将逐步替代 Dubbo 2.7.0 &lt;a href=&quot;http://dubbo.apache.org/zh-cn/docs/user/references/metadata/introduction.html&quot;&gt;元数据中心&lt;/a&gt;，并随着 Dubbo 版本的更迭，所支持的元数据类型也将有所变化，比如 Dubbo 2.7.5 元数据服务支持的类型包括：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Dubbo 暴露的服务 URL 列表&lt;/li&gt;
  &lt;li&gt;Dubbo 订阅的服务 URL 列表&lt;/li&gt;
  &lt;li&gt;Dubbo 服务定义&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;dubbo-暴露的服务-url-列表&quot;&gt;Dubbo 暴露的服务 URL 列表&lt;/h4&gt;

&lt;p&gt;当前 Dubbo Service 暴露或发布 Dubbo 服务 URL 集合，如：[ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo://192.168.1.2:20880/com.acme.Interface1?group=default&amp;amp;version=v1&lt;/code&gt; , &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thirft://192.168.1.2:20881/com.acme.InterfaceX&lt;/code&gt; , &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rest://192.168.1.2:20882/com.acme.interfaceN&lt;/code&gt; ]&lt;/p&gt;

&lt;h4 id=&quot;dubbo-订阅的服务-url-列表&quot;&gt;Dubbo 订阅的服务 URL 列表&lt;/h4&gt;

&lt;p&gt;当前 Dubbo Service 所有订阅的 Dubbo 服务 URL 集合，该元数据主要被 Dubbo 运维平台来收集。&lt;/p&gt;

&lt;h4 id=&quot;dubbo-服务定义&quot;&gt;Dubbo 服务定义&lt;/h4&gt;

&lt;p&gt;Dubbo 服务提供方（Provider）在服务暴露的过程中，将元信息以 JSON 的格式同步到注册中心，包括服务配置的全部参数，以及服务的方法信息（方法名，入参出参的格式）。在服务自省引入之前，该元数据被 Dubbo 2.7.0 &lt;a href=&quot;http://dubbo.apache.org/zh-cn/docs/user/references/metadata/introduction.html&quot;&gt;元数据中心&lt;/a&gt; 存储，如：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;{
 &quot;parameters&quot;: {
  &quot;side&quot;: &quot;provider&quot;,
  &quot;methods&quot;: &quot;sayHello&quot;,
  &quot;dubbo&quot;: &quot;2.0.2&quot;,
  &quot;threads&quot;: &quot;100&quot;,
  &quot;interface&quot;: &quot;org.apache.dubbo.samples.metadatareport.configcenter.api.AnnotationService&quot;,
  &quot;threadpool&quot;: &quot;fixed&quot;,
  &quot;version&quot;: &quot;1.1.1&quot;,
  &quot;generic&quot;: &quot;false&quot;,
  &quot;revision&quot;: &quot;1.1.1&quot;,
  &quot;valid&quot;: &quot;true&quot;,
  &quot;application&quot;: &quot;metadatareport-configcenter-provider&quot;,
  &quot;default.timeout&quot;: &quot;5000&quot;,
  &quot;group&quot;: &quot;d-test&quot;,
  &quot;anyhost&quot;: &quot;true&quot;
 },
 &quot;canonicalName&quot;: &quot;org.apache.dubbo.samples.metadatareport.configcenter.api.AnnotationService&quot;,
 &quot;codeSource&quot;: &quot;file:/../dubbo-samples/dubbo-samples-metadata-report/dubbo-samples-metadata-report-configcenter/target/classes/&quot;,
 &quot;methods&quot;: [{
  &quot;name&quot;: &quot;sayHello&quot;,
  &quot;parameterTypes&quot;: [&quot;java.lang.String&quot;],
  &quot;returnType&quot;: &quot;java.lang.String&quot;
 }],
 &quot;types&quot;: [{
  &quot;type&quot;: &quot;java.lang.String&quot;,
  &quot;properties&quot;: {
   &quot;value&quot;: {
    &quot;type&quot;: &quot;char[]&quot;
   },
   &quot;hash&quot;: {
    &quot;type&quot;: &quot;int&quot;
   }
  }
 }, {
  &quot;type&quot;: &quot;int&quot;
 }, {
  &quot;type&quot;: &quot;char&quot;
 }]
}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;更多元数据类型支持&quot;&gt;更多元数据类型支持&lt;/h4&gt;

&lt;p&gt;在架构上，元数据服务（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt;）所支持元数据类型是不限制的，如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/dubbo/2020-05-11/10.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(图 10）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;除上文曾讨论的三种元数据类型，还包括“Dubbo 服务 REST 元信息” 和 “其他元信息”。其中，Dubbo 服务 REST 元信息包含 Dubbo 服务 与 REST 映射信息，可用于 Dubbo 服务网关，而其他元信息可能包括 Dubbo 服务 JavaDoc 元信息，可用于 Dubbo API 文档。&lt;/p&gt;

&lt;h3 id=&quot;元数据服务升级&quot;&gt;元数据服务升级&lt;/h3&gt;

&lt;p&gt;考虑到 Dubbo Provider 和 Consumer 可能依赖不同发行版本的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; ，因此，Provider 提供的和 Consumer 所需要的元数据类型并不对等，如 Provider 使用 Dubbo 版本为 2.7.5，该发行版本仅支持“Dubbo 暴露的服务 URL 列表”，“Dubbo 订阅的服务 URL 列表”和“Dubbo 服务定义”，这三种元数据分别来源于接口的三个方法。当 Consumer 使用了更高的 Dubbo 版本，并需要获取“Dubbo 服务 REST 元信息”时，自然无法从 Provider 端获取。假设 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 为其新增一个方法，那么，当 Consumer 发起调用时，那么这个调用自然会失败。即使两端使用的版本相同，那么 Provider 仍有可能选择性支持特定的元数据类型。为了确保元数据接口的兼容性，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 应具备元数据类型支持的判断。如此设计，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MetadataService&lt;/code&gt; 在元数据类型上支持更具有弹性。&lt;/p&gt;

&lt;h2 id=&quot;事件驱动架构&quot;&gt;事件驱动架构&lt;/h2&gt;

&lt;p&gt;相较于传统的 Dubbo 架构，服务自省架构的执行流程更为复杂，执行动作之间的关联非常紧密，如 Dubbo Service 服务实例注册前需要完成 Dubbo 服务 revision 的计算，并将其添加至服务实例的 metadata 中。又如当 Dubbo Service 服务实例出现变化时，Consumer 元数据需要重新计算。这些动作被 “事件”（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Event&lt;/code&gt;）驱动，驱动者被定义为“事件分发器”（ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EventDispatcher&lt;/code&gt; ），而动作的处理则由“事件监听器”（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EventListener&lt;/code&gt;）执行，三者均为 “&lt;strong&gt;Dubbo 事件&lt;/strong&gt;“的核心组件，同样由 Dubbo 2.7.5 引入。不过，Dubbo 事件是相对独立的架构，不过被服务自省中的“服务注册与发现架构”和“元数据服务架构”依赖。&lt;/p&gt;

&lt;h3 id=&quot;dubbo-内建事件&quot;&gt;Dubbo 内建事件&lt;/h3&gt;

&lt;p&gt;Dubbo 内建事件可归纳为以下类型：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Dubbo 服务类型事件&lt;/li&gt;
  &lt;li&gt;Dubbo Service 类型事件&lt;/li&gt;
  &lt;li&gt;Dubbo 服务实例类型事件&lt;/li&gt;
  &lt;li&gt;Dubbo 服务注册和发现类型事件&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;dubbo-服务类型事件&quot;&gt;Dubbo 服务类型事件&lt;/h4&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;事件类型&lt;/th&gt;
      &lt;th&gt;事件触发时机&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceConfigExportedEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务暴露完成时&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceConfigUnexportedEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务下线后&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReferenceConfigInitializedEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务引用初始化后&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReferenceConfigDestroyedEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务引用销毁后&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 id=&quot;dubbo-service-类型事件&quot;&gt;Dubbo Service 类型事件&lt;/h4&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;事件类型&lt;/th&gt;
      &lt;th&gt;事件触发时机&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DubboShutdownHookRegisteredEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo ShutdownHook 注册后&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DubboShutdownHookUnregisteredEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo ShutdownHook 注销后&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DubboServiceDestroyedEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 进程销毁后&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 id=&quot;dubbo-服务实例类型事件&quot;&gt;Dubbo 服务实例类型事件&lt;/h4&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;事件类型&lt;/th&gt;
      &lt;th&gt;事件触发时机&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceInstancePreRegisteredEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务实例注册前&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceInstanceRegisteredEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务实例注册后&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceInstancePreUnregisteredEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务实例注销前&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceInstanceUnregisteredEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务实例注销后&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceInstancesChangedEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 某个 Dubbo Service 下的服务实例列表变更时&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 id=&quot;dubbo-服务注册和发现类型事件&quot;&gt;Dubbo 服务注册和发现类型事件&lt;/h4&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;事件类型&lt;/th&gt;
      &lt;th&gt;事件触发时机&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceDiscoveryInitializingEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务注册与发现组件初始化中&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceDiscoveryInitializedEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务注册与发现组件初始化后&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceDiscoveryExceptionEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务注册与发现组件异常发生时&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceDiscoveryDestroyingEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务注册与发现组件销毁中&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServiceDiscoveryDestroyedEvent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;当 Dubbo 服务注册与发现组件销毁后&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h1 id=&quot;结束语&quot;&gt;结束语&lt;/h1&gt;

&lt;h1 id=&quot;whats-the-next&quot;&gt;What’s the next?&lt;/h1&gt;
</description>
        <pubDate>Mon, 11 May 2020 00:00:00 +0000</pubDate>
        <link>https://weibo.com/mercyblitz/2020/05/11/Apache-Dubbo-%E6%9C%8D%E5%8A%A1%E8%87%AA%E7%9C%81%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/</link>
        <guid isPermaLink="true">https://weibo.com/mercyblitz/2020/05/11/Apache-Dubbo-%E6%9C%8D%E5%8A%A1%E8%87%AA%E7%9C%81%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/</guid>
        
        
      </item>
    
      <item>
        <title>2019 java 趋势报告 infoq 采访稿（小马哥部分）</title>
        <description>&lt;h3 id=&quot;趋势报告框架&quot;&gt;趋势报告框架&lt;/h3&gt;

&lt;h4 id=&quot;第一部分java的技术采用生命周期&quot;&gt;第一部分：Java的技术采用生命周期&lt;/h4&gt;

&lt;p&gt;这部分采用与英文站同样的标准划分：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;创新者&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;早期采用者&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;早期大众&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;晚期大众&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;技术采用生命周期是美国高科技营销大师杰弗里·摩尔在自己的书《跨越鸿沟》里提出的概念。技术采用生命周期是一个用来衡量用户对某项新技术接受程度的模型，它认为一个新的技术，从一开始出现到最后走向成熟，必然会经历创新者、早期采用者、早期大众、晚期大众的阶段。&lt;/p&gt;

&lt;p&gt;虽然每个人群间都会有裂缝，但是早期采用者和早期大众之间的那条裂缝最大，这条裂缝就是传说中的“鸿沟”，只有跨越过这条鸿沟，渗透到早期大众这个人群，产品才等于是进入了主流市场。&lt;/p&gt;

&lt;p&gt;希望您结合国内使用和发展情况，把以下技术对应到技术采用生命周期相应的不同阶段中：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Java/JVM
    &lt;ul&gt;
      &lt;li&gt;Java版本（8～13）；&lt;/li&gt;
      &lt;li&gt;OpenJDK定制版或者公开发行版，Oracle JDK, OpenJDK by Oracle/Redhat/Azul/Alibaba/Amazon, 或者其他；&lt;/li&gt;
      &lt;li&gt;非Hotspot JDK生产实践，如GraalVM、IBM OpenJ9；&lt;/li&gt;
      &lt;li&gt;语法与特性，例如：Lambda /Stream、Vector API等（可以从是否有哪些特性带来了突出甚至不可替代的生产价值的角度，评判他们在技术采用生命周期中的位置）；&lt;/li&gt;
      &lt;li&gt;JVM语言，Kotlin、Scala、Groovy、其他；&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;不同层次的主流框架：Java EE（Jakarta EE）、Spring Framework、RxJava 、Vert.x、Netty；&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;微服务领域：Spring Boot/Cloud、Dubbo、TarsJava、ServiceComb、其他&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;小马哥（@mercyblitz）&lt;/a&gt;：&lt;/p&gt;

  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;创新者&lt;/th&gt;
        &lt;th&gt;早期采用者&lt;/th&gt;
        &lt;th&gt;早期大众&lt;/th&gt;
        &lt;th&gt;晚期大众&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;Java 13&lt;/td&gt;
        &lt;td&gt;Java 11&lt;/td&gt;
        &lt;td&gt;OpenJDK&lt;/td&gt;
        &lt;td&gt;Java 8&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Jakarta EE&lt;/td&gt;
        &lt;td&gt;GraalVM&lt;/td&gt;
        &lt;td&gt;Reactive Streams&lt;/td&gt;
        &lt;td&gt;Lambda/Stream&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;Apache Dubbo (ECO System)&lt;/td&gt;
        &lt;td&gt;Vert.x&lt;/td&gt;
        &lt;td&gt;Kotlin&lt;/td&gt;
        &lt;td&gt;Scala、Groovy&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt;TarsJava&lt;/td&gt;
        &lt;td&gt;RxJava/Reactor&lt;/td&gt;
        &lt;td&gt;Java EE（Jakarta EE）、Netty&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt;ServiceComb&lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt;Spring Framework&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt;Spring Boot/Cloud&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt; &lt;/td&gt;
        &lt;td&gt;Apache Dubbo&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;https://uploader.shimo.im/f/PlaoGDZsEGoeqwtL.png!thumbnail&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;

&lt;p&gt;InfoQ英文站结果供参考&lt;/p&gt;

&lt;h4 id=&quot;第二部分java趋势点评&quot;&gt;第二部分：Java趋势点评&lt;/h4&gt;

&lt;p&gt;对第一部分中您所归类的处于不同阶段的技术，请您逐一做出如下点评问题包括：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;某个技术为什么要被划在这个技术采用生命周期内？这个技术在国内的发展情况以及机遇和挑战是什么？&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;小马哥（@mercyblitz）&lt;/a&gt;：&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;
      &lt;p&gt;Java / JVM 语言 - Java 8 已被业界普遍接受，无论像 Spring Framework、Spring Boot，以及 Spring Cloud 这样的现代 Java 框架，还是类似于 Vert.x、RxJava 或 Reactor 这类小众框架，均已构建在 Java 8 以及更高的版本之上。同时，Lambda 语法以及 Stream API 也在开发人员的日常工作中广泛地运用，并且没有看到语法回退的趋势。因此，Java 8 和 Lambda/Stream 可归类为“&lt;strong&gt;晚期大众&lt;/strong&gt;”。 JVM 语言 Scala 和 Groovy 已快成为明日黄花，往昔的光芒逐渐地被后期之秀 Kotlin 替代，故 Scala  和 Groovy  属于“&lt;strong&gt;晚期大众&lt;/strong&gt;”，而 Kotlin 则纳入”&lt;strong&gt;早期大众&lt;/strong&gt;“ 之流。然而 Java 9 的被接受程度则没有那么幸运，尽管我们等待它的到来已有数年。 Java 模块化作为 Java 9 核心的特性，就我个人而言，完全能够理解和接受它的设计。虽然模块化增强了模块的隔离性，减少了内存的 Footprint，然而，它更强的封装性无形之中增加了管理依赖的成本。所谓曲高和寡，夸张地说，模块化形同虚设。因此，应用升级 Java 9 的效果相当于 Java API 以及 JVM 的更新。同时，Oracle 宣布从 Java 9 开始，每半年将更新一个 Java 大版本。那么，更多的人会选择 Java 11 这样的长期支持（Long-Term -Support, LTS）版本，换言之，Java 9/10 则成了过渡版本（non‑LTS）&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;。因此，Java 11 将是未来 Java 用户的最可能选项，将其列为“早期采用者”。至于 Java 13，最近有注意到该本版在新 GC 算法的提升以及 Socket 实现上的变化&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;，还是非常令人期待的，故排在“&lt;strong&gt;创新者&lt;/strong&gt;” 之列。除了模块化之外，Java 9 还有大量的 API 更新，在偏开发侧的部分，Flow API 可能是最有吸引力的，提供了 Reactive Streams&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; 标准接口以及实现，并且内建了 HTTP Client Reactive 实现。尽管 Spring 和 Eclipse 社区大力的推广，并且 Java Lambda 以及 Stream API 也流行开来，不过对开发者而言，Reactive Streams 技术还是相对陌生，将其放在 “&lt;strong&gt;早期大众&lt;/strong&gt;“。同理，Spring 引入的 Reactor 框架也属于“&lt;strong&gt;早期大众&lt;/strong&gt;” 阶段。虽然 RxJava 并非 Reactive Streams 的实现，但是相较于前两者而言，它在 Reactive 编程中的地位必然是有过之而无不及的，故也在 “&lt;strong&gt;早期大众&lt;/strong&gt;“ 之中。&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;OpenJDK - 由于 Oracle 宣布 2019 年伊始，Oracle  JDK 8 以及更高版本在服务器端部署不再免费，OpenJDK 则成为大多数 Java 用户的选项。尽管 Oracle JDK 与 OpenJDK 几乎出至于同一家之手，不过OpenJDK 很可能被认为是一种退而求其次的选择。对于具备自主研发的企业，它们可能选择在 OpenJDK 的基础上，自定义分支继续开发。在一定程度上，Java 的发展方向出现了裂痕，所以未来仍存在着不确定性，故将其放置于 “&lt;strong&gt;早期大众&lt;/strong&gt;“&lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;非Hotspot JDK生产实践 - 按照 GraalVM 官方的描述，GraalVM 将会是下一代的 JVM 基础设施，也是 Oracle 的重点项目，能够将传统的 JVM 进程 native 化，那么未来 Java 的性能提升以及快速启停则不再遥远，不够目前还尚不可知其兼容性情况以及明确的商业化条款，列为“&lt;strong&gt;早期采用者&lt;/strong&gt; 应该是合理的&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;不同层次的主流框架
      &lt;ul&gt;
        &lt;li&gt;Java EE  -  在 Java 生态中，绝大多数应用直接或间接地使用了 Spring Framework，这个曾经以轻量级著称的框架，目前显然“名不副实”，不过巨大的用户基础，早已进入“&lt;strong&gt;晚期大众&lt;/strong&gt;”的行列。相反，Java EE 规范或者重组后的 Jakarta EE&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; 则寂寥许多。实际上，作为 J2EE 或 Java EE 的模仿者，尽管 Spring Framework 多半的特性和实现向 JSR&lt;sup id=&quot;fnref:5&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:5&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; 参考。一定程度上，Spring Framework 的流行“压缩”了 Java EE 以及 JSR 的认知空间，因此不少的开发人员不知道 Java EE API 或者 JSR 的存在，尤其是年轻的国内从业人员。当然，Spring 也反哺了少量标准给 Java EE，比如 JSR 330&lt;sup id=&quot;fnref:6&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:6&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;，因此，将 Java EE 列为 &lt;strong&gt;“晚期大众&lt;/strong&gt;” 是毋容置疑的。值得一提的是，Jakarta EE 在 Eclipse 基金会&lt;sup id=&quot;fnref:7&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:7&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;的带领下能否再次“伟大” 值得期待，后续未来 Jakarta EE 将是“&lt;strong&gt;创新者&lt;/strong&gt;”成员&lt;/li&gt;
        &lt;li&gt;网络框架 - Java 的网络框架只有两种，其一是 Netty，其二则是其他。如此描述也丝毫不夸张，毕竟大多数与网络相关的框架或中间件都和 Netty 多少存在关联，如 Apache Dubbo、Spring 5 Web Server、Jersey 等，所以&lt;strong&gt;“晚期大众&lt;/strong&gt;”的排行众望所归。&lt;/li&gt;
        &lt;li&gt;微服务框架 - Java 微服务框架的王者非 Spring Boot 和 Spring Cloud 莫属，进过数年的生产使用，两者早已属于“&lt;strong&gt;晚期大众&lt;/strong&gt;” 的技术栈。相对应地，Apache Dubbo 出现和开源的时间比 Spring Cloud 早不少，无论是性能还是稳定性，相对于后者要优秀不少，因此，Apache Dubbo 也属于 “&lt;strong&gt;晚期大众&lt;/strong&gt;” 框架。不过，最新的 Apache Dubbo ECO System（生态系统）则基于 Apache Dubbo 衍进的 Cloud Native 解决方案，目前尚未枝叶茂盛，处于 “&lt;strong&gt;创新者&lt;/strong&gt;” 阵营。而小众 的 Vert.x 则由于编程模型以及 API 熟悉度等客观条件所限，它不得不仍处于 ”&lt;strong&gt;早期采用者&lt;/strong&gt;”。类似，TarsJava 以及 ServiceComb 最近才出现，用户的认可度和稳定性稍微成熟，同样处于 ”&lt;strong&gt;早期采用者&lt;/strong&gt;”。&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
  &lt;/ul&gt;

&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;国内是否在某个相对完整的领域，形成甚至开始引领技术趋势？&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;小马哥（@mercyblitz）&lt;/a&gt;：&lt;/p&gt;

  &lt;p&gt;在国内的开源软件中，Apache Dubbo（后文简称 Dubbo）常年受到业界的青睐，并荣获多次殊荣。个人认为 Dubbo 有机会引领技术趋势。Dubbo 从过去的高性能 RPC 框架，正在走向 Cloud Native 的生态系统（后文简称 Dubbo ECO System）。具体执行的步骤也是 Dubbo 社区对 Cloud Native 的发展趋势研判，首要场景是 Dubbo 在 Spring Cloud 之间的整合。这部分工作已在 Spring Cloud Alibaba 项目中完成，作为项目中的核心成员，Dubbo Spring Cloud 可无缝地替换过传统 Spring Cloud OpenFeign，不仅提供更好的性能，并且具备更多的负载均衡策略和熔断等特性。同时，灵活的扩展点和内建实现帮助 Dubbo 适应不同语言、环境和基础设施。随着 Dubbo 内核即将发布 Cloud Native（即将发布）特性 ，能够将 Dubbo 帮助独立于任意的基础设施，实现 Dubbo（原生）与 Spring Cloud（原生）调用互通，甚至在 K8S 场景下。无论 Dubbo 身处何处，统一的编程模型帮助开发人员快速和高效地实现业务逻辑，达成 “&lt;strong&gt;Write Once, Run Anywhere&lt;/strong&gt;” 的目的。后续，Dubbo 在多语言、Mesh 化 以及 Istio 的建树将逐一呈现。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&quot;第三部分应用实践&quot;&gt;第三部分：应用实践&lt;/h4&gt;

&lt;p&gt;请您尽可能详细地回答以下问题，这些问题的回答除了作为趋势报告的一部分之外，还可以作为您所在企业的技术实践，单独成文（InfoQ记者将针对每位嘉宾所在企业和技术实践，补充个性化问题）：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Java相关：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;您的企业使用的JDK版本情况，是否采用了某个OpenJDK 发行版？您如何看待OpenJDK 在国内的发展？（如果没有采用，原因以及后续计划？）&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;小马哥（@mercyblitz）&lt;/a&gt;：&lt;/p&gt;

      &lt;p&gt;在开源方面， OpenJDK 的选择仅为 Oracle 官方提供。如果是公司内部的话，则是  OpenJDK Alibaba 的分支。OpenJDK 在国内直接拿去使用的多，有能力围之扩展的公司凤毛菱角。可能随着 OpenJDK 不同分支的成熟，未来国内公司选择面将会更广&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;您的企业目前在支持Java技术栈方面的策略是什么？计划和目标是什么？相关的核心痛点或者业务需求是什么？&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;小马哥（@mercyblitz）&lt;/a&gt;：&lt;/p&gt;

      &lt;p&gt;关于公司在战略层面的设定，个人是不是非常清楚的。不过，作为一名基础设施的研发人员，自身遇到和周遭听到同事抱怨的痛点还是存在的。比如，Java 9 之后的版本更新问题。 Reactive Streams 推广和落地时的阻碍，毕竟大多数开发人员从事业务开发，业务系统的稳定性是他们核心 KPI 之一，他们缺少足够的勇气和动力蒸腾新技术的引进、也没有时间和精力关注其中细节，尤其当没有明显特性变化的基础设施 和 API 升级时。对于本人而言，我比较关心 JVM 中的变化，包括 GC 算法和性能提升，比如 C1 和 C2 编译所导致的延迟和资源开销，如何帮助 JVM 快速启停，因为这些会限制 Java 作为编程语言在云原生时代的想象空间&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;对于当前Java的整体发展情况，您有什么感想？&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;小马哥（@mercyblitz）&lt;/a&gt;：&lt;/p&gt;

      &lt;p&gt;Java 目前仍具在编程语言排行榜上夺魁，不过在整体比重上微幅下滑。个人看来，未来这个趋势还将持续。究其原因，一方面是由于新语种出现的中短期效应，一方面是 Java 的编程复杂度并没有明显的降低，比如 I/O 处理、并发/并行计算，以及类加载等等。再者是 Java 与操作系统之间的交互仍不够充分，尽管 Java 9 开始提供了不少的 API，然而了解和使用的群体不足。Java 在这方面明显不及 GO 语言。&lt;/p&gt;

      &lt;p&gt;从语言层面来看，Java 正在向主流非 Java 语言融合，解决其中鸿沟的起手式就是语法的变化，比如 Java 8 的 Lambda 表达式 和 Java 10 的局部变量类型（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var&lt;/code&gt; ）等。个人认为这是一件好事，未来前后端不分家，相互渗透，对于彼此语言都是良性发展。&lt;/p&gt;

      &lt;p&gt;除此之外，个人比较期待的是 GraalVM 对 Java 的改变，传统 Java 应用必须依赖 JVM 进程加载字节码后解释执行，无法保证所有的代码能够在运行期编程完成，不免有运行时编译所带来的性能开销，从而影响 JVM 的启停时间，简单地说，这种方式不够 Native，对于云原生或许不够友好。如果未来 GraalVM 的社区版也能够像 OpenJDK 那般“亲民”，那么，Java 的变化将是颠覆性的&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;微服务相关：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;请介绍您的企业是否进行了微服务实践？如果是，在整体系统架构中的比例是多少？如果不是，是否有相关计划？&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;小马哥（@mercyblitz）&lt;/a&gt;：&lt;/p&gt;

      &lt;p&gt;大多数应用已实施微服务架构，微服务应用的比重高达8成以上&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;您所采用的主要微服务框架是什么？如何判断国内该领域的技术发展情况？您认为微服务主流框架的争夺是否尘埃落定？&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;小马哥（@mercyblitz）&lt;/a&gt;：&lt;/p&gt;

      &lt;p&gt;采用的微服务架构主要以 Spring Boot/Cloud 以及 Apache Dubbo 为主，同时这也是国内大多数公司作为微服务框架的选择。不过，在国内，一直都有 Spring Cloud 与 Apache Dubbo 的优劣之争，然而这个争端似乎没有持续太长的时间，因为随着 Dubbo Spring Cloud（作为 Spring Cloud Alibaba 的一部分）发布之后，强强联合，互补互助&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;您如何看待Service Mesh在国内的发展现状和发展前景？&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;小马哥（@mercyblitz）&lt;/a&gt;：&lt;/p&gt;

      &lt;p&gt;个人对 Service Mesh 的看法是乐观偏谨慎的，一方面，作为从业人员，对于技术总有猎奇的心态。另外一方面，这个技术在设计上存在一些理想主义，比如，性能损耗以及稳定性，并且分布式场景中的典型问题并没有得到解决和改善，比如数据一致性、分布式事务等。据我所知，国内不少的互联网公司，如阿里巴巴、蚂蚁金服以及美团等已经开始在生产环境试点 Service Mesh，听起来这是一件好事。前沿的技术总有有人去探险。如果成功，前人栽树，后人乘凉。至于它能否成功，主要看市场是否愿意买单&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;参与专家&quot;&gt;参与专家：&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;小马哥（@mercyblitz）&lt;/a&gt;，《Spring Boot 编程思想》作者、Apache Dubbo PMC 和 Spring-Cloud-Alibaba Architect&lt;/p&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Oracle Java SE Support Roadmap - https://www.oracle.com/technetwork/java/java-se-support-roadmap.html &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Java Performance Tuning News August 2019 - http://www.javaperformancetuning.com/news/news225.shtml &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Reactive Streams JVM - https://github.com/reactive-streams/reactive-streams-jvm &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Jakarta EE - https://jakarta.ee/ &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Java Community Process - https://jcp.org/en/home/index &lt;a href=&quot;#fnref:5&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:6&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;JSR 330: Dependency Injection for Java  - https://jcp.org/en/jsr/detail?id=330 &lt;a href=&quot;#fnref:6&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:7&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Eclipse Foundation -  https://www.eclipse.org/org/foundation/ &lt;a href=&quot;#fnref:7&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 05 Sep 2019 00:00:00 +0000</pubDate>
        <link>https://weibo.com/mercyblitz/2019/09/05/2019-Java-%E8%B6%8B%E5%8A%BF%E6%8A%A5%E5%91%8A-InfoQ-%E9%87%87%E8%AE%BF%E7%A8%BF-%E5%B0%8F%E9%A9%AC%E5%93%A5%E9%83%A8%E5%88%86/</link>
        <guid isPermaLink="true">https://weibo.com/mercyblitz/2019/09/05/2019-Java-%E8%B6%8B%E5%8A%BF%E6%8A%A5%E5%91%8A-InfoQ-%E9%87%87%E8%AE%BF%E7%A8%BF-%E5%B0%8F%E9%A9%AC%E5%93%A5%E9%83%A8%E5%88%86/</guid>
        
        
      </item>
    
      <item>
        <title>Service mesh 时代，dubbo 架构该怎么跟进？</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;原文链接：&lt;a href=&quot;https://mp.weixin.qq.com/s/-p06WsPQK7EmFpmUABluRA&quot;&gt;Service Mesh 时代，Dubbo 架构该怎么跟进？&lt;/a&gt;，来自于微信公众号：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;次灵均阁&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;导读：6月21-23日，2019 GIAC全球互联网架构大会将于深圳举行。GIAC是面向架构师、技术负责人及高端技术从业人员的年度技术架构大会，是中国地区规模最大的技术会议之一。今年GIAC邀请到了众多布道师、明星讲师以及105位来自Google、微软、Oracle、eBay、百度、阿里、腾讯、商汤、图森、字节跳动、新浪、美团点评等公司专家出席。&lt;/p&gt;

&lt;p&gt;在大会前夕，高可用架构采访了本届 GIAC Java分论坛讲师&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;小马哥&lt;/a&gt;，就目前大家广泛关注的Dubbo/微服务相关的问题进行了访谈。&lt;/p&gt;

&lt;h4 id=&quot;作为-duboo-核心开发者请先简单介绍下自己&quot;&gt;作为 Duboo 核心开发者，请先简单介绍下自己&lt;/h4&gt;

&lt;p&gt;答：大家好，我是小马哥（mercyblitz），一名学习当爸爸的父亲，&lt;a href=&quot;https://www.douyu.com/mercyblitz&quot;&gt;Java 劝退师&lt;/a&gt;，&lt;a href=&quot;https://dubbo.apache.org/&quot;&gt;Apache Dubbo&lt;/a&gt; PMC、&lt;a href=&quot;https://github.com/spring-cloud-incubator/spring-cloud-alibaba&quot;&gt;Spring Cloud Alibaba&lt;/a&gt;项目架构师，《Spring Boot 编程思想》的作者。目前主要负责集团中间件开源项目、微服务技术实施、架构衍进、基础设施构建等。&lt;/p&gt;

&lt;h4 id=&quot;spring-cloud-和-duboo-在微服务方面的优劣分别是什么&quot;&gt;Spring Cloud 和 Duboo 在微服务方面的优劣分别是什么？&lt;/h4&gt;

&lt;p&gt;答：在 Java 生态中，Spring Cloud 和 Dubbo 都是微服务框架。前者被业界常作为 Java 微服务的首选框架，而后者有时被错误地解读为服务治理的 RPC 框架。实际上，两者在微服务架构中并没有本质的差异，均是分布式应用服务治理的框架。&lt;/p&gt;

&lt;p&gt;在开发体验方面，Spring Cloud 开箱即用的组件让人印象深刻。在 API 抽象和设计方面，流淌着 Spring 家族血液的 Spring Cloud 延续了父辈的荣耀。由此观之，Dubbo 与其存在差距。&lt;/p&gt;

&lt;p&gt;然而随着实践的不断深入，Spring Cloud 功能的稳定性以及版本的兼容性等问题较为突出。当应用集群达到一定规模时，其分布式经验上的短板也随之暴露，尤其是 Spring Cloud Netflix 套件，比如 Eureka 与 Ribbon 之间的 90 秒延迟会影响服务调用的成功率，以及负载均衡算法缺少权重无法帮助 JVM 预热。简言之，在服务治理方面，Spring Cloud 相较于 Dubbo 而言，并不算太成熟。如果大家有兴趣了解更多的话，可参考&lt;a href=&quot;https://github.com/mercyblitz/tech-weekly&quot;&gt;「小马哥技术周报」&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;总之，Spring Cloud 和 Dubbo 各有特色，过度地关注彼此优劣并不可取。为此，Spring Cloud Alibaba 项目综合两家之长，提供了一套名为 Dubbo Spring Cloud 的整容实现，使得 Dubbo 与 Spring Cloud 不再是互斥性选项。&lt;/p&gt;

&lt;h4 id=&quot;请介绍下-duboo-的现状&quot;&gt;请介绍下 Duboo 的现状？&lt;/h4&gt;

&lt;p&gt;答：2019年5月16日，Apache 软件基金会董事会决议通过了 Apache Dubbo 的毕业申请，这意味着 Apache Dubbo 正式成为 Apache 的顶级项目。Apache Dubbo 项目在 Github 上的 star 数已超过 2.7 万，contributors 人数达到 202，Commiters 人数也升至 32 人，借此机会感谢所有关系和参与 Apache Dubbo 建设的小伙伴。目前，项目主要包含三大核心的分支，均在并行开发。其中，2.6.x 处于维护状态；2.7.x 聚焦云原生微服务方向，3.0.x 则指定未来标准和技术走向。简言之，Dubbo 不再是纯粹的 Java 服务治理 RPC 框架，已经逐渐成为多语种 Cloud Native 基础设施的中坚力量。&lt;/p&gt;

&lt;h4 id=&quot;duboo在成为apache顶级项目的过程中背后有哪些不为人知的故事&quot;&gt;Duboo在成为Apache顶级项目的过程中，背后有哪些不为人知的故事？&lt;/h4&gt;

&lt;p&gt;答：Dubbo 在 Apache 从孵化到毕业，期间的确有太多不为人知的故事，这里我简单地介绍一下其中孵化过程：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;筹备期（2017.12-2018.2）：最主要的工作是准备进入孵化器相关的材料，比如寻找合适的导师，编写加入孵化器的提案等。&lt;/li&gt;
  &lt;li&gt;初始期（2018.2-2018.5）：主要完成的工作主要是完成知识产权的清理，邮件列表的创建，代码迁移等工作。&lt;/li&gt;
  &lt;li&gt;首次 Release：Apache孵化项目第一个重要的里程碑，第一次Release非常关键，除了确保功能的稳定以外，最重要的就是需要确保引入的代码的许可证符合Apache的政策，Apache对于许可证有着明确的规定。&lt;/li&gt;
  &lt;li&gt;社区发展（Community Building）：也是作为一个Apache项目非常看重的一环。最不愿意看到的就是一家公司独大，控制整个项目，对于Dubbo来说，经过这么多年的发展，在国内已经具备了一定的渗透率，有了不少用户，但是他们就像花粉一样散落在各个角落里面，需要做的事情就是把他们都聚集起来。&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;在未来一年duboo的新特性路线图可以简单介绍下吗&quot;&gt;在未来一年，Duboo的新特性路线图可以简单介绍下吗？&lt;/h4&gt;

&lt;p&gt;答：由于 Dubbo 2.6.x 处于维护状态，不会新增明显的功能特性。&lt;/p&gt;

&lt;p&gt;本年度主要的发力点在 Dubbo 2.7 这个版本上，该版本致力于 Cloud Native 以及微服务领域，大致的路线计划为&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;2.7.2 - Metrics、etcd 元数据、nacos 配置与元数据以及 2.6 兼容&lt;/li&gt;
  &lt;li&gt;2.7.3 - Cloud Native 注册机制、服务自省以及 Dubbo Proxy&lt;/li&gt;
  &lt;li&gt;2.7.4 - K8s 原生支持（服务发现、元数据存储和配置推送）、Dubbo GO 以及 gRPC 集成&lt;/li&gt;
  &lt;li&gt;2.7.5 - 服务治理规则支持 Pilot CRD&lt;/li&gt;
  &lt;li&gt;2.7.6 - 控制面 xDS API 对接&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dubbo 3.0.0 M1 版本的核心特性围绕在 RSocket、Reactive 以及异步化上的支持。 M2 版本计划将在 8 月发布，主要提供对 HTTP/2 的支持和性能调优。接下来的 M3 版本将通过 HTTP/2 支持 gPRC 以及 Rocket 通讯协议。3.0.0 正式的发布将安排在 2020 年的 2 月。&lt;/p&gt;

&lt;h4 id=&quot;duboo-开源以来代码贡献者中阿里本身的开发者占绝大多数这是否意味着来自阿里的需求会起主导作用在后续的发展过程中计划如何引入阿里之外的开发者&quot;&gt;Duboo 开源以来，代码贡献者中阿里本身的开发者占绝大多数，这是否意味着来自阿里的需求会起主导作用？在后续的发展过程中，计划如何引入阿里之外的开发者？&lt;/h4&gt;

&lt;p&gt;答：尽管目前 Apache Duboo 代码贡献者主要来自于阿里的开发人员，不过这个比重正在迅速地变小，一方面说明  Dubbo 用户人数在逐渐变大，专业程度在不断地变深，同时，也说明有意主导并且贡献的小伙伴越来越活跃。这无论对社区的发展，还是从业人员的职业技能均有裨益。因此，需求的来源不再已阿里为绝对主导，社区共建和共制的发展模式已成事实。&lt;/p&gt;

&lt;h4 id=&quot;service-mesh-时代需要什么样的微服务框架&quot;&gt;Service Mesh 时代，需要什么样的微服务框架？&lt;/h4&gt;

&lt;p&gt;答：哈哈，需要 Dubbo 这样的框架（玩笑）。首先，个人并不是 Service Mesh 方面的专家，就目前所得到掌握的信息，Service Mesh 并不算成熟的技术，换言之，目前还不是 Service Mesh 的时代，甚至我听到不少的朋友由于性能和稳定性方面的原因，从该架构中退化，这也是 Dubbo 在 Service Mesh 方面的衍进相对缓慢的原因之一。当然，技术的发展总会是在掌声伴随着嘘声中前进，因此，个人对于 Service Mesh 的看法是谨慎乐观的。&lt;/p&gt;

&lt;h4 id=&quot;对于公司内部定制dubbo而言你有什么建议吗&quot;&gt;对于公司内部定制Dubbo而言，你有什么建议吗？&lt;/h4&gt;

&lt;p&gt;答：流水不腐户枢不蠹，我希望这些公司能够积极参与 Dubbo 社区的共建，或许这些定制化的场景也可以服务其他场景。大家互通有无，实现共同进步。&lt;/p&gt;

&lt;h4 id=&quot;对于初级开发者而言学习duboo应该如何入手对于资深开发者而言怎样研究dubbo的源代码更加高效&quot;&gt;对于初级开发者而言，学习Duboo应该如何入手？对于资深开发者而言，怎样研究Dubbo的源代码更加高效？&lt;/h4&gt;

&lt;p&gt;答：对于初级开发者，我的建议是首先从 Apache Dubbo 官网（&lt;a href=&quot;http://dubbo.apache.org/&quot;&gt;https://dubbo.apache.org&lt;/a&gt;）学习《用户文档》，初步了解了 Dubbo 架构和特性后，再结合 Dubbo 官方样例（https://github.com/apache/dubbo-samples）全面掌握 Dubbo 功能和最佳实践。最后，参考官方博客（&lt;a href=&quot;http://dubbo.apache.org/zh-cn/blog/index.html&quot;&gt;http://dubbo.apache.org/zh-cn/blog/index.html&lt;/a&gt;），深度理解 Dubbo。&lt;/p&gt;

&lt;p&gt;对于资深开发者，尤其是那些致力于贡献的小伙伴，我建议参考《开发者文档》，掌握 Dubbo 设计和实现，并且结合 Dubbo 的源码巩固学习，最好直接贡献代码（在 GitHub Pull Request），战胜心中一切的畏惧。如果仍不满足于此，强烈推荐参考 Apache Dubbo PMC 商宗海（花名：诣极）编写并即将出版的书籍 - 《深入理解 Apache Dubbo 与实战》，从中本人也受益匪浅，建议小伙们入手。&lt;/p&gt;

&lt;h4 id=&quot;你作为讲师参加giac对本次giac大会有何寄语&quot;&gt;你作为讲师参加GIAC，对本次GIAC大会有何寄语？&lt;/h4&gt;

&lt;p&gt;答：非常感谢 GIAC 的主办方给本人这次机会分享 Dubbo 相关的的议程，这也是我本人第二次在 GIAC 分享该主题了。我衷心地祝福 GIAC 影响力越做越大，希望能够走出国门，成为具有国际化影响力的技术组织，向世界传播技术和力量。&lt;/p&gt;

&lt;h4 id=&quot;作为duboo的开发者你最喜欢的javajava8以后特性是什么你最希望加入的java特性是什么&quot;&gt;作为Duboo的开发者，你最喜欢的Java（Java8以后）特性是什么？你最希望加入的Java特性是什么？&lt;/h4&gt;

&lt;p&gt;答：Java 8 是 Dubbo 2.7 默认的语言级别，其中 Lambda 表达式以及 Stream API 被广泛地使用。除此之外，本人同样偏好使用 CompletableFuture 作为并行编程的 API。我最希望 Java 增加 JVM 级别的协程支持。&lt;/p&gt;

&lt;h4 id=&quot;简单介绍下你自己的从业经历&quot;&gt;简单介绍下你自己的从业经历？&lt;/h4&gt;

&lt;p&gt;答：今年是我从业的第十二个年头，这些年一直在从事 Java 研发。首个雇主是一家外企公司，为其服务了三年。外企的工作相对轻松，拥有充分的自主时间提升技能，同时也有机会提升英语水平。期间通过了 SUN Java（SCJP、SCWCD、SCBCD）以及 Oracle OCA 等的认证，尽管这些证书并没有受到国内雇主的重视，不过对我后续的职业产生了深远的影响。当然，事情并不是总是积极正面，东西方文化差异，以及部分外籍同事的傲慢与偏见着实让本人对西方的技术和文化重新开始审视。既然无法改变，那么离开并继续深造或许是必然的选择，希望有一天能够通过共同的努力，让世界看到中华的进步。于是，我的第一份工作就在 2010 年 10 月 1 号画上了句点。迎接我的是第二份工作，至今也快九个年头。这几年，我经历了很多、学到了很多，也成长了很多，岂能尽如人意，但求无愧我心。不可否认的是，儒家思想对我的影响最为深刻，它让我学会独立、理性以及辩证的思考，培养我处变不惊的人生态度，直接或间接地提升了专业素质。经过数年的沉寂，我也明确了自己的方向，辗转投入开源社区的建设。不过，纵使浑身是铁能打几根钉，开源社区的发展需要更多的能人参与，知之者不如好之者，好之者不如乐之者。然而现实的情况又有些残酷，不少的年轻人在经济的压力下，逐渐失去对技术的追求。于是从 2016 年开始，我便尝试做一些技术分享，希望能够帮助到部分年轻从业人员，使他们对技术产生兴趣。随后，我又着手编写《Spring Boot 编程思想》，希望读者能够理解规范和基础的重要性，如果读者从中能够培养自己系统化的知识体系或者思维方式，那就善莫大焉了。我也时常鼓励更多的小伙伴多多分享，无论是免费，还是收费。同时，注重知识产权的保护，树立良好的生态环境。当然，我的第二份职业尚未告一段落，或许等它结束之际，方可“盖棺定论“。总之，但行好事，莫问前程。&lt;/p&gt;

&lt;h4 id=&quot;书籍推荐&quot;&gt;&lt;a href=&quot;https://item.jd.com/12570242.html&quot;&gt;书籍推荐&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;-《Spring Boot 编程思想（核⼼心篇）》 https://item.jd.com/12570242.html&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;本书全名为&lt;a href=&quot;https://mercyblitz.github.io/books/thinking-in-spring-boot/&quot;&gt;《Spring Boot 编程思想》&lt;/a&gt;，是以 Spring Boot 2.0 为讨论的主线，讨论的范围将涵盖 Spring Boot 1.x 的所有版本，以及所关联的 Spring Framework 版本，致力于：&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;场景分析：掌握技术选型&lt;/li&gt;
    &lt;li&gt;系统学习：拒绝浅尝辄止&lt;/li&gt;
    &lt;li&gt;重视规范：了解发展趋势&lt;/li&gt;
    &lt;li&gt;源码解读：理解设计思想&lt;/li&gt;
    &lt;li&gt;实战演练：巩固学习成果&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://item.jd.com/12172344.html&quot;&gt;《Spring Cloud 微服务实战》&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://item.jd.com/12489649.html&quot;&gt;《深⼊入理理解Kafka：核⼼心设计与实践原理理》&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://item.jd.com/12498217.html&quot;&gt;《未来架构 从服务化到云原⽣生》&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://item.jd.com/12585284.html&quot;&gt;《⾼高可⽤用可伸缩微服务架构：基于Dubbo、Spring Cloud和Service Mesh》&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://item.jd.com/12601558.html&quot;&gt;《Kubernetes权威指南：从Docker到Kubernetes实践全接触》&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://item.jd.com/12615848.html&quot;&gt;《Java编程⽅方法论：响应式RxJava与代码设计实战》&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Tue, 18 Jun 2019 00:00:00 +0000</pubDate>
        <link>https://weibo.com/mercyblitz/2019/06/18/Service-Mesh-%E6%97%B6%E4%BB%A3-Dubbo-%E6%9E%B6%E6%9E%84%E8%AF%A5%E6%80%8E%E4%B9%88%E8%B7%9F%E8%BF%9B/</link>
        <guid isPermaLink="true">https://weibo.com/mercyblitz/2019/06/18/Service-Mesh-%E6%97%B6%E4%BB%A3-Dubbo-%E6%9E%B6%E6%9E%84%E8%AF%A5%E6%80%8E%E4%B9%88%E8%B7%9F%E8%BF%9B/</guid>
        
        
      </item>
    
      <item>
        <title>Dubbo spring cloud 重塑微服务治理</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;原文链接：&lt;a href=&quot;https://mp.weixin.qq.com/s/K60e1VkAWjwQXftmHw74NQ&quot;&gt;Dubbo Spring Cloud 重塑微服务治理&lt;/a&gt;，来自于微信公众号：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;次灵均阁&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;摘要&quot;&gt;摘要&lt;/h2&gt;

&lt;p&gt;在 Java 微服务生态中，Spring Cloud&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; 成为了开发人员的首选技术栈，然而随着实践的深入和运用规模的扩大，大家逐渐意识到 Spring Cloud 的局限性。在服务治理方面，相较于 Dubbo&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; 而言，Spring Cloud 并不成熟。遗憾的是，Dubbo 往往被部分开发者片面地视作服务治理的 RPC 框架，而非微服务基础设施。即使是那些有意将 Spring Cloud 迁移至 Dubbo 的小伙伴，当面对其中迁移和改造的成本时，难免望而却步。庆幸的是，Dubbo 生态体系已发生巨大变化，Dubbo Spring Cloud 作为 Spring Cloud Alibaba&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; 的最核心组件，完全地拥抱 Spring Cloud 技术栈，不但无缝地整合 Spring Cloud 注册中心，包括 Nacos&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;、Eureka&lt;sup id=&quot;fnref:5&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:5&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;、Zookeeper&lt;sup id=&quot;fnref:6&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:6&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt; 以及 Consul&lt;sup id=&quot;fnref:7&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:7&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;，而且完全地兼容 Spring Cloud Open Feign&lt;sup id=&quot;fnref:8&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:8&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt; 以及 @LoadBalanced RestTemplate，本文将讨论 Dubbo Spring Cloud 对 Spring Cloud 技术栈所带来的革命性变化。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;注：由于 Spring Cloud 技术栈涵盖的特性众多，因此本文讨论的范围仅限于服务治理部分。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;简介&quot;&gt;简介&lt;/h2&gt;

&lt;p&gt;Dubbo Spring Cloud 基于 Dubbo Spring Boot 2.7.1&lt;sup id=&quot;fnref:9&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:9&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;9&lt;/a&gt;&lt;/sup&gt; 和 Spring Cloud 2.x 开发，无论开发人员是 Dubbo 用户还是 Spring Cloud 用户，都能轻松地驾驭，并以接近“零”成本的代价使应用向上迁移。Dubbo Spring Cloud 致力于简化 Cloud Native 开发成本，提高研发效能以及提升应用性能等目的。&lt;/p&gt;

&lt;p&gt;2019年4月19日，Dubbo Spring Cloud 首个 Preview Release，随同 Spring Cloud Alibaba &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.2.2.RELEASE&lt;/code&gt; 和  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.9.0.RELEASE&lt;/code&gt; 一同发布&lt;sup id=&quot;fnref:10&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:10&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;10&lt;/a&gt;&lt;/sup&gt;，分别对应 Spring Cloud Finchley&lt;sup id=&quot;fnref:11&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:11&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;11&lt;/a&gt;&lt;/sup&gt; 与 Greenwich&lt;sup id=&quot;fnref:12&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:12&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;12&lt;/a&gt;&lt;/sup&gt; (下文分别简称为 “F” 版 和 “G” 版) 。&lt;/p&gt;

&lt;h2 id=&quot;版本支持&quot;&gt;版本支持&lt;/h2&gt;

&lt;p&gt;由于 Spring 官方宣布 Spring Cloud Edgware(下文简称为 “E” 版) 将在 2019 年 8 月 1 号后停止维护13，因此，目前 Dubbo Spring Cloud 发布版本并未对 “E” 版提供支持，仅为 “F” 版 和 “G” 版开发，同时也建议和鼓励 Spring Cloud 用户更新至 “F” 版 或 “G” 版。&lt;/p&gt;

&lt;p&gt;同时，Dubbo Spring Cloud 基于 Apache Dubbo Spring Boot 2.7.1 开发（最低 Java 版本为 1.8），提供完整的 Dubbo 注解驱动、外部化配置以及 Production-Ready 的特性，详情请参考：https://github.com/apache/incubator-dubbo-spring-boot-project&lt;/p&gt;

&lt;p&gt;以下表格将说明 Dubbo Spring Cloud 版本关系映射关系：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Spring Cloud&lt;/th&gt;
      &lt;th&gt;Spring Cloud Alibaba&lt;/th&gt;
      &lt;th&gt;Spring Boot&lt;/th&gt;
      &lt;th&gt;Dubbo Spring Boot&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Finchley&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.2.2.RELEASE&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.0.x&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.7.1&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Greenwich&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.9.0.RELEASE&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.1.x&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.7.1&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Edgware&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.1.2.RELEASE&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.5.x&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;:x: Dubbo Spring Cloud 不支持该版本&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;功能特性&quot;&gt;功能特性&lt;/h2&gt;

&lt;p&gt;由于 Dubbo Spring Cloud 构建在原生的 Spring Cloud 之上，其服务治理方面的能力可认为是 Spring Cloud Plus，不仅完全覆盖 Spring Cloud 原生特性&lt;sup id=&quot;fnref:13&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:13&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;13&lt;/a&gt;&lt;/sup&gt;，而且提供更为稳定和成熟的实现，特性比对如下表所示：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;功能组件&lt;/th&gt;
      &lt;th&gt;Spring Cloud&lt;/th&gt;
      &lt;th&gt;Dubbo Spring Cloud&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;分布式配置（Distributed configuration）&lt;/td&gt;
      &lt;td&gt;Git、Zookeeper、Consul、JDBC&lt;/td&gt;
      &lt;td&gt;Spring Cloud 分布式配置 + Dubbo 配置中心&lt;sup id=&quot;fnref:14&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:14&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;14&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;服务注册与发现（Service registration and discovery）&lt;/td&gt;
      &lt;td&gt;Eureka、Zookeeper、Consul&lt;/td&gt;
      &lt;td&gt;Spring Cloud 原生注册中心&lt;sup id=&quot;fnref:15&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:15&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;15&lt;/a&gt;&lt;/sup&gt; + Dubbo 原生注册中心&lt;sup id=&quot;fnref:16&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:16&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;16&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;负载均衡（Load balancing）&lt;/td&gt;
      &lt;td&gt;Ribbon（随机、轮询等算法）&lt;/td&gt;
      &lt;td&gt;Dubbo 内建实现（随机、轮询等算法 + 权重等特性）&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;服务熔断（Circuit Breakers）&lt;/td&gt;
      &lt;td&gt;Spring Cloud Hystrix&lt;/td&gt;
      &lt;td&gt;Spring Cloud Hystrix + Alibaba Sentinel&lt;sup id=&quot;fnref:17&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:17&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;17&lt;/a&gt;&lt;/sup&gt; 等&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;服务调用（Service-to-service calls）&lt;/td&gt;
      &lt;td&gt;Open Feign、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RestTemplate&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Spring Cloud 服务调用 + Dubbo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Reference&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;链路跟踪（Tracing）&lt;/td&gt;
      &lt;td&gt;Spring Cloud Sleuth&lt;sup id=&quot;fnref:18&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:18&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;18&lt;/a&gt;&lt;/sup&gt; + Zipkin&lt;sup id=&quot;fnref:19&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:19&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;19&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
      &lt;td&gt;Zipkin、opentracing 等&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;高亮特性&quot;&gt;高亮特性&lt;/h3&gt;

&lt;h4 id=&quot;1-dubbo-使用-spring-cloud-服务注册与发现&quot;&gt;1. Dubbo 使用 Spring Cloud 服务注册与发现&lt;/h4&gt;

&lt;p&gt;Dubbo Spring Cloud 基于 Spring Cloud Commons 抽象实现 Dubbo 服务注册与发现，应用只需增添外部化配置属性 “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.registry.address = spring-cloud://localhost&lt;/code&gt;”，就能轻松地桥接到所有原生 Spring Cloud 注册中心，包括：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Nacos&lt;/li&gt;
  &lt;li&gt;Eureka&lt;/li&gt;
  &lt;li&gt;Zookeeper&lt;/li&gt;
  &lt;li&gt;Consul&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Dubbo Spring Cloud 将在下个版本支持 Spring Cloud 注册中心与 Dubbo 注册中心并存，提供双注册机制，实现无缝迁移。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&quot;2-dubbo-作为-spring-cloud-服务调用&quot;&gt;2. Dubbo 作为 Spring Cloud 服务调用&lt;/h4&gt;

&lt;p&gt;默认情况，Spring Cloud Open Feign 以及 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@LoadBalanced&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RestTemplate&lt;/code&gt; 作为 Spring Cloud 的两种服务调用方式。Dubbo Spring Cloud 为其提供了第三种选择，即 Dubbo 服务将作为 Spring Cloud 服务调用的同等公民出现，应用可通过 Apache Dubbo 注解 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Service&lt;/code&gt;和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Reference&lt;/code&gt; 暴露和引用 Dubbo 服务，实现服务间多种协议的通讯。同时，也可以利用 Dubbo 泛化接口轻松实现服务网关。&lt;/p&gt;

&lt;h4 id=&quot;3-dubbo-服务自省&quot;&gt;3. Dubbo 服务自省&lt;/h4&gt;

&lt;p&gt;Dubbo Spring Cloud 引入了全新的服务治理特性 - 服务自省（Service Introspection），其设计目的在于最大化减轻注册中心负载，去 Dubbo 注册元信息中心化。假设一个 Spring Cloud 应用引入 Dubbo Spring Boot Starter，并暴露 N 个 Dubbo 服务，以 &lt;a href=&quot;https://github.com/apache/incubator-dubbo/tree/master/dubbo-registry/dubbo-registry-nacos&quot;&gt;Dubbo Nacos 注册中心&lt;/a&gt; 为例，当前应用将注册 N+1 个 Nacos 应用，除 Spring Cloud 应用本身之前，其余 N 个应用均来自于 Dubbo 服务，当 N 越大时，注册中心负载越重。因此，Dubbo Spring Cloud 应用对注册中心的负载相当于传统 Dubbo 的 N 分之一，在不增加基础设施投入的前提下，理论上，使其集群规模扩大 N 倍。当然，未来的 Dubbo 也将提供服务自省的能力。&lt;/p&gt;

&lt;h4 id=&quot;4-dubbo-迁移-spring-cloud-服务调用&quot;&gt;4. Dubbo 迁移 Spring Cloud 服务调用&lt;/h4&gt;

&lt;p&gt;尽管 Dubbo Spring Cloud 完全地保留了原生 Spring Cloud 服务调用特性，不过 Dubbo 服务治理的能力是 Spring Cloud Open Feign 所不及的，如高性能、高可用以及负载均衡稳定性等方面。因此，建议开发人员将 Spring Cloud Open Feign 或者 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@LoadBalanced&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RestTemplate&lt;/code&gt; 迁移为 Dubbo 服务。考虑到迁移过程并非一蹴而就，因此，Dubbo Spring Cloud 提供了方案，即 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@DubboTransported&lt;/code&gt; 注解。该注解能够帮助服务消费端的 Spring Cloud Open Feign 接口以及 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@LoadBalanced&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RestTemplate&lt;/code&gt; Bean 底层走 Dubbo 调用（可切换 Dubbo 支持的协议），而服务提供方则只需在原有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@RestController&lt;/code&gt; 类上追加 Dubbo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Servce&lt;/code&gt; 注解（需要抽取接口）即可，换言之，在不调整 Feign 接口以及 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RestTemplate&lt;/code&gt; URL 的前提下，实现无缝迁移。如果迁移时间充分的话，建议使用 Dubbo 服务重构系统中的原生 Spring Cloud 服务的定义。&lt;/p&gt;

&lt;h2 id=&quot;简单示例&quot;&gt;简单示例&lt;/h2&gt;

&lt;p&gt;开发 Dubbo Spring Cloud 应用的方法与传统 Dubbo 或 Spring Cloud 应用类似，按照以下步骤就能完整地实现Dubbo 服务提供方和消费方的应用，完整的示例代码请访问一下资源：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Dubbo 服务提供方应用 - &lt;a href=&quot;https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-server-sample&quot;&gt;https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-server-sample&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Dubbo 服务消费方应用 - &lt;a href=&quot;https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-client-sample&quot;&gt;https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-client-sample&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;定义-dubbo-服务接口&quot;&gt;定义 Dubbo 服务接口&lt;/h3&gt;

&lt;p&gt;Dubbo 服务接口是服务提供方与消费方的远程通讯契约，通常由普通的 Java 接口（interface）来声明，如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EchoService&lt;/code&gt; 接口：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EchoService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;为了确保契约的一致性，推荐的做法是将 Dubbo 服务接口打包在第二方或者第三方的 artifact（jar）中，如以上接口就存放在 artifact &lt;a href=&quot;https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-sample-api&quot;&gt;spring-cloud-dubbo-sample-api&lt;/a&gt; 之中。&lt;/p&gt;

&lt;p&gt;对于服务提供方而言，不仅通过依赖 artifact 的形式引入 Dubbo 服务接口，而且需要将其实现。对应的服务消费端，同样地需要依赖该 artifact，并以接口调用的方式执行远程方法。接下来进一步讨论怎样实现 Dubbo 服务提供方和消费方。&lt;/p&gt;

&lt;h3 id=&quot;实现-dubbo-服务提供方&quot;&gt;实现 Dubbo 服务提供方&lt;/h3&gt;

&lt;h4 id=&quot;初始化-spring-cloud-dubbo-server-sample-maven-工程&quot;&gt;初始化 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-server-sample&lt;/code&gt; Maven 工程&lt;/h4&gt;

&lt;p&gt;首先，创建 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;artifactId&lt;/code&gt; 名为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-server-sample&lt;/code&gt; 的 Maven 工程，并在其  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pom.xml&lt;/code&gt; 文件中增添 
Dubbo Spring Cloud 必要的依赖：&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Sample API --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-dubbo-sample-api&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${project.version}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Spring Boot dependencies --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-actuator&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Dubbo Spring Cloud Starter --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-dubbo&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Spring Cloud Nacos Service Discovery --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-alibaba-nacos-discovery&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;以上依赖 artifact 说明如下：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-sample-api&lt;/code&gt; : 提供 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EchoService&lt;/code&gt; 接口的 artifact&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-boot-actuator&lt;/code&gt; : Spring Boot Production-Ready artifact，间接引入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-boot&lt;/code&gt; artifact&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-starter-dubbo&lt;/code&gt; : Dubbo Spring Cloud Starter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;artifact&lt;/code&gt;，间接引入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo-spring-boot-starter&lt;/code&gt; 等 artifact&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-starter-alibaba-nacos-discovery&lt;/code&gt; : Nacos Spring Cloud 服务注册与发现 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;artifact&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;值得注意的是，以上 artifact 未指定版本(version)，因此，还需显示地声明 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/code&gt; :&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Spring Cloud Alibaba dependencies --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-alibaba-dependencies&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.9.0.RELEASE&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span class=&quot;nt&quot;&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span class=&quot;nt&quot;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependencyManagement&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;以上完整的 Maven 依赖配置，请参考 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-server-sample&lt;/code&gt; &lt;a href=&quot;spring-cloud-dubbo-server-sample/pom.xml&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pom.xml&lt;/code&gt;&lt;/a&gt; 文件&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;完成以上步骤之后，下一步则是实现 Dubbo 服务&lt;/p&gt;

&lt;h4 id=&quot;实现-dubbo-服务&quot;&gt;实现 Dubbo 服务&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EchoService&lt;/code&gt; 作为暴露的 Dubbo 服务接口，服务提供方 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-server-sample&lt;/code&gt; 需要将其实现：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nd&quot;&gt;@org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;apache&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dubbo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;annotation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Service&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EchoServiceImpl&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EchoService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;[echo] Hello, &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;其中，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@org.apache.dubbo.config.annotation.Service&lt;/code&gt; 是 Dubbo 服务注解，仅声明该 Java 服务（本地）实现为 Dubbo 服务。
因此，下一步需要将其配置 Dubbo 服务（远程）。&lt;/p&gt;

&lt;h4 id=&quot;配置-dubbo-服务提供方&quot;&gt;配置 Dubbo 服务提供方&lt;/h4&gt;

&lt;p&gt;在暴露 Dubbo 服务方面，推荐开发人员外部化配置的方式，即指定 Java 服务实现类的扫描基准包。&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;Dubbo Spring Cloud 继承了 Dubbo Spring Boot 的外部化配置特性，也可以通过标注 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@DubboComponentScan&lt;/code&gt; 来实现基准包扫描。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;同时，Dubbo 远程服务需要暴露网络端口，并设定通讯协议，完整的 YAML 配置如下所示：&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;na&quot;&gt;dubbo&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# dubbo 服务扫描基准包&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;base-packages&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;org.springframework.cloud.alibaba.dubbo.bootstrap&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# dubbo 协议&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# dubbo 协议端口（ -1 表示自增端口，从 20880 开始）&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;-1&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;registry&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# 挂载到 Spring Cloud 注册中心&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;spring-cloud://localhost&lt;/span&gt;
    
&lt;span class=&quot;na&quot;&gt;spring&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Dubbo 应用名称&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;spring-cloud-alibaba-dubbo-server&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Spring Boot 2.1 需要设定&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;allow-bean-definition-overriding&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;cloud&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;nacos&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Nacos 服务发现与注册配置&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;discovery&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;server-addr&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;127.0.0.1:8848&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;以上 YAML 内容，上半部分为 Dubbo 的配置：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.scan.base-packages&lt;/code&gt; : 指定 Dubbo 服务实现类的扫描基准包&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.protocol&lt;/code&gt; : Dubbo 服务暴露的协议配置，其中子属性 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; 为协议名称，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;port&lt;/code&gt; 为协议端口（ -1 表示自增端口，从 20880 开始）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.registry&lt;/code&gt; : Dubbo 服务注册中心配置，其中子属性 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;address&lt;/code&gt; 的值 “spring-cloud://localhost”，说明挂载到 Spring Cloud 注册中心
    &lt;blockquote&gt;
      &lt;p&gt;当前 Dubbo Spring Cloud 实现必须配置 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.registry.address = spring-cloud://localhost&lt;/code&gt;，下一个版本将其配置变为可选
（参考 &lt;a href=&quot;https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/592&quot;&gt;issue #592&lt;/a&gt;），
并且支持传统 Dubbo 协议的支持（参考 &lt;a href=&quot;https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/588&quot;&gt;issue #588&lt;/a&gt;）&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;下半部分则是 Spring Cloud 相关配置：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring.application.name&lt;/code&gt; : Spring 应用名称，用于 Spring Cloud 服务注册和发现。
    &lt;blockquote&gt;
      &lt;p&gt;该值在 Dubbo Spring Cloud 加持下被视作 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.application.name&lt;/code&gt;，因此，无需再显示地配置 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.application.name&lt;/code&gt;&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring.main.allow-bean-definition-overriding&lt;/code&gt; : 在 Spring Boot 2.1 以及更高的版本增加该设定，
因为 Spring Boot 默认调整了 Bean 定义覆盖行为。（推荐一个好的 Dubbo 讨论 &lt;a href=&quot;https://github.com/apache/incubator-dubbo/issues/3193#issuecomment-474340165&quot;&gt;issue #3193&lt;/a&gt;）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring.cloud.nacos.discovery&lt;/code&gt; : Nacos 服务发现与注册配置，其中子属性 server-addr 指定 Nacos 服务器主机和端口&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;以上完整的 YAML 配置文件，请参考 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-server-sample&lt;/code&gt; &lt;a href=&quot;spring-cloud-dubbo-server-sample/src/main/resources/bootstrap.yaml&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap.yaml&lt;/code&gt;&lt;/a&gt; 文件&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;完成以上步骤后，还需编写一个 Dubbo Spring Cloud 引导类。&lt;/p&gt;

&lt;h4 id=&quot;引导-dubbo-spring-cloud-服务提供方应用&quot;&gt;引导 Dubbo Spring Cloud 服务提供方应用&lt;/h4&gt;

&lt;p&gt;Dubbo Spring Cloud 引导类与普通 Spring Cloud 应用并无差别，如下所示：&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nd&quot;&gt;@EnableDiscoveryClient&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@EnableAutoConfiguration&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DubboSpringCloudServerBootstrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;SpringApplication&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DubboSpringCloudServerBootstrap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在引导 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DubboSpringCloudServerBootstrap&lt;/code&gt; 之前，请提前启动 Nacos 服务器。
当 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DubboSpringCloudServerBootstrap&lt;/code&gt; 启动后，将应用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-server-sample&lt;/code&gt; 将出现在 Nacos 控制台界面。&lt;/p&gt;

&lt;p&gt;当 Dubbo 服务提供方启动后，下一步实现一个 Dubbo 服务消费方。&lt;/p&gt;

&lt;h3 id=&quot;实现-dubbo-服务消费方&quot;&gt;实现 Dubbo 服务消费方&lt;/h3&gt;

&lt;p&gt;由于 Java 服务就 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EchoService&lt;/code&gt;、服务提供方应用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-server-sample&lt;/code&gt; 以及 Nacos 服务器均已准备完毕。Dubbo 服务消费方
只需初始化服务消费方 Maven 工程 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-client-sample&lt;/code&gt; 以及消费 Dubbo 服务。&lt;/p&gt;

&lt;h4 id=&quot;初始化-spring-cloud-dubbo-client-sample-maven-工程&quot;&gt;初始化 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-client-sample&lt;/code&gt; Maven 工程&lt;/h4&gt;

&lt;p&gt;与服务提供方 Maven 工程类，需添加相关 Maven 依赖：&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Spring Cloud Alibaba dependencies --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-alibaba-dependencies&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.9.0.RELEASE&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span class=&quot;nt&quot;&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span class=&quot;nt&quot;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependencyManagement&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Sample API --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-dubbo-sample-api&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${project.version}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Spring Boot dependencies --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-actuator&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Dubbo Spring Cloud Starter --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-dubbo&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Spring Cloud Nacos Service Discovery --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-alibaba-nacos-discovery&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;与应用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-server-sample&lt;/code&gt; 不同的是，当前应用依赖 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-boot-starter-web&lt;/code&gt;，表明它属于 Web Servlet 应用。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;以上完整的 Maven 依赖配置，请参考 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-client-sample&lt;/code&gt; &lt;a href=&quot;spring-cloud-dubbo-client-sample/pom.xml&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pom.xml&lt;/code&gt;&lt;/a&gt; 文件&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&quot;配置-dubbo-服务消费方&quot;&gt;配置 Dubbo 服务消费方&lt;/h4&gt;

&lt;p&gt;Dubbo 服务消费方配置与服务提供方类似，当前应用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-client-sample&lt;/code&gt; 属于纯服务消费方，因此，所需的外部化配置更精简：&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;na&quot;&gt;dubbo&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;registry&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# 挂载到 Spring Cloud 注册中心&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;spring-cloud://localhost&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;cloud&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;subscribed-services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;spring-cloud-alibaba-dubbo-server&lt;/span&gt;
    
&lt;span class=&quot;na&quot;&gt;spring&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Dubbo 应用名称&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;spring-cloud-alibaba-dubbo-client&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Spring Boot 2.1 需要设定&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;allow-bean-definition-overriding&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;cloud&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;nacos&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Nacos 服务发现与注册配置&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;discovery&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;server-addr&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;127.0.0.1:8848&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;对比应用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-server-sample&lt;/code&gt;，除应用名称 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring.application.name&lt;/code&gt; 存在差异外，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-client-sample&lt;/code&gt;
新增了属性 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.cloud.subscribed-services&lt;/code&gt; 的设置。并且该值为服务提供方应用 “spring-cloud-dubbo-server-sample”。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.cloud.subscribed-services&lt;/code&gt; : 用于服务消费方订阅服务提供方的应用名称的列表，若需订阅多应用，使用 “,” 分割。
不推荐使用默认值为 “*“，它将订阅所有应用。
    &lt;blockquote&gt;
      &lt;p&gt;当应用使用属性 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.cloud.subscribed-services&lt;/code&gt; 默认值时，日志中将会输出一行警告：&lt;/p&gt;
      &lt;blockquote&gt;
        &lt;p&gt;Current application will subscribe all services(size:x) in registry, a lot of memory and CPU cycles may be used,
thus it’s strongly recommend you using the externalized property ‘dubbo.cloud.subscribed-services’ to specify the services&lt;/p&gt;
      &lt;/blockquote&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;由于当前应用属于 Web 应用，它会默认地使用 8080 作为 Web 服务端口，如果需要自定义，可通过属性 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;server.port&lt;/code&gt; 调整。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;以上完整的 YAML 配置文件，请参考 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-client-sample&lt;/code&gt; &lt;a href=&quot;spring-cloud-dubbo-client-sample/src/main/resources/bootstrap.yaml&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap.yaml&lt;/code&gt;&lt;/a&gt; 文件&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&quot;引导-dubbo-spring-cloud-服务消费方应用&quot;&gt;引导 Dubbo Spring Cloud 服务消费方应用&lt;/h4&gt;

&lt;p&gt;为了减少实现步骤，以下引导类将 Dubbo 服务消费以及引导功能合二为一：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nd&quot;&gt;@EnableDiscoveryClient&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@EnableAutoConfiguration&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@RestController&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DubboSpringCloudClientBootstrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Reference&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EchoService&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;echoService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@GetMapping&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/echo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;echoService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;SpringApplication&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DubboSpringCloudClientBootstrap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;不仅如此，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DubboSpringCloudClientBootstrap&lt;/code&gt; 也作为 REST Endpoint，通过暴露 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/echo&lt;/code&gt; Web 服务，消费 Dubbo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EchoService&lt;/code&gt; 服务。因此，
可通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; 命令执行 HTTP GET 方法：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;$ curl http://127.0.0.1:8080/echo?message=%E5%B0%8F%E9%A9%AC%E5%93%A5%EF%BC%88mercyblitz%EF%BC%89
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;HTTP 响应为：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;[echo] Hello, 小马哥（mercyblitz）
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;以上结果说明应用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-client-sample&lt;/code&gt; 通过消费 Dubbo 服务，返回服务提供方 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring-cloud-dubbo-server-sample&lt;/code&gt; 运算后的内容。&lt;/p&gt;

&lt;h2 id=&quot;高阶示例&quot;&gt;高阶示例&lt;/h2&gt;

&lt;p&gt;如果您需要进一步了解 Dubbo Spring Cloud 使用细节，可参考官方 Samples：https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples&lt;/p&gt;

&lt;p&gt;其子模块说明如下：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;spring-cloud-dubbo-sample-api：API 模块，存放 Dubbo 服务接口和模型定义&lt;/li&gt;
  &lt;li&gt;spring-cloud-dubbo-provider-web-sample：Dubbo Spring Cloud 服务提供方示例（Web 应用）&lt;/li&gt;
  &lt;li&gt;spring-cloud-dubbo-provider-sample：Dubbo Spring Cloud 服务提供方示例（非 Web 应用）&lt;/li&gt;
  &lt;li&gt;spring-cloud-dubbo-consumer-sample：Dubbo Spring Cloud 服务消费方示例&lt;/li&gt;
  &lt;li&gt;spring-cloud-dubbo-servlet-gateway-sample：Dubbo Spring Cloud Servlet 网关简易实现示例&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;问题反馈&quot;&gt;问题反馈&lt;/h2&gt;
&lt;p&gt;如果您在使用 Dubbo Spring Cloud 的过程中遇到任何问题，请内容反馈至 https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues&lt;/p&gt;

&lt;h2 id=&quot;进阶阅读&quot;&gt;进阶阅读&lt;/h2&gt;
&lt;p&gt;关于更多的 Dubbo Spring Cloud 特性以及设计细节，请关注&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Spring Cloud Alibaba wiki - https://github.com/spring-cloud-incubator/spring-cloud-alibaba/wiki&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Dubbo 的博客：http://dubbo.apache.org/zh-cn/blog/index.html&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;下篇预告&quot;&gt;下篇预告&lt;/h2&gt;

&lt;p&gt;接下的文章将会介绍 Dubbo Spring Cloud 高阶示例的运用和实现，敬请关注小马哥微信公众号：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;次灵均阁&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://camo.githubusercontent.com/36671f72e171f0c95f33f781f294b3e6bdceef07/68747470733a2f2f6d65726379626c69747a2e6769746875622e696f2f626f6f6b732f7468696e6b696e672d696e2d737072696e672d626f6f742f6173736574732f6d795f6d705f7172636f64652e6a7067&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/36671f72e171f0c95f33f781f294b3e6bdceef07/68747470733a2f2f6d65726379626c69747a2e6769746875622e696f2f626f6f6b732f7468696e6b696e672d696e2d737072696e672d626f6f742f6173736574732f6d795f6d705f7172636f64652e6a7067&quot; alt=&quot;img&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;获得最新 Dubbo Spring Cloud 相关资讯。&lt;/p&gt;

&lt;h2 id=&quot;新书推荐&quot;&gt;&lt;a href=&quot;https://item.jd.com/12570242.html&quot;&gt;新书推荐&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;本书全名为&lt;a href=&quot;https://mercyblitz.github.io/books/thinking-in-spring-boot/&quot;&gt;《Spring Boot 编程思想》&lt;/a&gt;，是以 Spring Boot 2.0 为讨论的主线，讨论的范围将涵盖 Spring Boot 1.x 的所有版本，以及所关联的 Spring Framework 版本，致力于：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;场景分析：掌握技术选型&lt;/li&gt;
  &lt;li&gt;系统学习：拒绝浅尝辄止&lt;/li&gt;
  &lt;li&gt;重视规范：了解发展趋势&lt;/li&gt;
  &lt;li&gt;源码解读：理解设计思想&lt;/li&gt;
  &lt;li&gt;实战演练：巩固学习成果&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/img/bVbqfh2&quot; alt=&quot;clipboard.png&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;欢迎小伙伴在京东或当当订购
京东存有少量现货（随机发送签名版），可先睹为快：http://t.cn/ExjBU2M
当当价格优惠，需要五月初发货：http://t.cn/EX0QteF&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;分享推荐&quot;&gt;分享推荐&lt;/h2&gt;

&lt;h3 id=&quot;免费分享&quot;&gt;免费分享&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.douyu.com/mercyblitz&quot;&gt;「小马哥技术周报」&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://www.douyu.com/mercyblitz&quot;&gt;斗鱼直播&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://space.bilibili.com/327910845/channel/detail?cid=52311&quot;&gt;B 站录播&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.imooc.com/t/5387391&quot;&gt;「慕课网」&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://www.imooc.com/learn/933&quot;&gt;Spring Boot 2.0深度实践-初遇Spring Boot&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://www.imooc.com/learn/1058&quot;&gt;Spring Boot 2.0深度实践之系列总览&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://segmentfault.com/u/mercyblitz&quot;&gt;「SegmentFault」&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://mp.weixin.qq.com/s?__biz=MzIxNDU4NjE1OQ==&amp;amp;mid=2247484085&amp;amp;idx=1&amp;amp;sn=5905f53e69bae9d48b3783a83bde40b3&quot;&gt;「小马哥 2019 跨年直播」一入 Java 深似海，从此“劝退”成必然&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;收费分享&quot;&gt;收费分享&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://t.cn/RnxUYzd&quot;&gt;「小马哥 Java 知识星球」&lt;/a&gt;
    &lt;blockquote&gt;
      &lt;p&gt;深入探讨 Java 相关技术，包括行业动态，架构设计，设计模式，框架使用，源码分析等。&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;SegmentFault 直播
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;http://t.cn/RoC0nNi&quot;&gt;《Java 微服务实践 - Spring Boot / Spring Cloud》&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;http://t.cn/E6bTa9O&quot;&gt;《一入 Java 深似海》&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;慕课视频
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;http://t.cn/ReChCU9&quot;&gt;《Spring Boot 2.0深度实践之核心技术篇》&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;慕课网
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://coding.imooc.com/class/252.html&quot;&gt;Spring Boot 2.0深度实践之核心技术篇&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;Spring Boot 2.0深度实践之生态整合篇（即将上线…）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;关于作者&quot;&gt;关于作者&lt;/h2&gt;

&lt;p&gt;小马哥，Java 劝退师，Apache 和 Spring Cloud 等知名开源架构成员，&lt;a href=&quot;https://mercyblitz.github.io/about/&quot;&gt;点击查看详情&lt;/a&gt;。&lt;/p&gt;

&lt;hr /&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Spring Cloud provides tools for developers to quickly build some of the common patterns in distributed systems (e.g. configuration management, service discovery, circuit breakers, intelligent routing, micro-proxy, control bus, one-time tokens, global locks, leadership election, distributed sessions, cluster state). - https://spring.io/projects/spring-cloud &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;table&gt;
        &lt;tbody&gt;
          &lt;tr&gt;
            &lt;td&gt;Apache Dubbo (incubating)&lt;/td&gt;
            &lt;td&gt;ˈdʌbəʊ&lt;/td&gt;
            &lt;td&gt;is a high-performance, light weight, java based RPC framework. - https://dubbo.apache.org&lt;/td&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;
      &lt;p&gt;&lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Spring Cloud Alibaba provides a one-stop solution for distributed application development. - https://github.com/spring-cloud-incubator/spring-cloud-alibaba &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Nacos is an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications - https://nacos.io/ &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Eureka is a REST (Representational State Transfer) based service that is primarily used in the AWS cloud for locating services for the purpose of load balancing and failover of middle-tier servers. - https://github.com/Netflix/eureka &lt;a href=&quot;#fnref:5&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:6&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. - https://zookeeper.apache.org &lt;a href=&quot;#fnref:6&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:7&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Consul is a distributed service mesh to connect, secure, and configure services across any runtime platform and public or private cloud - https://www.consul.io/ &lt;a href=&quot;#fnref:7&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:8&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Spring Cloud Open Feign - https://github.com/spring-cloud/spring-cloud-openfeign &lt;a href=&quot;#fnref:8&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:9&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;从 2.7.0 开始，Dubbo Spring Boot 与 Dubbo 在版本上保持一致 &lt;a href=&quot;#fnref:9&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:10&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Preview releases of Spring Cloud Alibaba are available: 0.9.0, 0.2.2, and 0.1.2 - &lt;a href=&quot;https://spring.io/blog/2019/04/19/preview-releases-of-spring-cloud-alibaba-are-available-0-9-0-0-2-2-and-0-1-2&quot;&gt;https://spring.io/blog/2019/04/19/preview-releases-of-spring-cloud-alibaba-are-available-0-9-0-0-2-2-and-0-1-2&lt;/a&gt; &lt;a href=&quot;#fnref:10&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:11&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;目前最新的 Spring Cloud “F” 版的版本为：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Finchley.SR2&lt;/code&gt; - &lt;a href=&quot;https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html&quot;&gt;https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html&lt;/a&gt; &lt;a href=&quot;#fnref:11&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:12&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;当前Spring Cloud “G” 版为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Greenwich.RELEASE&lt;/code&gt; &lt;a href=&quot;#fnref:12&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:13&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Spring Cloud 特性列表 - &lt;a href=&quot;https://cloud.spring.io/spring-cloud-static/Greenwich.RELEASE/single/spring-cloud.html#_features&quot;&gt;https://cloud.spring.io/spring-cloud-static/Greenwich.RELEASE/single/spring-cloud.html#_features&lt;/a&gt; &lt;a href=&quot;#fnref:13&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:14&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Dubbo 2.7 开始支持配置中心，可自定义适配 - &lt;a href=&quot;http://dubbo.apache.org/zh-cn/docs/user/configuration/config-center.html&quot;&gt;http://dubbo.apache.org/zh-cn/docs/user/configuration/config-center.html&lt;/a&gt; &lt;a href=&quot;#fnref:14&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:15&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Spring Cloud 原生注册中心，除 Eureka、Zookeeper、Consul 之外，还包括 Spring Cloud Alibaba 中的 Nacos &lt;a href=&quot;#fnref:15&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:16&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Dubbo 原生注册中心 - &lt;a href=&quot;http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html&quot;&gt;http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html&lt;/a&gt; &lt;a href=&quot;#fnref:16&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:17&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Alibaba Sentinel：Sentinel 以流量为切入点，从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性 - &lt;a href=&quot;https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D&quot;&gt;https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D&lt;/a&gt;，目前 Sentinel 已被 Spring Cloud 项目纳为 Circuit Breaker  的候选实现 - &lt;a href=&quot;https://spring.io/blog/2019/04/16/introducing-spring-cloud-circuit-breaker&quot;&gt;https://spring.io/blog/2019/04/16/introducing-spring-cloud-circuit-breaker&lt;/a&gt; &lt;a href=&quot;#fnref:17&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:18&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Spring Cloud Sleuth - &lt;a href=&quot;https://spring.io/projects/spring-cloud-sleuth&quot;&gt;https://spring.io/projects/spring-cloud-sleuth&lt;/a&gt; &lt;a href=&quot;#fnref:18&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:19&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Zipkin - &lt;a href=&quot;https://github.com/apache/incubator-zipkin&quot;&gt;https://github.com/apache/incubator-zipkin&lt;/a&gt; &lt;a href=&quot;#fnref:19&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Fri, 26 Apr 2019 00:00:00 +0000</pubDate>
        <link>https://weibo.com/mercyblitz/2019/04/26/Dubbo-Spring-Cloud-%E9%87%8D%E5%A1%91%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86/</link>
        <guid isPermaLink="true">https://weibo.com/mercyblitz/2019/04/26/Dubbo-Spring-Cloud-%E9%87%8D%E5%A1%91%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86/</guid>
        
        
      </item>
    
      <item>
        <title>《java编程方法论 响应式之rxjava篇》序</title>
        <description>&lt;h1 id=&quot;java编程方法论-响应式之rxjava篇序&quot;&gt;《Java编程方法论 响应式之Rxjava篇》序&lt;/h1&gt;

&lt;p&gt;在《2019 一月的InfoQ 架构和设计趋势报告》&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;中，响应式编程（Reactive Programming）和函数式（Functional Programing）仍旧编列在第一季度（Q1）的 Early Adopters（早期采纳者） 中。尽管这仅是一家之言，然而不少的开发人员逐渐意识到 Reactive 之风俨然吹起。也许您的生产系统尚未出现 Reactive 的身影，不过您可能听说过 Spring WebFlux 或 Netflix Hystrix 等开源框架。笔者曾请教过 Pivotal（Spring 母公司）布道师 Josh Long&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;：”Spring 技术栈未来的重心是否要布局在 Reactive 之上？“。对方的答复是：”没错，Reactive 是未来趋势。“。同时，越来越多的开源项目开始签署 Reactive 宣言（The Reactive Manifesto）&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;，并喊出 ”Web Are Reactive“ 的口号。&lt;/p&gt;

&lt;p&gt;或许开源界的种种举动无法说服您向 Reactive 的”港湾“中停靠，不过 Java 9  Flow API&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; 的引入，又给业界注入了一剂强心针。不难看出，无论是 Java API，还是 Java 框架均走向了 Reactive 编程模型的道路，这并非是一种巧合。&lt;/p&gt;

&lt;p&gt;通常，人们谈到的 Reactive 可与 Reactive 编程划上等号，以”非阻塞（Non-Blocking）“和”异步（Asynchronous）“的特性并述，数据结构与操作相辅相成。Reactive 涉及函数式和并发两种编程模型，前者关注语法特性，后者强调执行效率。简言之，Reactive 编程的意图在于 ”Less Code，More Efficient“。除此之外，个人认为 Reactive 更大的价值在于统一 Java 并发编程模型，使得同步和异步的实现代码无异，同时做到 Java 编程风格与其他编程语言更好地融合，或许您也发现 Java  与 JS 在 Reactive 方面并不存在本质区别。纵观 Java 在 Reactive 编程上的发展而看，其特性更新可谓是步步为营，如履薄冰。尽管 Java 线程 API &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Thread&lt;/code&gt; 与 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Runnable&lt;/code&gt; 就已具备异步以及非阻塞的能力，然而同步和异步编程的模式并不统一，并且理解 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Thread&lt;/code&gt; API 的细节和管理线程生命周期的成本均由开发人员概括承受。虽然 Java 5 引入 J.U.C 框架（Java 并发框架）之后， &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecutorService&lt;/code&gt; 实现减轻了以上负担。不过开发人员仍需关注 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecutorService&lt;/code&gt; 实现细节，比如怎样合理地设置线程池空间以及阻塞队列又成为新的挑战。为此，Java 7 又引入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ForkJoinPool&lt;/code&gt; API，不过此时的J.U.C 框架与 Reactive 理念仍存在距离，即使是线程安全的数据结构，也并不具备并行计算的能力，如：集合并行排序，同时操作集合的手段也相当的贫瘠，缺少类似 Map/Reduce 等操作。不过这些困难只是暂时的，终究被 Java 8 ”救赎“。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt; API 的出现不但具备数据操作在串行和并行间自由切换的能力，如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sequential()&lt;/code&gt; 以及 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parallel()&lt;/code&gt; 方法，而且淡化了并发的特性，如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sorted()&lt;/code&gt; 方法即可能是传统排序，亦或是并行排序。相同的设计哲学也体现在 Java Reactive 实现框架中，如同书中提及的 RxJava&lt;sup id=&quot;fnref:5&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:5&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; API &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;io.reactivex.Observable&lt;/code&gt; 。统一编程模型只是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt; 其中设计目标之一，它结合 Lambda 语法特性，虽然提供了数量可观的操作方法，如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flatMap()&lt;/code&gt; 等，然而无论对比 RxJava，还是  Reactor&lt;sup id=&quot;fnref:6&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:6&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt; ，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt; 操作方法却又相形见绌。值得一提的是，这些操作方法在 Reactive 的术语中称之为操作符（Operators）。当然框架内建的操作符的多与寡，并非判断其是否为 Reactive 实现的依据。其中决定性因素在于数据必须来源于发布方（生产者）的”推送（Push）“，而非消费端的”拉取（Pull）“。显然，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt;  属于消费端已就绪（Ready）的数据集合，并不存在其他数据推送源。不过 JVM 语言早期的 Reactive 定义处于模糊地带，如 RxJava  API 属于观察者模式（Observer Pattern）&lt;sup id=&quot;fnref:7&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:7&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;的扩展，而非迭代器（Iterator Pattern）模式&lt;sup id=&quot;fnref:8&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:8&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;的实现。而 Reactor 的实现则拥抱 Reactive Streams 规范&lt;sup id=&quot;fnref:9&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:9&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;9&lt;/a&gt;&lt;/sup&gt; ，该规范消费端对于数据的操作是被动的处理，而非主动的索。换言之，数据的到达存在着不确定性&lt;sup id=&quot;fnref:10&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:10&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;10&lt;/a&gt;&lt;/sup&gt;。当推送的数据无法得到消费端及时效应时，Reactive 框架必须提供背压（Backpressure）&lt;sup id=&quot;fnref:11&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:11&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;11&lt;/a&gt;&lt;/sup&gt;实现，确保消费端拥有”拒绝的权利（cancel）”。在此理论基础上，Reactive Streams 规范定义了一套抽象的 API，作为 Java 9 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.util.concurrent.Flow&lt;/code&gt; API 的顶层设计。不过关于操作符的部分，该规范似乎不太关心，这也是为什么 RxJava 和 Reactor 均称自身为 Reactive 扩展框架的原因，同时两者在 API 级别提供多种调度器（Schedulers）&lt;sup id=&quot;fnref:12&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:12&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;12&lt;/a&gt;&lt;/sup&gt;实现，适配不同并发场景提供。尽管 Reactive 定义在不同的阵营之间存在差异，援引本人在《Reactive-Programming-一种技术-各自表述》&lt;sup id=&quot;fnref:13&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:13&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;13&lt;/a&gt;&lt;/sup&gt;文中的总结：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Reactive Programming 作为观察者模式（&lt;a href=&quot;https://en.wikipedia.org/wiki/Observer_pattern&quot;&gt;Observer&lt;/a&gt;） 的延伸，不同于传统的命令编程方式（ &lt;a href=&quot;https://en.wikipedia.org/wiki/Imperative_programming&quot;&gt;Imperative programming&lt;/a&gt;）同步拉取数据的方式，如迭代器模式（&lt;a href=&quot;https://en.wikipedia.org/wiki/Iterator_pattern&quot;&gt;Iterator&lt;/a&gt;） 。而是采用数据发布者同步或异步地推送到数据流（Data Streams）的方案。当该数据流（Data Steams）订阅者监听到传播变化时，立即作出响应动作。在实现层面上，Reactive Programming 可结合函数式编程简化面向对象语言语法的臃肿性，屏蔽并发实现的复杂细节，提供数据流的有序操作，从而达到提升代码的可读性，以及减少 Bugs 出现的目的。同时，Reactive Programming 结合背压（Backpressure）的技术解决发布端生成数据的速率高于订阅端消费的问题。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;不难看出，Reactive 是一门综合的编程艺术，在实现框架的加持下，相同的代码逻辑实现同步和异步非阻塞功能，从而达到提升应用整体性能的目的。不过现实的情况或许没有那么理想，Spring 官方文档在《Web on Reactive Stack》章节中提到，”Reactive 和非阻塞通常并不是让应用运行的更快”&lt;sup id=&quot;fnref:14&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:14&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;14&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Reactive and non-blocking generally do not make applications run faster.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;为此，JHipster&lt;sup id=&quot;fnref:15&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:15&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;15&lt;/a&gt;&lt;/sup&gt; 给出了一份《 Spring 5 WebFlux 性能测试报告》&lt;sup id=&quot;fnref:16&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:16&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;16&lt;/a&gt;&lt;/sup&gt;，其中一条结论是，”Reactive 应用并没有表现出速度提升（甚至是变得更差）“：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;No improvement in speed was observed with our reactive apps (the Gatling results are even slightly worse).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;数月后，看似相反的结论却在DZone&lt;sup id=&quot;fnref:17&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:17&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;17&lt;/a&gt;&lt;/sup&gt;一篇名为《Raw Performance Numbers - Spring Boot 2 Webflux vs. Spring Boot 1》&lt;sup id=&quot;fnref:18&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:18&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;18&lt;/a&gt;&lt;/sup&gt;的文中出现，测试结果是 Spring Boot 2 WebFlux在高并发下响应时间更为平稳。实际上，这个测试结论有些”关公战秦琼“的味道，毕竟 Spring Boot 2.0 下的 WebFlux 和 Spring Boot 1.0 中的 Servlet  容器所使用线程模型是不同的，并且 Servlet 3.0 异步以及非阻塞特性缺省是关闭的。不过以上两篇的结论并不矛盾，前者关注于响应速度，后者则强调吞吐量，都是性能的核心指标。遗憾的是，两篇文章均未对各自的测试用例做出调优，因此以上结论都存在一定的局限性，这也是本人对 Reactive 技术能否提升性能提出质疑的地方。&lt;/p&gt;

&lt;p&gt;如果本人是国内提出 Reactive 问题的第一人的话，那么知秋&lt;sup id=&quot;fnref:19&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:19&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;19&lt;/a&gt;&lt;/sup&gt;就是国内第一个解决问题的人。作为国内为数不多的 Reactive 以及 NIO 方面的专家，在技术研究上，他追求格物致知，不轻忽技术细节。在知识分享上，他可谓是知无不言，言无不尽，不仅在社交群中答疑解惑，而且录制免费视频，发布在 B 站&lt;sup id=&quot;fnref:20&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:20&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;20&lt;/a&gt;&lt;/sup&gt;以及 YouTube 频道&lt;sup id=&quot;fnref:21&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:21&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;21&lt;/a&gt;&lt;/sup&gt;，并得到 Josh Long 等大佬的推文(Twitter)。或许以上方式还不足以完整地讨论 Java Reactive 技术，知秋选择了漫长而又艰苦的著书之路，尽管他是本人的朋友，然而 ”内举不避亲“，笔者推荐给读者朋友，首先是因为这是大陆地区第一本全面解读 Java Reactive 技术的书籍，除作者的雄厚技术积累背书之外，书中的知识脉络是循序渐进的。同时，这也是一本引人深思的书，本书在导读源码的同时，也引导读者对于代码设计上的思考。再者，这又是一本知识苦旅的书，因为它涉及面较广，读者不仅需要具备一定的 Java 并发以及面向对象设计，而且需要读者付出较多的时间去反复推敲。正所谓”夫夷以近，则游者众；险以远，则至者少“&lt;sup id=&quot;fnref:22&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:22&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;22&lt;/a&gt;&lt;/sup&gt;，笔者希望读者在购买此书后，不轻言放弃，当您面临挑战时，那才是成长的开始。同时，也期盼读者将 Reactive 技术付之于实践，提早触碰未来。&lt;/p&gt;

&lt;p&gt;小马哥（mercyblitz)&lt;sup id=&quot;fnref:23&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:23&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;23&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;2019 年 3 月 5 日&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Architecture and Design InfoQ Trends Report - January 2019 - https://www.infoq.com/articles/architecture-trends-2019 &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Josh (@starbuxman) is the Spring Developer Advocate at Pivotal and a Java Champion - https://spring.io/team/jlong &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;The Reactive Manifesto -  https://www.reactivemanifesto.org &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/Flow.html &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;RxJava: Reactive Extensions for the JVM - https://github.com/ReactiveX/RxJava6 &lt;a href=&quot;#fnref:5&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:6&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Reactor is a fully non-blocking reactive programming foundation for the JVM, with efficient demand management (in the form of managing “backpressure”). - https://github.com/reactor/reactor-core &lt;a href=&quot;#fnref:6&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:7&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Observer Pattern - http://en.wikipedia.org/wiki/observer_pattern &lt;a href=&quot;#fnref:7&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:8&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Iterator Pattern - https://en.wikipedia.org/wiki/Iterator_pattern &lt;a href=&quot;#fnref:8&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:9&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Reactive Streams is an initiative to provide a standard for asynchronous stream processing with non-blocking back pressure. - https://www.reactive-streams.org/ &lt;a href=&quot;#fnref:9&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:10&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Handling streams of data—especially “live” data whose volume is not predetermined - https://github.com/reactive-streams/reactive-streams-jvm#goals-design-and-scope &lt;a href=&quot;#fnref:10&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:11&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Backpressure is an integral part of this model in order to allow the queues which mediate between threads to be bounded. The benefits of asynchronous processing would be negated if the backpressure signals were synchronous (see also the &lt;a href=&quot;http://reactivemanifesto.org/&quot;&gt;Reactive Manifesto&lt;/a&gt;), therefore care has been taken to mandate fully non-blocking and asynchronous behavior of all aspects of a Reactive Streams implementation. - https://github.com/reactive-streams/reactive-streams-jvm#goals-design-and-scope &lt;a href=&quot;#fnref:11&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:12&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;RxJava Scheduler - http://reactivex.io/documentation/scheduler.html, Reactor Schedulers : https://projectreactor.io/docs/core/release/reference/#schedulers &lt;a href=&quot;#fnref:12&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:13&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;《Reactive Programming 一种技术，各自表述》：https://mercyblitz.github.io/2018/07/25/Reactive-Programming-一种技术-各自表述 &lt;a href=&quot;#fnref:13&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:14&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;1.1.6. Performance - https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-performance &lt;a href=&quot;#fnref:14&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:15&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;JHipster -https://www.jhipster.tech/ &lt;a href=&quot;#fnref:15&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:16&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;《Spring 5 WebFlux: Performance tests》- https://blog.ippon.tech/spring-5-webflux-performance-tests &lt;a href=&quot;#fnref:16&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:17&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;DZone : https://dzone.com &lt;a href=&quot;#fnref:17&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:18&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;《Raw Performance Numbers - Spring Boot 2 Webflux vs. Spring Boot 1》 - https://dzone.com/articles/raw-performance-numbers-spring-boot-2-webflux-vs-s &lt;a href=&quot;#fnref:18&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:19&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;知秋，本书的作者笔名 &lt;a href=&quot;#fnref:19&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:20&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;https://space.bilibili.com/2494318 &lt;a href=&quot;#fnref:20&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:21&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;https://www.youtube.com/channel/UCmxVT2rkFwDX1tPpVDPJQaQ &lt;a href=&quot;#fnref:21&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:22&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;《游褒禅山记》，王安石 &lt;a href=&quot;#fnref:22&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:23&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;小马哥，&lt;a href=&quot;https://www.douyu.com/mercyblitz&quot;&gt;Java 劝退师&lt;/a&gt;，&lt;a href=&quot;https://dubbo.apache.org/&quot;&gt;Apache Dubbo&lt;/a&gt; PPMC、&lt;a href=&quot;https://github.com/spring-cloud-incubator/spring-cloud-alibaba&quot;&gt;Spring Cloud Alibaba&lt;/a&gt; 项目架构师 - https://mercyblitz.github.io/about/ &lt;a href=&quot;#fnref:23&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Tue, 05 Mar 2019 00:00:00 +0000</pubDate>
        <link>https://weibo.com/mercyblitz/2019/03/05/Java%E7%BC%96%E7%A8%8B%E6%96%B9%E6%B3%95%E8%AE%BA-%E5%93%8D%E5%BA%94%E5%BC%8F%E4%B9%8BRxjava%E7%AF%87-%E5%BA%8F/</link>
        <guid isPermaLink="true">https://weibo.com/mercyblitz/2019/03/05/Java%E7%BC%96%E7%A8%8B%E6%96%B9%E6%B3%95%E8%AE%BA-%E5%93%8D%E5%BA%94%E5%BC%8F%E4%B9%8BRxjava%E7%AF%87-%E5%BA%8F/</guid>
        
        
      </item>
    
      <item>
        <title>Reactive programming 一种技术 各自表述</title>
        <description>&lt;h1 id=&quot;reactive-programming-一种技术各自表述&quot;&gt;Reactive Programming 一种技术，各自表述&lt;/h1&gt;

&lt;h2 id=&quot;前言&quot;&gt;前言&lt;/h2&gt;

&lt;p&gt;作为一名 Java 开发人员，尤其是 Java 服务端工程师，对于 Reactive Programming 的概念似乎相对陌生。随着 Java 9 以及 Spring Framework 5 的相继发布，Reactive 技术逐渐开始被广大从业人员所注意，笔者作为其中一员，更渴望如何理解 Reactive Programming，以及它所带来的哪些显著的编程变化，更为重要的是，怎么将其用于实际生产环境，解决当前面临的问题。然而，随着时间的推移和了解的深入，笔者对  Reactive Programming  的热情逐渐被浇息，对它的未来保持谨慎乐观的态度。&lt;/p&gt;

&lt;p&gt;本文从理解 Reactive Programming 的角度出发，尽可能地保持理性和中立的态度，讨论 Reactive Programming 的实质。&lt;/p&gt;

&lt;h2 id=&quot;初识-reactive&quot;&gt;初识 Reactive&lt;/h2&gt;

&lt;p&gt;笔者第一次接触 Reactive 技术的时间还要回溯到 2015年末，当时部分应用正使用 Hystrix 实现服务熔断，而 Hystrix 底层依赖是 RxJava 1.x，RxJava 是 Reactive 在 Java 编程语言的扩展框架。当时接触 Reactive 只能算上一种间接的接触，根据 Hystrix 特性来理解 Reactive 技术，感觉上，Hystrix 超时和信号量等特性与 Java 并发框架（J.U.C）的关系密切，进而认为 Reactive 是 J.U.C 的扩展。随后，笔者便参考了两本关于 Reactive Java 编程方面的书：《Reactive Java Programming》和《Reactive Programming with RxJava》。遗憾的是，两者尽管详细地描述 RxJava 的使用方法，然而却没有把 Reactive 使用场景讨论到要点上，如《Reactive Programming with RxJava》所给出的使用场景说明：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;When You Need Reactive Programming&lt;/p&gt;

  &lt;p&gt;Reactive programming is useful in scenarios such as the following:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Processing user events such as mouse movement and clicks, keyboard typing,GPS signals changing over time as users move with their device, device gyroscope signals, touch events, and so on.&lt;/li&gt;
    &lt;li&gt;Responding to and processing any and all latency-bound IO events from disk or network, given that IO is inherently asynchronous …&lt;/li&gt;
    &lt;li&gt;Handling events or data pushed at an application by a producer it cannot control …&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;实际上，以上三种使用场景早已在 Java 生态中完全地实现并充分地实践，它们对应的技术分别是  Java AWT/Swing、NIO/AIO 以及 JMS（Java 消息服务）。那么，再谈 RxJava 的价值又在哪里呢？如果读者是初学者，或许还能蒙混过关。好奇心促使笔者重新开始踏上探索 Reactive 之旅。&lt;/p&gt;

&lt;h2 id=&quot;理解-reactive&quot;&gt;理解 Reactive&lt;/h2&gt;

&lt;p&gt;2017年 Java 技术生态中，最有影响力的发布莫过于 Java 9 和 Spring 5，前者主要支持模块化，次要地提供了 Flow API 的支持，后者则将”身家性命“压在 Reactive 上面，认为 Reactive 是未来的趋势，它以 Reactive 框架 Reactor 为基础，逐步构建一套完整的 Reactive 技术栈，其中以 WebFlux 技术为最引人关注，作为替代 Servlet Web 技术栈的核心特性，承载了多年 Spring 逆转 Java EE 的初心。于是，业界开始大力地推广 Reactive 技术，于是笔者又接触到一些关于 Reactive 的讲法。&lt;/p&gt;

&lt;h3 id=&quot;关于-reactive-的一些讲法&quot;&gt;关于 Reactive 的一些讲法&lt;/h3&gt;

&lt;p&gt;其中笔者挑选了以下三种出镜率最高的讲法：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Reactive 是异步非阻塞编程&lt;/li&gt;
  &lt;li&gt;Reactive 能够提升程序性能&lt;/li&gt;
  &lt;li&gt;Reactive 解决传统编程模型遇到的困境&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;第一种说法描述了功能特性，第二种说法表达了性能收效，第三种说法说明了终极目地。下面的讨论将围绕着这三种讲法而展开，深入地探讨 Reactive Programming 的实质，并且理解为什么说 Reactive Programming 是”一种技术，各自表述“。&lt;/p&gt;

&lt;p&gt;同时，讨论的方式也一反常态，并不会直奔主题地解释什么 Reactive Programming，而是从问题的角度出发，从 Reactive 规范和框架的论点，了解传统编程模型中所遇到的困境，逐步地揭开 Reactive 神秘的面纱。其中 Reactive 规范是 JVM Reactive 扩展规范 &lt;a href=&quot;https://github.com/reactive-streams/reactive-streams-jvm&quot;&gt;Reactive Streams JVM&lt;/a&gt;，而 Reactive 实现框架则是最典型的实现：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Java 9 Flow API&lt;/li&gt;
  &lt;li&gt;RxJava&lt;/li&gt;
  &lt;li&gt;Reactor&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;传统编程模型中的某些困境&quot;&gt;传统编程模型中的某些困境&lt;/h3&gt;

&lt;h4 id=&quot;reactor-认为阻塞可能是浪费的&quot;&gt;&lt;a href=&quot;http://projectreactor.io/docs/core/release/reference/#_blocking_can_be_wasteful&quot;&gt;Reactor&lt;/a&gt; 认为阻塞可能是浪费的&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;h3 id=&quot;31-blocking-can-be-wasteful&quot;&gt;3.1. Blocking Can Be Wasteful&lt;/h3&gt;

  &lt;p&gt;Modern applications can reach huge numbers of concurrent users, and, even though the capabilities of modern hardware have continued to improve, performance of modern software is still a key concern.&lt;/p&gt;

  &lt;p&gt;There are broadly two ways one can improve a program’s performance:&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;&lt;strong&gt;parallelize&lt;/strong&gt;: use more threads and more hardware resources.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;seek more efficiency&lt;/strong&gt; in how current resources are used.&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;Usually, Java developers write programs using blocking code. This practice is fine until there is a performance bottleneck, at which point the time comes to introduce additional threads, running similar blocking code. But this scaling in resource utilization can quickly introduce contention and concurrency problems.&lt;/p&gt;

  &lt;p&gt;Worse still, blocking wastes resources.&lt;/p&gt;

  &lt;p&gt;So the parallelization approach is not a silver bullet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;将以上 Reactor 观点归纳如下，它认为：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;阻塞导致性能瓶颈和浪费资源&lt;/li&gt;
  &lt;li&gt;增加线程可能会引起资源竞争和并发问题&lt;/li&gt;
  &lt;li&gt;并行的方式不是银弹（不能解决所有问题）&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;第三点基本上是废话，前面两点则较为容易理解，为了减少理解的偏差，以下讨论将结合示例说明。&lt;/p&gt;

&lt;h5 id=&quot;理解阻塞的弊端&quot;&gt;理解阻塞的弊端&lt;/h5&gt;

&lt;p&gt;假设有一个数据加载器，分别加载配置、用户信息以及订单信息，如下图所示：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;图示&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/DataLoader.png&quot; alt=&quot;image-20180722175037967&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Java 实现&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DataLoader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 开始时间&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;doLoad&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 具体执行&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;costTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 消耗时间&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;load() 总耗时：&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;costTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; 毫秒&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;doLoad&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 串行计算&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;loadConfigurations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;//  耗时 1s&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;loadUsers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;//  耗时 2s&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;loadOrders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;// 耗时 3s&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 总耗时 1s + 2s  + 3s  = 6s&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;loadConfigurations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;loadMock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;loadConfigurations()&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;loadUsers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;loadMock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;loadUsers()&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;loadOrders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;loadMock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;loadOrders()&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;loadMock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;milliseconds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TimeUnit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;SECONDS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toMillis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;milliseconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;costTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[线程 : %s] %s 耗时 :  %d 毫秒\n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;currentThread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;costTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;InterruptedException&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;RuntimeException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DataLoader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;运行结果&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;[线程 : main] loadConfigurations() 耗时 :  1005 毫秒
[线程 : main] loadUsers() 耗时 :  2002 毫秒
[线程 : main] loadOrders() 耗时 :  3001 毫秒
load() 总耗时：6031 毫秒
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;结论&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;由于加载过程串行执行的关系，导致消耗实现线性累加。Blocking 模式即串行执行 。&lt;/p&gt;

&lt;p&gt;不过 Reactor 也提到，以上问题可通过并行的方式来解决，不过编写并行程序较为复杂，那么其中难点在何处呢？&lt;/p&gt;

&lt;h5 id=&quot;理解并行的复杂&quot;&gt;理解并行的复杂&lt;/h5&gt;

&lt;p&gt;再将以上示例由串行调整为并行，如下图所示：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;图示&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/ParallelDataLoader.png&quot; alt=&quot;image-20180722175519583&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Java 代码&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ParallelDataLoader&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DataLoader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;doLoad&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// 并行计算&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ExecutorService&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executorService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Executors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;newFixedThreadPool&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 创建线程池&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;CompletionService&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;completionService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ExecutorCompletionService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executorService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;completionService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadConfigurations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;//  耗时 &amp;gt;= 1s&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;completionService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadUsers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;//  耗时 &amp;gt;= 2s&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;completionService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadOrders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;//  耗时 &amp;gt;= 3s&lt;/span&gt;

        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 等待三个任务完成&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;completionService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;poll&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executorService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;shutdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// 总耗时 max(1s, 2s, 3s)  &amp;gt;= 3s&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ParallelDataLoader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;运行结果&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;[线程 : pool-1-thread-1] loadConfigurations() 耗时 :  1003 毫秒
[线程 : pool-1-thread-2] loadUsers() 耗时 :  2005 毫秒
[线程 : pool-1-thread-3] loadOrders() 耗时 :  3005 毫秒
load() 总耗时：3068 毫秒
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;结论&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;明显地，程序改造为并行加载后，性能和资源利用率得到提升，消耗时间取最大者，即三秒，由于线程池操作的消耗，整体时间将略增一点。不过，以上实现为什么不直接使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future#get()&lt;/code&gt;  方法强制所有任务执行完毕，然后再统计总耗时？&lt;/p&gt;

&lt;p&gt;Reactor 这方面的看法并没有向读者清晰地表达全秒，不过这还不是全部，听听它接下来的说法。&lt;/p&gt;

&lt;h4 id=&quot;reactor-认为异步不一定能够救赎&quot;&gt;&lt;a href=&quot;http://projectreactor.io/docs/core/release/reference/#_asynchronicity_to_the_rescue&quot;&gt;Reactor&lt;/a&gt; 认为异步不一定能够救赎&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;h3 id=&quot;32-asynchronicity-to-the-rescue&quot;&gt;3.2. Asynchronicity to the Rescue?&lt;/h3&gt;

  &lt;p&gt;The second approach (mentioned earlier), seeking more efficiency, can be a solution to the resource wasting problem. By writing &lt;em&gt;asynchronous&lt;/em&gt;, &lt;em&gt;non-blocking&lt;/em&gt; code, you let the execution switch to another active task &lt;strong&gt;using the same underlying resources&lt;/strong&gt; and later come back to the current process when the asynchronous processing has finished.&lt;/p&gt;

  &lt;p&gt;Java offers two models of asynchronous programming:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Callbacks&lt;/strong&gt;: Asynchronous methods do not have a return value but take an extra &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;callback&lt;/code&gt; parameter (a lambda or anonymous class) that gets called when the result is available. A well known example is Swing’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EventListener&lt;/code&gt;hierarchy.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Futures&lt;/strong&gt;: Asynchronous methods return a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&amp;lt;T&amp;gt;&lt;/code&gt; &lt;strong&gt;immediately&lt;/strong&gt;. The asynchronous process computes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T&lt;/code&gt; value, but the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; object wraps access to it. The value is not immediately available, and the object can be polled until the value is available. For instance, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecutorService&lt;/code&gt; running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Callable&amp;lt;T&amp;gt;&lt;/code&gt; tasks use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; objects.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;Are these techniques good enough? Not for every use case, and both approaches have limitations.&lt;/p&gt;

  &lt;p&gt;Callbacks are hard to compose together, quickly leading to code that is difficult to read and maintain (known as “Callback Hell”).&lt;/p&gt;

  &lt;p&gt;Futures are a bit better than callbacks, but they still do not do well at composition, despite the improvements brought in Java 8 by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompletableFuture&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;再次将以上观点归纳，它认为：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Callbacks 是解决非阻塞的方案，然而他们之间很难组合，并且快速地将代码引导至 “Callback Hell” 的不归路&lt;/li&gt;
  &lt;li&gt;Futures  相对于 Callbacks 好一点，不过还是无法组合，不过  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompletableFuture&lt;/code&gt; 能够提升这方面的不足&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;以上 Reactor 的观点仅给出了结论，没有解释现象，其中场景设定也不再简单直白，从某种程度上，这也侧面地说明，Reactive Programming 实际上是”高端玩家“的游戏。接下来，本文仍通过示例的方式，试图解释”Callback Hell” 问题以及 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; 的限制。&lt;/p&gt;

&lt;h5 id=&quot;理解-callback-hell&quot;&gt;理解 “Callback Hell”&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;Java GUI 示例&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JavaGUI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;JFrame&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jFrame&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;JFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;GUI 示例&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setBounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;LayoutManager&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;layoutManager&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BorderLayout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setLayout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layoutManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addMouseListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MouseAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// callback 1&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mouseClicked&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MouseEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[线程 : %s] 鼠标点击，坐标(X : %d, Y : %d)\n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;currentThreadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addWindowListener&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WindowAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// callback 2&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;windowClosing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;WindowEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[线程 : %s] 清除 jFrame... \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentThreadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;jFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dispose&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 清除 jFrame&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;windowClosed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;WindowEvent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;[线程 : %s] 退出程序... \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentThreadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 退出程序&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;当前线程：&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currentThreadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;jFrame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setVisible&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;currentThreadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 当前线程名称&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;currentThread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;运行结果&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;点击窗体并关闭窗口，控制台输出如下：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;当前线程：main
[线程 : AWT-EventQueue-0] 鼠标点击，坐标(X : 180, Y : 121)
[线程 : AWT-EventQueue-0] 鼠标点击，坐标(X : 180, Y : 122)
[线程 : AWT-EventQueue-0] 鼠标点击，坐标(X : 180, Y : 122)
[线程 : AWT-EventQueue-0] 鼠标点击，坐标(X : 180, Y : 122)
[线程 : AWT-EventQueue-0] 鼠标点击，坐标(X : 180, Y : 122)
[线程 : AWT-EventQueue-0] 鼠标点击，坐标(X : 201, Y : 102)
[线程 : AWT-EventQueue-0] 清除 jFrame... 
[线程 : AWT-EventQueue-0] 退出程序...
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;结论&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Java GUI 以及事件/监听模式基本采用匿名内置类实现，即回调实现。从本例可以得出，鼠标的点击确实没有被其他线程给阻塞。不过当监听的维度增多时，Callback 实现也随之增多。Java Swing 事件/监听是一种典型的既符合异步非阻塞，又属于 Callback 实现的场景，其并发模型可为同步或异步。不过，在 Java 8 之前，由于接口无法支持 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt; 方法，当接口方法过多时，通常采用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Adapter&lt;/code&gt; 模式作为缓冲方案，达到按需实现的目的。尤其在 Java GUI 场景中。即使将应用的 Java 版本升级到 8 ，由于这些 Adapter ”遗老遗少“实现的存在，使得开发人员仍不得不面对大量而繁琐的 Callback 折中方案。既然 Reactor 提出了这个问题，那么它或者 Reactive 能否解决这个问题呢？暂时存疑，下一步是如何理解 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; 的限制。&lt;/p&gt;

&lt;h5 id=&quot;理解-future-的限制&quot;&gt;理解 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; 的限制&lt;/h5&gt;

&lt;p&gt;Reactor 的观点仅罗列 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; 的一些限制，并没有将它们解释清楚，接下来用两个例子来说明其中原委。&lt;/p&gt;

&lt;h6 id=&quot;限制一future-的阻塞性&quot;&gt;限制一：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; 的阻塞性&lt;/h6&gt;

&lt;p&gt;在前文示例中，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParallelDataLoader&lt;/code&gt; 利用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompletionService&lt;/code&gt; API 实现 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;load*()&lt;/code&gt; 方法的并行加载，如果将其调整为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; 的实现，可能的实现如下：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Java &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; 阻塞式加载示例&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FutureBlockingDataLoader&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DataLoader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;doLoad&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ExecutorService&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;executorService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Executors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;newFixedThreadPool&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 创建线程池&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;runCompletely&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executorService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadConfigurations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;//  耗时 &amp;gt;= 1s&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;runCompletely&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executorService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadUsers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;//  耗时 &amp;gt;= 2s&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;runCompletely&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executorService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadOrders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;//  耗时 &amp;gt;= 3s&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;executorService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;shutdown&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 总耗时 sum(&amp;gt;= 1s, &amp;gt;= 2s, &amp;gt;= 3s)  &amp;gt;= 6s&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;runCompletely&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Future&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;future&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;future&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 阻塞等待结果执行&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;FutureBlockingDataLoader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;运行结果&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;[线程 : pool-1-thread-1] loadConfigurations() 耗时 :  1003 毫秒
[线程 : pool-1-thread-2] loadUsers() 耗时 :  2004 毫秒
[线程 : pool-1-thread-3] loadOrders() 耗时 :  3002 毫秒
load() 总耗时：6100 毫秒
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;结论&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParallelDataLoader&lt;/code&gt; 加载耗时为”3068 毫秒“，调整后的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FutureBlockingDataLoader&lt;/code&gt; 则比串行的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DataLoader&lt;/code&gt;  加载耗时（“6031 毫秒”）还要长。说明&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future#get()&lt;/code&gt; 方法不得不等待任务执行完成，换言之，如果多个任务提交后，返回的多个 Future 逐一调用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get()&lt;/code&gt; 方法时，将会依次 blocking，任务的执行从并行变为串行。这也是之前为什么 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParallelDataLoader&lt;/code&gt; 不采取 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; 的解决方案的原因。&lt;/p&gt;

&lt;h6 id=&quot;限制二future--不支持链式操作&quot;&gt;限制二：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt;  不支持链式操作&lt;/h6&gt;

&lt;p&gt;由于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt;  无法实现异步执行结果链式处理，尽管 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FutureBlockingDataLoader&lt;/code&gt; 能够解决方法数据依赖以及顺序执行的问题，不过它将并行执行带回了阻塞（串行）执行。所以，它不是一个理想实现。不过  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompletableFuture&lt;/code&gt;  可以帮助提升 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt;  的限制：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Java &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompletableFuture&lt;/code&gt; 重构 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; 链式实现&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FutureChainDataLoader&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DataLoader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;doLoad&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;CompletableFuture&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;runAsync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadConfigurations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;thenRun&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadUsers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;thenRun&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loadOrders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;whenComplete&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;throwable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 完成时回调&lt;/span&gt;
                    &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;加载完成&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 等待完成&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ChainDataLoader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;运行结果&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;[线程 : ForkJoinPool.commonPool-worker-1] loadConfigurations() 耗时 :  1000 毫秒
[线程 : ForkJoinPool.commonPool-worker-1] loadUsers() 耗时 :  2005 毫秒
[线程 : ForkJoinPool.commonPool-worker-1] loadOrders() 耗时 :  3001 毫秒
加载完成
load() 总耗时：6093 毫秒
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;结论&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;通过输出日志分析，  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FutureChainDataLoader&lt;/code&gt; 并没有像 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FutureBlockingDataLoader&lt;/code&gt; 那样使用三个线程分别执行加载任务，仅使用了一个线程，换言之，这三次加载同一线程完成，并且异步于 main 线程，如下所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/FutureChainDataLoader_Sequences.png&quot; alt=&quot;FutureChainDataLoader&quot; /&gt;&lt;/p&gt;

&lt;p&gt;尽管 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompletableFuture&lt;/code&gt;  不仅是异步非阻塞操作，而且还能将 Callback 组合执行，也不存在所谓的 ”Callback Hell“ 等问题。如果强制等待结束的话，又回到了阻塞编程的方式。同时，相对于  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FutureBlockingDataLoader&lt;/code&gt;  实现，重构后的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FutureChainDataLoader&lt;/code&gt; 不存在明显性能提升。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;稍作解释，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompletableFuture&lt;/code&gt;  不仅可以支持 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; 链式操作，而且提供三种生命周期回调，即执行回调（Action）、完成时回调（Complete）、和异常回调（Exception），类似于 Spring 4 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListenableFuture&lt;/code&gt; 以及 Guava &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListenableFuture&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;至此，Reactor 的官方参考文档再没有出现其他有关”传统编程模型中的某些困境“的描述，或许读者老爷和我一样，对 Reactive 充满疑惑，它真能解决以上问题吗？当然，监听则明，偏听则暗，下面我们再来参考 &lt;a href=&quot;https://github.com/reactive-streams/reactive-streams-jvm&quot;&gt;Reactive Streams JVM&lt;/a&gt; 的观点。&lt;/p&gt;

&lt;h4 id=&quot;reactive-streams-jvm-认为异步系统和资源消费需要特殊处理&quot;&gt;&lt;a href=&quot;https://github.com/reactive-streams/reactive-streams-jvm#goals-design-and-scope&quot;&gt;Reactive Streams JVM&lt;/a&gt; 认为异步系统和资源消费需要特殊处理&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;p&gt;Handling streams of data—especially “live” data whose volume is not predetermined—requires special care in an asynchronous system. The most prominent issue is that resource consumption needs to be carefully controlled such that a fast data source does not overwhelm the stream destination. Asynchrony is needed in order to enable the parallel use of computing resources, on collaborating network hosts or multiple CPU cores within a single machine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;观点归纳：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;流式数据容量难以预判&lt;/li&gt;
  &lt;li&gt;异步编程复杂&lt;/li&gt;
  &lt;li&gt;数据源和消费端之间资源消费难以平衡&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;此观点与 Reactor 相同的部分是，两者均认为异步编程复杂，而前者还提出了数据结构（流式数据）以及数据消费问题。&lt;/p&gt;

&lt;p&gt;无论两者的观点孰优谁劣，至少说明一个现象，业界对于 Reactive 所解决的问题并非达到一致，几乎各说各话。那么，到底怎样才算 Reactive Programming 呢？&lt;/p&gt;

&lt;h3 id=&quot;什么是-reactive-programming&quot;&gt;什么是 Reactive Programming&lt;/h3&gt;

&lt;p&gt;关于什么是 Reactive Programming，下面给出六种渠道的定义，尝试从不同的角度，了解 Reactive Programming 的意涵。首先了解的是 “&lt;a href=&quot;https://www.reactivemanifesto.org/&quot;&gt;The Reactive Manifesto&lt;/a&gt;” 中的定义&lt;/p&gt;

&lt;h4 id=&quot;the-reactive-manifesto-中的定义&quot;&gt;&lt;a href=&quot;https://www.reactivemanifesto.org/&quot;&gt;The Reactive Manifesto&lt;/a&gt; 中的定义&lt;/h4&gt;

&lt;p&gt;Reactive Systems are: Responsive, Resilient, Elastic and Message Driven.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;https://www.reactivemanifesto.org/&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;该组织对 Reactive 的定义非常简单，其特点体现在以下关键字：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;响应的（Responsive）&lt;/li&gt;
  &lt;li&gt;适应性强的（Resilient）&lt;/li&gt;
  &lt;li&gt;弹性的（Elastic）&lt;/li&gt;
  &lt;li&gt;消息驱动的（Message Driven）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;不过这样的定义侧重于 Reactive 系统，或者说是设计 Reactive 系统的原则。&lt;/p&gt;

&lt;h4 id=&quot;维基百科中的定义&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Reactive_programming&quot;&gt;维基百科&lt;/a&gt;中的定义&lt;/h4&gt;

&lt;p&gt;维基百科作为全世界的权威知识库，其定义的公允性能够得到保证：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Reactive programming is a declarative programming paradigm concerned with &lt;strong&gt;data streams&lt;/strong&gt; and the &lt;strong&gt;propagation of change&lt;/strong&gt;. With this paradigm it is possible to express static (e.g. arrays) or dynamic (e.g. event emitters) data streams with ease, and also communicate that an inferred dependency within the associated execution model exists, which facilitates the automatic propagation of the changed data flow.&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;参考地址：https://en.wikipedia.org/wiki/Reactive_programming&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;维基百科认为 Reactive programming 是一种声明式的编程范式，其核心要素是&lt;strong&gt;数据流（data streams ）&lt;/strong&gt;与&lt;strong&gt;其传播变化（ propagation of change）&lt;/strong&gt;，前者是关于数据结构的描述，包括静态的数组（arrays）和动态的事件发射器（event emitters）。由此描述，在笔者脑海中浮现出以下技术视图：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;数据流：Java 8 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;传播变化：Java &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Observable&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Observer&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;事件/监听：Java &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EventObject&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EventListener&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这些技术能够很好地满足维基百科对于 Reactive 的定义，那么， Reactive 框架和规范的存在意义又在何方？或许以上定义过于抽象，还无法诠释 Reactive 的全貌。于是乎，笔者想到了去 Spring 官方找寻答案，正如所愿，在 Spring Framework 5 官方参考文档中找到其中定义。&lt;/p&gt;

&lt;h4 id=&quot;spring-5-中的定义&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-why-reactive&quot;&gt;Spring&lt;/a&gt; 5 中的定义&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;p&gt;The term “reactive” refers to programming models that are built around &lt;strong&gt;reacting to change&lt;/strong&gt; — network component reacting to I/O events, UI controller reacting to mouse events, etc. In that sense &lt;strong&gt;non-blocking&lt;/strong&gt; is reactive because instead of being blocked we are now in the mode of reacting to notifications as operations complete or data becomes available.&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;参考地址：https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-why-reactive&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;相对于维基百科的定义，Spring 5 WebFlux 章节同样也提到了变化响应（reacting to change ） ，并且还说明非阻塞（non-blocking）就是 Reactive。同时，其定义的侧重点在响应通知方面，包括操作完成（operations complete）和数据可用（data becomes available）。Spring WebFlux 作为 Reactive Web 框架，天然支持非阻塞，不过早在 Servlet 3.1 规范时代皆以实现以上需求，其中包括 Servlet 3.1 非阻塞 API &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReadListener&lt;/code&gt; 和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WriteListener&lt;/code&gt;，以及 Servlet 3.0 所提供的异步上下文 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsyncContext&lt;/code&gt; 和事件监听 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AsyncListener&lt;/code&gt;。这些 Servlet 特性正是为 Spring WebFlux 提供适配的以及，所以 Spring WebFlux 能完全兼容 Servlet 3.1 容器。笔者不禁要怀疑，难道 Reactive 仅是新包装的概念吗？或许就此下结论还为时尚早，不妨在了解一下 ReactiveX 的定义。&lt;/p&gt;

&lt;h4 id=&quot;reactivex-中的定义&quot;&gt;&lt;a href=&quot;http://reactivex.io/intro.html&quot;&gt;ReactiveX&lt;/a&gt; 中的定义&lt;/h4&gt;

&lt;p&gt;广泛使用的 RxJava 作为 ReactiveX 的 Java 实现，对于 Reactive 的定义，ReactiveX 具备相当的权威性：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ReactiveX extends the observer pattern to support sequences of data and/or events and adds operators that allow you to compose sequences together declaratively while abstracting away concerns about things like low-level threading, synchronization, thread-safety, concurrent data structures, and non-blocking I/O.&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;参考地址：http://reactivex.io/intro.html&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;不过，ReactiveX 并没有直接给 Reactive 下定义，而是通过技术实现手段说明如何实现 Reactive。ReactiveX 作为观察者模式的扩展，通过操作符（Opeators）对数据/事件序列（Sequences of data and/or events )进行操作，并且屏蔽并发细节（abstracting away…），如线程 API（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Exectuor&lt;/code&gt; 、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Runnable&lt;/code&gt;）、同步、线程安全、并发数据结构以及非阻塞 I/O。该定义的侧重点主要关注于实现，包括设计模式、数据结构、数据操作以及并发模型。除设计模式之外，Java 8 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt; API 具备不少的操作符，包括迭代操作 for-each、map/reduce 以及集合操作 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Collector&lt;/code&gt;等，同时，通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parallel()&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sequential()&lt;/code&gt; 方法实现并行和串行操作间的切换，同样屏蔽并发的细节。至于数据结构，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt; 和数据流或集合序列可以画上等号。唯独在设计模式上，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt; 是迭代器（Iterator）模式实现，而 ReactiveX 则属于观察者（Observer）模式的实现。 对此，Reactor 做了进一步地解释。&lt;/p&gt;

&lt;h4 id=&quot;reactor-中的定义&quot;&gt;&lt;a href=&quot;http://projectreactor.io/docs/core/release/reference/#intro-reactive&quot;&gt;Reactor&lt;/a&gt; 中的定义&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;p&gt;The reactive programming paradigm is often presented in object-oriented languages as an extension of the Observer design pattern. One can also compare the main reactive streams pattern with the familiar Iterator design pattern, as there is a duality to the Iterable-Iterator pair in all of these libraries. One major difference is that, while an Iterator is pull-based, reactive streams are push-based.&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;&lt;a href=&quot;http://projectreactor.io/docs/core/release/reference/&quot;&gt;http&lt;/a&gt;&lt;a href=&quot;http://projectreactor.io/docs/core/release/reference/&quot;&gt;://projectreactor.io/docs/core/release/reference/#&lt;/a&gt;&lt;a href=&quot;http://projectreactor.io/docs/core/release/reference/&quot;&gt;intro-reactive&lt;/a&gt;&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;同样地，Reactor 也提到了观察者模式（Observer pattern ）和迭代器模式（Iterator pattern）。不过它将 Reactive 定义为响应流模式（Reactive streams pattern ），并解释了该模式和迭代器模式在数据读取上的差异，即前者属于推模式（push-based），后者属于拉模式（pull-based）。难道就因为这因素，就要使用 Reactive 吗？这或许有些牵强。个人认为，以上组织均没有坦诚或者简单地向用户表达，都采用一种模糊的描述，多少难免让人觉得故弄玄虚。幸运地是，我从 ReactiveX 官方找到一位前端牛人 &lt;a href=&quot;https://gist.github.com/staltz&quot;&gt;André Staltz&lt;/a&gt;，他在学习 Reactive 过程中与笔者一样，吃了不少的苦头，在他博文&lt;a href=&quot;https://gist.github.com/staltz/868e7e9bc2a7b8c1f754&quot;&gt;《The introduction to Reactive Programming you’ve been missing》&lt;/a&gt;中，他给出了中肯的解释。&lt;/p&gt;

&lt;h4 id=&quot;andré-staltz-给出的定义&quot;&gt;&lt;a href=&quot;https://gist.github.com/staltz&quot;&gt;André Staltz&lt;/a&gt; 给出的定义&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://gist.github.com/staltz/868e7e9bc2a7b8c1f754#reactive-programming-is-programming-with-asynchronous-data-streams&quot;&gt;Reactive programming is programming with &lt;strong&gt;asynchronous data streams&lt;/strong&gt;.&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;In a way, &lt;strong&gt;this isn’t anything new&lt;/strong&gt;. Event buses or your typical click events are really an asynchronous event stream, on which you can observe and do some side effects. Reactive is that &lt;strong&gt;idea on steroids&lt;/strong&gt;. You are able to create data streams of anything, not just from click and hover events. Streams are cheap and ubiquitous, anything can be a stream: variables, user inputs, properties, caches, data structures, etc.&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;&lt;a href=&quot;https://gist.github.com/staltz/868e7e9bc2a7b8c1f754#what-is-reactive-programming&quot;&gt;“What is Reactive Programming?”&lt;/a&gt;&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;他在文章指出，Reactive Programming 并不是新东西，而是司空见惯的混合物，比如事件总监、鼠标点击事件等。同时，文中也提到异步（asynchronous ）以及数据流（data streams）等关键字。如果说因为 Java 8 Stream  是迭代器模式的缘故，它不属于Reactive Programming 范式的话，那么，Java GUI 事件/监听则就是 Reactive。那么，Java 开发人员学习 RxJava、Reactor、或者 Java 9 Flow API 的必要性又在哪里呢？因此，非常有必要深入探讨 Reactive Programming 的使用场景。&lt;/p&gt;

&lt;h3 id=&quot;reactive-programming-使用场景&quot;&gt;Reactive Programming 使用场景&lt;/h3&gt;

&lt;p&gt;正如同 Reactive Programming 的定义那样，各个组织各执一词，下面仍采用多方引证的方式，寻求 Reactive Programming 使用场景的“最大公约数”。&lt;/p&gt;

&lt;h4 id=&quot;reactive-streams-jvm-认为的使用场景&quot;&gt;&lt;a href=&quot;https://github.com/reactive-streams/reactive-streams-jvm&quot;&gt;Reactive Streams JVM&lt;/a&gt; 认为的使用场景&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;p&gt;The main goal of Reactive Streams is to govern the exchange of stream data across an asynchronous boundary.&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;https://github.com/reactive-streams/reactive-streams-jvm&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/reactive-streams/reactive-streams-jvm&quot;&gt;Reactive Streams JVM&lt;/a&gt; 认为 Reactive Streams 用于在异步边界（asynchronous boundary）管理流式数据交换（ govern the exchange of stream data）。异步说明其并发模型，流式数据则体现数据结构，管理则强调它们的它们之间的协调。&lt;/p&gt;

&lt;h4 id=&quot;spring-5-认为的使用场景&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring/docs/5.0.7.RELEASE/spring-framework-reference/web-reactive.html#webflux-performance&quot;&gt;Spring 5&lt;/a&gt; 认为的使用场景&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;p&gt;Reactive and non-blocking generally do not make applications run faster. They can, in some cases, for example if using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebClient&lt;/code&gt; to execute remote calls in parallel. On the whole it requires more work to do things the non-blocking way and that can increase slightly the required processing time.&lt;/p&gt;

  &lt;p&gt;The key expected benefit of reactive and non-blocking is the ability to scale with a small, fixed number of threads and less memory. That makes applications more resilient under load because they scale in a more predictable way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Spring 认为 Reactive 和非阻塞通常并非让应用运行更快速（generally do not make applications run faster），甚至会增加少量的处理时间，因此，它的使用场景则利用较少的资源，提升应用的伸缩性（scale with a small, fixed number of threads and less memory）。&lt;/p&gt;

&lt;h4 id=&quot;reactivex-认为的使用场景&quot;&gt;&lt;a href=&quot;http://reactivex.io/intro.html&quot;&gt;ReactiveX&lt;/a&gt; 认为的使用场景&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;p&gt;The ReactiveX Observable model allows you to treat streams of asynchronous events with the same sort of simple, composable operations that you use for collections of data items like arrays. It frees you from tangled webs of callbacks, and thereby makes your code more readable and less prone to bugs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ReactiveX 所描述的使用场景与 Spring 的不同，它没有从性能入手，而是代码可读性和减少 Bugs 的角度出发，解释了 Reactive Programming 的价值。同时，强调其框架的核心特性：异步（asynchronous）、同顺序（same sort）和组合操作（composable operations）。它也间接地说明了，Java 8 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt; 在组合操作的限制，以及操作符的不足。&lt;/p&gt;

&lt;h4 id=&quot;reactor-认为的使用场景&quot;&gt;&lt;a href=&quot;http://projectreactor.io/docs/core/release/reference/#intro-reactive&quot;&gt;Reactor&lt;/a&gt; 认为的使用场景&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;p&gt;Composability and readability&lt;/p&gt;

  &lt;p&gt;Data as a flow manipulated with a rich vocabulary of operators&lt;/p&gt;

  &lt;p&gt;Nothing happens until you subscribe&lt;/p&gt;

  &lt;p&gt;Backpressure or the ability for the consumer to signal the producer that the rate of emission is too high&lt;/p&gt;

  &lt;p&gt;High level but high value abstraction that is concurrency-agnostic&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Reactor 同样强调结构性和可读性（Composability and readability）和高层次并发抽象（High level abstraction），并明确地表示它提供丰富的数据操作符（ rich vocabulary of operators）弥补 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt; API 的短板，还支持背压（Backpressure）操作，提供数据生产者和消费者的消息机制，协调它们之间的产销失衡的情况。同时，Reactor 采用订阅式数据消费（Nothing happens until you subscribe）的机制，实现 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream&lt;/code&gt; 所不具备的数据推送机制。&lt;/p&gt;

&lt;p&gt;至此，讨论接近尾声，最后的部分将 Reactive Programming 内容加以总结。&lt;/p&gt;

&lt;h2 id=&quot;总结-reactive-programming&quot;&gt;总结 Reactive Programming&lt;/h2&gt;

&lt;p&gt;Reactive Programming 作为观察者模式（&lt;a href=&quot;https://en.wikipedia.org/wiki/Observer_pattern&quot;&gt;Observer&lt;/a&gt;） 的延伸，不同于传统的命令编程方式（ &lt;a href=&quot;https://en.wikipedia.org/wiki/Imperative_programming&quot;&gt;Imperative programming&lt;/a&gt;）同步拉取数据的方式，如迭代器模式（&lt;a href=&quot;https://en.wikipedia.org/wiki/Iterator_pattern&quot;&gt;Iterator&lt;/a&gt;） 。而是采用数据发布者同步或异步地推送到数据流（Data Streams）的方案。当该数据流（Data Steams）订阅者监听到传播变化时，立即作出响应动作。在实现层面上，Reactive Programming 可结合函数式编程简化面向对象语言语法的臃肿性，屏蔽并发实现的复杂细节，提供数据流的有序操作，从而达到提升代码的可读性，以及减少 Bugs 出现的目的。同时，Reactive Programming  结合背压（Backpressure）的技术解决发布端生成数据的速率高于订阅端消费的问题。&lt;/p&gt;

&lt;h2 id=&quot;后记&quot;&gt;后记&lt;/h2&gt;

&lt;p&gt;2005年，李敖大师曾在上海复旦大学做过一次演讲，他在讲到“放弃自由主义，注重务实”的部分时，引述一段故事：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;美国有一个报纸，办报的人叫ABBOTT，他晚年的时候写回忆录，他爸爸是一个写儿童书的作家，他爸爸临死前告诉他说，感觉到人间所有的教会的争执90％都是名词之争。这个小ABBOTT老了以后，他回忆这段话，他说我回忆我爸爸告诉我所有人间宗教的争执90％都是名词之争，他说我发现我爸爸数学不好，原来最后那10％也是名词之争。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;实际上，名词之争的战场不限于宗教教会，技术领域不也是如此吗？Reactive Programming 实际是一种技术，却被各自表达。有些定义含糊不清，有些定义则空洞无实，还有一些则是夸大其词，只有少数保持客观中立。不免让然唏嘘技术领域的非理性营销。当了解了 Reactive Programming 的本质后，您的热情还能像如初般地高涨吗？&lt;/p&gt;

</description>
        <pubDate>Wed, 25 Jul 2018 00:00:00 +0000</pubDate>
        <link>https://weibo.com/mercyblitz/2018/07/25/Reactive-Programming-%E4%B8%80%E7%A7%8D%E6%8A%80%E6%9C%AF-%E5%90%84%E8%87%AA%E8%A1%A8%E8%BF%B0/</link>
        <guid isPermaLink="true">https://weibo.com/mercyblitz/2018/07/25/Reactive-Programming-%E4%B8%80%E7%A7%8D%E6%8A%80%E6%9C%AF-%E5%90%84%E8%87%AA%E8%A1%A8%E8%BF%B0/</guid>
        
        
      </item>
    
      <item>
        <title>Dubbo cloud native 实践与思考</title>
        <description>&lt;h1 id=&quot;dubbo-cloud-native-实践与思考&quot;&gt;Dubbo Cloud Native 实践与思考&lt;/h1&gt;

&lt;!-- TOC --&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#dubbo-cloud-native-%E5%AE%9E%E8%B7%B5%E4%B8%8E%E6%80%9D%E8%80%83&quot;&gt;Dubbo Cloud Native 实践与思考&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#%E5%88%86%E4%BA%AB%E7%AE%80%E4%BB%8B&quot;&gt;分享简介&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#%E8%87%AA%E6%88%91%E4%BB%8B%E7%BB%8D&quot;&gt;自我介绍&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#%E4%B8%BB%E8%A6%81%E8%AE%AE%E7%A8%8B&quot;&gt;主要议程&lt;/a&gt;
        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#cloud-native-%E5%9F%BA%E7%A1%80%E8%AE%BE%E6%96%BD&quot;&gt;Cloud Native 基础设施&lt;/a&gt;
            &lt;ul&gt;
              &lt;li&gt;&lt;a href=&quot;#%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0service-discovery&quot;&gt;服务发现（Service Discovery ）&lt;/a&gt;
                &lt;ul&gt;
                  &lt;li&gt;&lt;a href=&quot;#%E5%A6%82%E4%BD%95%E9%80%89%E6%8B%A9&quot;&gt;如何选择&lt;/a&gt;
                    &lt;ul&gt;
                      &lt;li&gt;&lt;a href=&quot;#eureka&quot;&gt;Eureka&lt;/a&gt;&lt;/li&gt;
                      &lt;li&gt;&lt;a href=&quot;#consul&quot;&gt;Consul&lt;/a&gt;&lt;/li&gt;
                      &lt;li&gt;&lt;a href=&quot;#zookeeper&quot;&gt;Zookeeper&lt;/a&gt;&lt;/li&gt;
                    &lt;/ul&gt;
                  &lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1&quot;&gt;负载均衡&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#%E6%9C%8D%E5%8A%A1%E7%BD%91%E5%85%B3&quot;&gt;服务网关&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#%E5%88%86%E5%B8%83%E5%BC%8F%E9%85%8D%E7%BD%AE&quot;&gt;分布式配置&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD&quot;&gt;服务熔断&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#%E9%93%BE%E8%B7%AF%E8%B7%9F%E8%B8%AA&quot;&gt;链路跟踪&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#%E6%9C%8D%E5%8A%A1%E7%9B%91%E6%8E%A7&quot;&gt;服务监控&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#cloud-native-%E6%9E%B6%E6%9E%84%E9%80%89%E5%9E%8B&quot;&gt;Cloud Native 架构选型&lt;/a&gt;
            &lt;ul&gt;
              &lt;li&gt;&lt;a href=&quot;#cncf-%E6%9E%B6%E6%9E%84%E4%BD%93%E7%B3%BB&quot;&gt;CNCF 架构体系&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#spring-cloud-%E6%9E%B6%E6%9E%84%E4%BD%93%E7%B3%BB&quot;&gt;Spring Cloud 架构体系&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#dubbo-%E6%9E%B6%E6%9E%84%E4%BD%93%E7%B3%BB&quot;&gt;Dubbo 架构体系&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#dubbo-cloud-native-%E5%87%86%E5%A4%87&quot;&gt;Dubbo Cloud Native 准备&lt;/a&gt;
            &lt;ul&gt;
              &lt;li&gt;&lt;a href=&quot;#dubbo-%E6%B3%A8%E8%A7%A3%E9%A9%B1%E5%8A%A8annotation-driven&quot;&gt;Dubbo 注解驱动（Annotation-Driven）&lt;/a&gt;
                &lt;ul&gt;
                  &lt;li&gt;&lt;a href=&quot;#dubbocomponentscan-%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%A4%BA%E4%BE%8B&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@DubboComponentScan&lt;/code&gt; 服务端示例&lt;/a&gt;&lt;/li&gt;
                  &lt;li&gt;&lt;a href=&quot;#dubbocomponentscan-%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%A4%BA%E4%BE%8B&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@DubboComponentScan&lt;/code&gt; 客户端示例&lt;/a&gt;&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AEexternalized-configuration&quot;&gt;Dubbo 外部化配置（Externalized Configuration）&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#%E7%8E%B0%E5%9C%BA%E6%BC%94%E7%A4%BA%E7%8E%AF%E8%8A%82&quot;&gt;现场演示环节&lt;/a&gt;
            &lt;ul&gt;
              &lt;li&gt;&lt;a href=&quot;#dubbo-%E6%95%B4%E5%90%88-hystrix-%E7%A4%BA%E4%BE%8B&quot;&gt;Dubbo 整合 Hystrix 示例&lt;/a&gt;
                &lt;ul&gt;
                  &lt;li&gt;&lt;a href=&quot;#dubbo-%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%AE%9E%E7%8E%B0&quot;&gt;Dubbo 客户端实现&lt;/a&gt;
                    &lt;ul&gt;
                      &lt;li&gt;&lt;a href=&quot;#dubbo-%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%AE%9E%E7%8E%B0&quot;&gt;Dubbo 服务端实现&lt;/a&gt;&lt;/li&gt;
                    &lt;/ul&gt;
                  &lt;/li&gt;
                  &lt;li&gt;&lt;a href=&quot;#%E6%B5%8B%E8%AF%95%E5%AE%A2%E6%88%B7%E7%AB%AF-rest-%E6%9C%8D%E5%8A%A1&quot;&gt;测试客户端 REST 服务&lt;/a&gt;&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#%E5%8F%82%E8%80%83%E8%B5%84%E6%BA%90&quot;&gt;参考资源&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;!-- /TOC --&gt;

&lt;h2 id=&quot;分享简介&quot;&gt;分享简介&lt;/h2&gt;

&lt;p&gt;Cloud Native 应用架构随着云技术的发展受到业界特别重视和关注，尤其是 CNCF（Cloud Native Computing Foundation）项目蓬勃发展之际。Dubbo 作为服务治理的标志性项目，自然紧跟业界的潮流，拥抱技术的变化。本次分享的议题包括介绍 Apache 孵化项目Dubbo Spring Boot Project 以及汇报 Dubbo 与 Cloud Native 整合过程中的一些实践与思考，如适配  Spring Cloud 、服务发现、服务网关、服务跟踪以及监控等。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;注：为了读者的阅读方便和习惯，本文字稿将在演讲内容的基础上做出适当的调整。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;自我介绍&quot;&gt;自我介绍&lt;/h2&gt;

&lt;p&gt;马昕曦（小马哥），阿里巴巴中间件技术专家，十余年 Java EE 从业经验，Dubbo 维护者、架构师以及微服务布道师。目前主要负责阿里巴巴集团微服务技术实施、架构衍进、基础设施构建等。重点关注云计算、微服务以及软件架构等领域。通过 SUN Java（SCJP、SCWCD、SCBCD）以及 Oracle OCA 等的认证。&lt;/p&gt;

&lt;h2 id=&quot;主要议程&quot;&gt;主要议程&lt;/h2&gt;

&lt;p&gt;今天我非常荣幸地与大家一起讨论关于 Dubbo Cloud Native 相关议题，本次议题紧扣“实践与思考“两个关键字，主要的议程包括：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Cloud Native 基础设施&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cloud Native 架构选型&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dubbo Cloud Native 准备&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;cloud-native-基础设施&quot;&gt;Cloud Native 基础设施&lt;/h3&gt;

&lt;p&gt;关于 Cloud Native 的定义，不同的云平台可能给出的内容存在差异。此处，我向大家介绍目前最热门的 CNCF 的定义：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;”&lt;a href=&quot;https://github.com/cncf/toc/blob/master/DEFINITION.md&quot;&gt;CNCF Cloud Native Definition v1.0&lt;/a&gt;“ 中的描述：&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;Cloud native technologies empower organizations to build and run scalable applications in modern, dynamic environments such as public, private, and hybrid clouds. Containers, service meshes, microservices, immutable infrastructure, and declarative APIs exemplify this approach.&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;相对于其他学术流派，CNCF 的 Cloud Native 定义更为具体，偏向于软件技术。这一点我们从文中的一些关键字能够明显地体会到，如关键字 “Containers（容器）”、”service meshes”、”microservices（微服务）“等。通常，开发人员较为关注的 Cloud Native 基础设施为：“服务发现”、“负载均衡”、“服务网关”、“分布式配置”、“服务熔断”以及“跟踪监控”，如图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/幻灯片05.jpg&quot; alt=&quot;幻灯片05&quot; /&gt;&lt;/p&gt;

&lt;p&gt;由于 PPT 格式的限制，此处我将“链路跟踪”与“服务监控” 并陈为“跟踪监控”。接下来，我们进入“服务发现”的讨论。&lt;/p&gt;

&lt;h4 id=&quot;服务发现service-discovery-&quot;&gt;服务发现（Service Discovery ）&lt;/h4&gt;

&lt;p&gt;随着微服务架构（MSA）受到不同规模企业的青睐，服务治理的实施逐渐被提上基础设施改造的议程。尽管这些概念在 SOA 时代已经提出，然而引起业界广泛关注应归功于微服务。服务发现（Service Discovery ）作为服务治理的核心特性，通常也将服务注册（Service Registration）一并讨论。无论是服务发现，还是服务注册，在具体落地实施时，它们必须面对技术选型的问题。在座的各位，包括我，大多数是 Java 程序员，自然关心 Java 的技术方案。目前，Java 社区最为津津乐道的方案莫过于 Spring Cloud，搭配 Netflix OSS 组件 Eureka，帮助 Spring Boot 应用快速搭建服务发现体系。其中，Eureka Server 作为注册中心服务器，Spring Boot 应用整合 Eureka Client 向 Eureka Server 注册。实际上，Spring Cloud 除了整合 Netflix Eureka 作为服务发现之外，还提供了 Apache Zookeeper 和 HachiCorp Consul 的实现，所以这三种方案出现在当前页面：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/幻灯片06.jpg&quot; alt=&quot;幻灯片06&quot; /&gt;&lt;/p&gt;

&lt;p&gt;其中还包括 Redis 和 Apache Curator，前者是 Dubbo 的服务发现实现方案之一，然而小马哥并不建议使用 Redis 作为注册中心，还是保持它缓存中间件的单纯性较好。而 Curator 作为 Zookeeper Java 客户端类库，它不但可用在 Dubbo，而且其扩展项目 Curator Service Discovery 也是 Spring Cloud 整合 Zookeeper 作为服务发现的关键基础设施。或许大家思考以上方案应该如何选型的问题。&lt;/p&gt;

&lt;h5 id=&quot;如何选择&quot;&gt;如何选择&lt;/h5&gt;

&lt;h6 id=&quot;eureka&quot;&gt;Eureka&lt;/h6&gt;

&lt;p&gt;当服务发现选型时，Netflix Eureka 或许是在开发人员脑海中复现的首选方案。然而 Eureka 在阿里大规模实践时，它的表现并不理想，当 Eureka 客户端服务实例数量达到一定时，Eureka Server 时常会出现服务不可用的情况，主要的问题集中在更新（Update）机制、复制（Replication）机制以及内存型存储。由于时间的关系，此处我不加详细说明，部分答案在 Eureka Wiki &lt;a href=&quot;https://github.com/Netflix/eureka/wiki/Eureka-2.0-Motivations&quot;&gt;Eureka 2.0 Motivations&lt;/a&gt; 中也有描述：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://github.com/Netflix/eureka/wiki/Eureka-2.0-Motivations#why-eureka-20&quot;&gt;Why Eureka 2.0?&lt;/a&gt;&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Only support homogenous client views&lt;/li&gt;
    &lt;li&gt;Only supports scheduled updates&lt;/li&gt;
    &lt;li&gt;Replication algorithm limits scalability&lt;/li&gt;
  &lt;/ul&gt;

  &lt;blockquote&gt;
    &lt;p&gt;注：以上具体内容在分享现场并没有具体提及，此处特意为读者补充。&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;以上问题 Netflix 早在 2015 年已意识到，然而 Eureka 2.0 的发布遥遥无期。后来，我托朋友联系上了 Netflix 的工程师，咨询他们关于 Eureka 1 在自身生产环境的使用情况。他们的回复是部分场景在使用。这样的答复值得玩味，再细问其覆盖比重，对方三缄其口。这不得不让我对 Eureka 的成熟度产生了质疑，所以我不建议大家在数以千计的应用实例场景中使用。&lt;/p&gt;

&lt;h6 id=&quot;consul&quot;&gt;Consul&lt;/h6&gt;

&lt;p&gt;Consul 同样作为 Spring Cloud 服务中心，基于 GO 语言开发，其数据一致性采用 Raft 算法，低内存，集群支持。曾一度成为我理想的替换 Eureka 的方案，不过本人并不具备 Consul 的大规模运用，为此还特意请教永辉云创的架构师翟永超（《Spring Cloud 微服务实战》的作者）。他告知 Consul 表现不错，并在跨 DC（数据中心）方面也比较稳定：&lt;img src=&quot;/img/assets/image-20180627210416358.png&quot; alt=&quot;image-20180627210416358&quot; /&gt;&lt;/p&gt;

&lt;p&gt;他的答复让我增强了 Consul 的信心，稍显遗憾的是其 Consul 应用节点略少。后来，我听说 B 站的哥们自研服务发现中间件 &lt;strong&gt;&lt;a href=&quot;https://github.com/Bilibili/discovery/&quot;&gt;discovery&lt;/a&gt;&lt;/strong&gt;，他们应该也对 Consul 做过调研和评估，他们的看法是：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/image-20180627210529749.png&quot; alt=&quot;image-20180627210529749&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Github 开源地址：https://github.com/Bilibili/discovery/&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/Bilibili/discovery/&quot;&gt;discovery&lt;/a&gt;&lt;/strong&gt; 在 B 站 K8S 上的使用情况：&lt;/p&gt;

  &lt;p&gt;&lt;img src=&quot;/img/assets/image-20180627210509857.png&quot; alt=&quot;image-20180627210509857&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;综合两家公司的评估，尽管没有经过本人实际操作，并且两者没有提供具体的数据指标，然而在一定程度上说明 Consul 作为注册中心的实例节点规模大概在 2k 以内。换言之，它比较适合中小型企业。&lt;/p&gt;

&lt;h6 id=&quot;zookeeper&quot;&gt;Zookeeper&lt;/h6&gt;

&lt;p&gt;Zookeeper 即可是 Spring Cloud 注册中心，又能作为 Dubbo 注册中心，与 Eureka 不同，它属于 CP 分布式策略，而后者属于 AP。两者的共同点在于均属于内存型注册中心，在大规模集群场景，也会遇到 Eureka 类似的问题。不过从运维的角度，相较于 Eureka 而言，熟悉 Zookeeper 运维朋友更多。在生态性方面，Zookeeper 周边的生态更丰富，如 Zookeeper C API，尽管 Eureka 提供了语言无关性的 REST 接口。同时，Zookeeper 还从当配置服务器的角色，降低了学习的成本。综上结论，我推荐使用 Zookeeper 作为服务发现基础设施，无论您选择 Dubbo 方案，还是使用 Spring Cloud。尽管它在大规模集群时也出现 Zookeeper 间歇性卡顿等问题。&lt;/p&gt;

&lt;h4 id=&quot;负载均衡&quot;&gt;负载均衡&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/幻灯片07.jpg&quot; alt=&quot;幻灯片07&quot; /&gt;&lt;/p&gt;

&lt;p&gt;负载均衡是第二个重要 Cloud Native 基础设施，熟悉 Spring Cloud 的朋友一定对右侧的蝴蝶结有印象，它就是 Netflix OSS 负载均衡组件 Ribbon，框架层面提供了多种负载均衡规则，如：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;随机&lt;/strong&gt; - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RandomRule&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;轮循&lt;/strong&gt; - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RoundRobinRule&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;权重响应时间&lt;/strong&gt; - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WeightedResponseTimeRule&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WeightedResponseTimeRule&lt;/code&gt; 之外，其他的 Ribbon 负载均衡实现均没有提供权重因子，而权重因子对于蓝绿发布、服务预热等方面的帮助是至关重要的。因此，权重因子在 Dubbo “&lt;strong&gt;随机&lt;/strong&gt;“、”&lt;strong&gt;轮询&lt;/strong&gt;“ 以及 ”&lt;strong&gt;最少活跃调用数&lt;/strong&gt;“ 负载均衡算法中均体现。&lt;/p&gt;

&lt;p&gt;以上讨论的两种框架均属于 Java 实现，而中间的 Kong 则是更为通用的实现，通常它作为 API 服务网关，后面我们将继续讨论。可简单地认为它是 Nginx + Lua 的扩展，负载均衡自然成为不可或缺的特性。其默认的负载均衡算法为具备权重的轮询（weighted-round-robin），同时一致性 Hash 算法作为可选方案。&lt;/p&gt;

&lt;h4 id=&quot;服务网关&quot;&gt;服务网关&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/幻灯片08.jpg&quot; alt=&quot;幻灯片08&quot; /&gt;&lt;/p&gt;

&lt;p&gt;谈及服务网关，Java 工程师最容易想到的是 Spring Cloud Zuul。Zuul 是 Netflix 基于 Servlet API 开发的 Web 服务代理组件，在 Spring Cloud 使用场景中，它与 Eureka  和 Ribbon 整合，打造具备服务动态更新和负载均衡能力的服务网关。&lt;/p&gt;

&lt;p&gt;最近，随着 Spring Cloud Finchley 的发布，Spring Cloud Zuul 的替代方案 Spring Cloud Gateway 孕育而生，不过官方的描述还是比较谦虚谨慎，并没有一刀切地引导开发人员从 Zuul 迁移到 Gateway 上来：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;API Gateway built on top of the Spring Ecosystem, including: Spring 5, Spring Boot 2 and Project Reactor. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;两者不同点在于，Zuul 运行在 Servlet 容器中，而 Gateway 并不像 Spring WebFlux 能够兼容 Servlet 3.1 运行时，而是必须依赖 Netty 的运行时，以及整合 Reactive 框架 Reactor，实现异步非阻塞网关。由于近期对于 Spring 5  WebFlux 能够大幅提升应用性能的观点甚嚣尘上，实际上，没有任何直接性能基准测试证明 WebFlux 能够加快程序执行速度，或许大家认为我的观点与主流格格不入，可是我要告诉大家的是，这个问题我在同事间验证过很多次，大多数情况，Reactive 并不没有提升性能。就连 Spring 官方也承认这个观点：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://docs.spring.io/spring/docs/5.0.7.RELEASE/spring-framework-reference/web-reactive.html#webflux-performance&quot;&gt;1.1.7. Performance vs scale&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Performance has many characteristics and meanings. &lt;strong&gt;Reactive and non-blocking generally do not make applications run faster&lt;/strong&gt;. They can, in some cases, for example if using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebClient&lt;/code&gt; to execute remote calls in parallel. &lt;strong&gt;On the whole it requires more work to do things the non-blocking way and that can increase slightly the required processing time&lt;/strong&gt;.&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;资源地址：https://docs.spring.io/spring/docs/5.0.7.RELEASE/spring-framework-reference/web-reactive.html#webflux-performance&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;同时，这里提供一篇 &lt;a href=&quot;https://blog.ippon.tech/spring-5-webflux-performance-tests/&quot;&gt;Spring 5 WebFlux: Performance tests&lt;/a&gt; 的文章，在结尾部分给出了结论，作者坦言在速度上没有明显的提升，甚至从结果来看，速度稍微更糟糕：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;No improvement in speed was observed with our reactive apps (the Gatling results are even slightly worse).&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;以上测试工程和结论是由开源项目 JHipster 的工程师给出，具备一定的客观性和可信度。&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;资源地址：https://blog.ippon.tech/spring-5-webflux-performance-tests/&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;换言之，基于 Reactor 开发的 Gateway 在性能可能并没有明显的提升。因此，Zuul 和 Gateway 的性能对比则演变为 Servlet 容器和 Netty Web 容器的比较，感兴趣的朋友可以去网上寻找一些比较数据，两者的性能在伯仲间。&lt;/p&gt;

&lt;p&gt;当然，我和在座的各位一样，对 Java 的实现方案自然是情有独钟。然而我想说的是，身为 Java 工程师，&lt;strong&gt;眼中难免有 Java，但是眼中不要只有 Java&lt;/strong&gt;。Nginx 作为当年著名 “C10K” 问题的解决方案，无论从连接数量，还是资源消耗方面均优于 Java 实现。作为技术人，应该具有更为宽广的胸怀，接纳非我族类的气魄，该放手的时候就放手。Nginx 作为服务网关不失为一种好的方案，然而它的动态性略为不足，需要结合 Lua 脚本辅助完成，因此，OpenResty 和 Kong 这类方案脱颖而出。如果就 HTTP API 网关而言，个人认为 Kong 的方案更佳，因为它提供完整的解决方案，包括前面讨论的负载均衡（权重）、服务熔断以及服务发现等特性。类似的特性在 CNCF 项目 Envoy 也有体现，它是另一种高性能代理的方案，提供服务发现、健康和负载均衡。在协议上，天然支持 HTTP 和 HTTP/2，而通讯协议支持 gRPC，建议大家予以高度关注。&lt;/p&gt;

&lt;p&gt;值得一提的是，HTTP API 网关通常需要支持 sidecar，换言之，支撑网关服务的基础设施必须提供服务发现的能力，就功能性而言，Zuul 和 Gateway 自身并不具备这样的特性，需要搭配 Eureka 这样组件，它们更像服务路由器的角色。&lt;/p&gt;

&lt;h4 id=&quot;分布式配置&quot;&gt;分布式配置&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/幻灯片09.jpg&quot; alt=&quot;幻灯片09&quot; /&gt;&lt;/p&gt;

&lt;p&gt;左边和中间的四种技术均为 Spring Cloud 分布式配置的底层存储，其中 Git 为版本式配置，而 JDBC 是从 Spring Cloud Edgware 版本开始支持，提供更为通用和动态的配置源。这里我们又见到 Zookeeper 的声影，从简化运维的角度，可以利用 Zookeeper 即承担服务发现，也作为分布式配置的基础设施。而最右边的 etcd 是最近非常火的 Kubernetes 分布式配置的 key-value 存储，提供快速、简单、安全和可高的解决方案。&lt;/p&gt;

&lt;h4 id=&quot;服务熔断&quot;&gt;服务熔断&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/幻灯片10.jpg&quot; alt=&quot;幻灯片10&quot; /&gt;&lt;/p&gt;

&lt;p&gt;服务熔断也非常让开发人员联想到 Spring Cloud Hystrix 技术，不过 Hystrix 并非与 Spring Cloud 强耦合，当然 Dubbo 也能结合 Netflix Hystrix 框架提供服务熔断的能力，后面部分将介绍 Dubbo 与 Hystrix 整合，提升 Dubbo 服务熔断的能力。确切地说，Dubbo 所提供的能力是集群容错，包括 Failover 等模式。 Kong 也天然地支持服务熔断的能力，所以它作为 API 网关的特性是全面的。&lt;/p&gt;

&lt;h4 id=&quot;链路跟踪&quot;&gt;链路跟踪&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/幻灯片11.jpg&quot; alt=&quot;幻灯片11&quot; /&gt;&lt;/p&gt;

&lt;p&gt;以上链路跟踪的基础设施从左至右，分别为 Zipkin、OpenTracing 以及 Jaeger，三者的灵感均来自于 &lt;a href=&quot;https://ai.google/research/pubs/pub36356&quot;&gt;Google 论文 Dapper&lt;/a&gt;。相对而言，Java 程序员可能更为熟悉 Zipkin，因为它是 Spring Cloud Sleuth 首选方案，提供客户端上报以及服务端聚合和 Dashboard 等功能。而 OpenTracing 和 Jaeger 是 CNCF 孵化项目，前者属于开放的标准，提供多语言的适配实现，后者则由 Uber（优步）公司开发并开源的链路跟踪项目，功能上与 Zipkin 类似，不过它基于 GO 语言开发，同时也提供 Java 客户端。&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;OpenTracing 官网：http://opentracing.io/
jaeger 官网：https://www.jaegertracing.io/&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&quot;服务监控&quot;&gt;服务监控&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/幻灯片12.jpg&quot; alt=&quot;幻灯片12&quot; /&gt;&lt;/p&gt;

&lt;p&gt;服务监控与链路跟踪有所区别，主要用于监控应用系统或业务的指标数据，可能是健康阈值，如 CPU 或 内存使用率，也可以是业务指标，如最近一小时的用户登录量。通常采用 Metrics 方式暴露，可使用客户端推送或服务端拉取的方式传输 Metrics 信息到数据中心。通常 Metrics 数据与时间是存在对应关系，因此，基本上采用时序型数据库来存储，如图中的 OpenTSDB。通常，Java 微服务应用会选择 Spring Boot 框架作为基础设施，如我之前设计的监控架构就采用了 Spring Boot + OpenTSDB ，后端存储基于 HBase。当时 Spring Boot Actuator Metrics 仅为简单的 Key Value 形式，自然 OpenTSDB 是理想的选择。随着 Spring Boot 2.0 开始支持 &lt;a href=&quot;https://micrometer.io/&quot;&gt;Micrometer&lt;/a&gt; 之后，使得 Spring Boot 的应用能够整合更多的 Micrometer 适配方案，其中名气较大的就是图中间的 &lt;a href=&quot;https://prometheus.io/&quot;&gt;Prometheus&lt;/a&gt;，它同样也是 CNCF 的孵化项目。&lt;/p&gt;

&lt;p&gt;当然服务监控不只是 Metrics 方式，我所知道国内不少的公司采用了日志收集的方案，并搭配 ELK（Elasticsearch, Logstash, Kibana） 架构，减少运维成本。假设您没有使用该方案，或者仅使用了 Elasticsearch 的话，无论哪种方案，图形化界面的监控是必不可少的，因此我推荐 Grafana，该项目能够支持多种数据源，包括前文提到的 OpenTSDB、Prometheus 以及 ElasticSearch 等。由此，从数据采集、上报、聚合以及展示的特性上，这些基础设施帮助 Cloud Native 应用构建服务监控的闭环。&lt;/p&gt;

&lt;p&gt;本议程介绍了一些 Cloud Native 技术设施，接下里我们继续讨论 Cloud Native 架构选型。&lt;/p&gt;

&lt;h3 id=&quot;cloud-native-架构选型&quot;&gt;Cloud Native 架构选型&lt;/h3&gt;

&lt;h4 id=&quot;cncf-架构体系&quot;&gt;CNCF 架构体系&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/CNCF.png&quot; alt=&quot;CNCF&quot; /&gt;&lt;/p&gt;

&lt;p&gt;CNCF 体系作为目前最热门的架构选型之一，基本上围绕着 Kubernetes 为中心而构建。个人认为，Java 业界和 CNCF 体系并没有达成共识，如服务网关，CNCF 主打 Envoy，而 Java 主要的方案为 Zuul 和 Spring Cloud Gateway。因此，个人建议是密切的关注 CNCF 的发展，不过个别孵化项目可以先行，如 Prometheus 和 Jaeger 等。 至于 CNCF 与 Java 生态的整合和落地，还得有待时日。&lt;/p&gt;

&lt;h4 id=&quot;spring-cloud-架构体系&quot;&gt;Spring Cloud 架构体系&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/Spring-Cloud.png&quot; alt=&quot;Spring Cloud&quot; /&gt;&lt;/p&gt;

&lt;p&gt;实际上，这个图片并非 Spring Cloud 组件架构，而是将其整合在 Pivotal Cloud Foundry (PCF) 架构中。基本上，Spring Cloud 功能组件均有所体现，包括 Eureka、Hystrix、Ribbon 等。不过值得注意的是，Spring Cloud Stream 是一套较为完整和抽象的流式编程框架，屏蔽了底层传输介质（不仅是消息服务），如 Kafka、RabbitMQ 等。除此之外，其他的组件可圈可点，如 Eureka 在大规模运用中的卡顿问题、Ribbon 缺少权重、Zuul 连接数限制和资源消耗、服务调用受限于 Feign REST 协议限制等。如果在小规模场景使用，以上限制或问题不明显，可以说 Spring Cloud 完全能够适任。&lt;/p&gt;

&lt;p&gt;不过，差不多两年前，我曾在不同的公开场合讲过：”Spring Boot 易学难精，Spring Cloud 能用但不成熟“。当时很多人觉得我“离经叛道”，然而这句话并非空穴来风，是我这几年来 Java 微服务架构实施的心得。这两年来，深受 Spring Cloud “折磨”的小伙伴逐渐觉醒，慢慢地开始回到 Dubbo 等技术方案。如 Martin Fowler 在为“微服务”下定义时，提到通讯协议要用轻量级的 REST。假设微服务要做到服务无关的话，那么 Web Services 协议也是可以，尽管它看起来比较重，不过 Web Services 的结构化和强类型，可以省去不少的运行时校验逻辑。在我看来，微服务更大程度应该体现在服务粒度上，诚如 Netflix 前架构师 Adrian Cockcroft 说言：“Fine grain SOA”（微服务就是细粒度的 SOA），就这一点而言，比较容易地和业界达成共识。当我们把 Martin 的话视如圭臬时，我们是否要思考它是否经得起工程检验。这里，我没有兴趣贬低他人，来抬高自己（Dubbo），从而引导让大家放弃 Spring Cloud，而是我们需要给 Spring Cloud 时间，包括未来 Dubbo 也会向 Spring Cloud 靠拢并整合。在阿里的内部，基于 Nacos（马上开源的项目）和 Apache RocketMQ，实现了 Spring Cloud Service Discovery、Config 以及 Stream 等整合和适配，一旦时机成熟，可能会开源与大家共建。&lt;/p&gt;

&lt;p&gt;既然谈到了 Dubbo，下面我们再来讨论 Dubbo 的架构体系。&lt;/p&gt;

&lt;h4 id=&quot;dubbo-架构体系&quot;&gt;Dubbo 架构体系&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/Dubbo.png&quot; alt=&quot;Dubbo.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;编程模型方面，不但支持传统的 Spring XML 配合方式，已经实现注解驱动以及外部化配置，并且全面支持最新的 Spring Boot 2.0，在不久的未来，大家会看到 Dubbo 与 Spring Cloud 的整合，使开发人员无缝地衔接已有的 Spring Cloud 应用。&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;Dubbo Spring Boot 项目地址：https://github.com/apache/incubator-dubbo-spring-boot-project&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;注册中心方面，Dubbo 将整合 Eureka、etcd 以及 Consul 基础设施，深度与业界热门方案整合。&lt;/p&gt;

&lt;p&gt;熔断机制方面，Dubbo 会在近期发布 Hystrix 整合实现，将编程友好性做得最大化。&lt;/p&gt;

&lt;p&gt;通讯协议方面，Dubbo 将会支持 gRPC、Thrift 等热门通讯协议。&lt;/p&gt;

&lt;p&gt;至于序列化协议，自然首先考虑的是 Protobuf，因其高层 gRPC 搭配 HTTP/2 快成或已经成为下一代通讯协议的事实标准，使得任何人无法忽视它们的存在。当然其他协议也会陆续支持。&lt;/p&gt;

&lt;p&gt;其他方面，我这里就不一一介绍，总之，现在 Dubbo 已不再只是一个单一的 PRC 框架，而是要拥抱业界，形成完整的生态体系，与业界形成最大公约数。&lt;/p&gt;

&lt;h3 id=&quot;dubbo-cloud-native-准备&quot;&gt;Dubbo Cloud Native 准备&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/img/assets/幻灯片16.jpg&quot; alt=&quot;幻灯片16&quot; /&gt;&lt;/p&gt;

&lt;p&gt;在 Dubbo 架构体系时，我们曾提到编程模型的变化。从 Dubbo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.5.8&lt;/code&gt; 开始，注解驱动和外部化配置均已得到支持。同时，Dubbo 已经合并 Dubbox 代码，Java JAX-RS 标准得到了支持，目前业界事实的 REST 标准 Spring Web MVC 正在同步开发。Reactive 的支持也在同步进行，小马哥还得友好地提醒一下各位，对于 Reactive 的期望不应该过分的关注性能的提升。&lt;/p&gt;

&lt;h4 id=&quot;dubbo-注解驱动annotation-driven&quot;&gt;Dubbo 注解驱动（Annotation-Driven）&lt;/h4&gt;

&lt;p&gt;在 Dubbo  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.5.7&lt;/code&gt; 之前的版本 ，Dubbo 提供了两个核心注解 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Service&lt;/code&gt; 以及 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Reference&lt;/code&gt;，分别用于Dubbo 服务提供和 Dubbo 服务引用。&lt;/p&gt;

&lt;p&gt;其中，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Service&lt;/code&gt; 作为 XML 元素 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:service&amp;gt;&lt;/code&gt; 的替代注解，与 Spring Framework &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@org.springframework.stereotype.Service&lt;/code&gt; 类似，用于服务提供方 Dubbo 服务暴露。与之相对应的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Reference&lt;/code&gt;，则是替代&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:reference&amp;gt;&lt;/code&gt; 元素，类似于 Spring 中的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Autowired&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.5.7&lt;/code&gt; 之前的Dubbo，与早期的 Spring Framework 2.5 存在类似的不足，即注解支持不够充分。注解需要和 XML 配置文件配合使用，如下所示：&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;beans&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns:xsi=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;xmlns:dubbo=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://code.alibabatech.com/schema/dubbo&quot;&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.springframework.org/schema/beans&quot;&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dubbo:application&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;annotation-provider&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dubbo:registry&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;address=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;127.0.0.1:4548&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;dubbo:annotation&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;package=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;com.alibaba.dubbo.config.spring.annotation.provider&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;/beans&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;不仅如此，当时的版本存在“ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Service&lt;/code&gt; Bean 不支持 Spring AOP” 以及 “&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Reference&lt;/code&gt; 不支持字段继承性” 等问题。&lt;/p&gt;

&lt;p&gt;从 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.5.7&lt;/code&gt; 开始，Dubbo 开始引入组件扫描 Annotation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@DubboComponentScan&lt;/code&gt;，借鉴了 Spring Boot 1.3 引入的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@ServletComponentScan&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;在职责上，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@DubboComponentScan&lt;/code&gt; 相对于 Spring Boot &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@ServletComponentScan&lt;/code&gt; 更为繁重，原因在于处理 Dubbo  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Service&lt;/code&gt; 类暴露 Dubbo 服务外，还有帮助 Spring  Bean &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Reference&lt;/code&gt;字段或者方法注入 Dubbo 服务代理。&lt;/p&gt;

&lt;p&gt;在场景上，Spring Framework &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@ComponentScan&lt;/code&gt; 组件扫描逻辑更为复杂。而在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@DubboComponentScan&lt;/code&gt;  只需关注 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Service&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Reference&lt;/code&gt; 处理。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;注：更多 Dubbo 注解驱动的详情，请参考&lt;a href=&quot;https://github.com/mercyblitz/blogs/blob/master/java/dubbo/Dubbo-Annotation-Driven.md&quot;&gt;《Dubbo 注解驱动（Annotation-Driven）》&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5 id=&quot;dubbocomponentscan-服务端示例&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@DubboComponentScan&lt;/code&gt; 服务端示例&lt;/h5&gt;

&lt;p&gt;假设，服务提供方和服务消费分均依赖服务接口&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DemoService&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DemoService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;服务提供方实现&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DemoService&lt;/code&gt;  - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnnotationDemoService&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;同时标注 Dubbo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Service&lt;/code&gt; ：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.provider&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.config.annotation.Service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.DemoService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 * Annotation {@link DemoService} 实现
 *
 * @author &amp;lt;a href=&quot;mailto:mercyblitz@gmail.com&quot;&amp;gt;Mercy&amp;lt;/a&amp;gt;
 */&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Service&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnotationDemoService&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DemoService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello , &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;服务端 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Configuration&lt;/code&gt; Class&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.config.ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.config.ProtocolConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.config.RegistryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.springframework.context.annotation.Bean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.springframework.context.annotation.Configuration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 * 服务提供方配置
 *
 * @author &amp;lt;a href=&quot;mailto:mercyblitz@gmail.com&quot;&amp;gt;Mercy&amp;lt;/a&amp;gt;
 */&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Configuration&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@DubboComponentScan&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;com.alibaba.dubbo.demo.provider&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 扫描 Dubbo 组件&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProviderConfiguration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * 当前应用配置
     */&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dubbo-annotation-provider&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dubbo-annotation-provider&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * 当前连接注册中心配置
     */&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-registry&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RegistryConfig&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;registryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;RegistryConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registryConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RegistryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;registryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAddress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;N/A&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * 当前连接注册中心配置
     */&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dubbo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProtocolConfig&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;protocolConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ProtocolConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;protocolConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProtocolConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;protocolConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dubbo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;protocolConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setPort&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;protocolConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;服务提供方引导类&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.bootstrap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.DemoService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.config.ProviderConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.springframework.context.annotation.AnnotationConfigApplicationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 * 服务提供方引导类
 *
 * @author &amp;lt;a href=&quot;mailto:mercyblitz@gmail.com&quot;&amp;gt;Mercy&amp;lt;/a&amp;gt;
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProviderBootstrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 创建 Annotation 配置上下文&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 注册配置 Bean&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ProviderConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 启动上下文&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;refresh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 获取 DemoService Bean&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;DemoService&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;demoService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DemoService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 执行 sayHello 方法&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;demoService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;World&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 控制台输出信息&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;dubbocomponentscan-客户端示例&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@DubboComponentScan&lt;/code&gt; 客户端示例&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;消费服务 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DemoService&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.consumer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.config.annotation.Reference&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.DemoService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 * Annotation 驱动 {@link DemoService} 消费方
 *
 * @author &amp;lt;a href=&quot;mailto:mercyblitz@gmail.com&quot;&amp;gt;Mercy&amp;lt;/a&amp;gt;
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnotationDemoServiceConsumer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Reference&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;dubbo://127.0.0.1:12345&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DemoService&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;demoService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;doSayHell&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;demoService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;消费端 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Configuration&lt;/code&gt; Class&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;与服务提供方配置类似，服务消费方也许 Dubbo 相关配置 Bean - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsumerConfiguration&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.config.ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.config.RegistryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.consumer.AnnotationDemoServiceConsumer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.springframework.context.annotation.Bean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.springframework.context.annotation.Configuration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 * 服务消费方配置
 *
 * @author &amp;lt;a href=&quot;mailto:mercyblitz@gmail.com&quot;&amp;gt;Mercy&amp;lt;/a&amp;gt;
 */&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Configuration&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@DubboComponentScan&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConsumerConfiguration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * 当前应用配置
     */&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dubbo-annotation-consumer&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * 当前连接注册中心配置
     */&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RegistryConfig&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;registryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;RegistryConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registryConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RegistryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;registryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAddress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;N/A&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * 注册 AnnotationDemoServiceConsumer，@DubboComponentScan 将处理其中 @Reference 字段。
     * 如果 AnnotationDemoServiceConsumer 非 Spring Bean 的话，
     * 即使 @DubboComponentScan 指定 package 也不会进行处理，与 Spring @Autowired 同理
     */&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnotationDemoServiceConsumer&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;annotationDemoServiceConsumer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AnnotationDemoServiceConsumer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;服务消费方引导类&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.bootstrap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.config.ConsumerConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.config.ProviderConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.alibaba.dubbo.demo.consumer.AnnotationDemoServiceConsumer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.springframework.context.ApplicationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.springframework.context.annotation.AnnotationConfigApplicationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/**
 * 服务消费端引导类
 *
 * @author &amp;lt;a href=&quot;mailto:mercyblitz@gmail.com&quot;&amp;gt;Mercy&amp;lt;/a&amp;gt;
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ConsumerBootstrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 启动服务提供方上下文&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;startProviderContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 启动并且返回服务消费方上下文&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumerContext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startConsumerContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 获取 AnnotationDemoServiceConsumer Bean&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;AnnotationDemoServiceConsumer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumerContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;AnnotationDemoServiceConsumer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 执行 doSayHello 方法&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;doSayHello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;World&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 输出执行结果&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * 启动并且返回服务消费方上下文
     *
     * @return AnnotationConfigApplicationContext
     */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationContext&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;startConsumerContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 创建服务消费方 Annotation 配置上下文&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumerContext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 注册服务消费方配置 Bean&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;consumerContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ConsumerConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 启动服务消费方上下文&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;consumerContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;refresh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 返回服务消费方 Annotation 配置上下文&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumerContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * 启动服务提供方上下文
     */&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;startProviderContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 创建 Annotation 配置上下文&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;providerContext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 注册配置 Bean&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;providerContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ProviderConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 启动服务提供方上下文&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;providerContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;refresh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;dubbo-外部化配置externalized-configuration&quot;&gt;Dubbo 外部化配置（Externalized Configuration）&lt;/h4&gt;

&lt;p&gt;在Dubbo 注解驱动例子中，无论是服务提供方，还是服务消费方，均需要转配相关配置Bean：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dubbo-annotation-consumer&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;虽然实现类似于&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProviderConfiguration&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsumerConfiguration&lt;/code&gt; 这样的 Spring  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Configuration&lt;/code&gt; Bean 成本并不高，不过通过 Java Code 的方式定义配置 Bean，或多或少是一种 Hard Code（硬编码）的行为，缺少弹性。&lt;/p&gt;

&lt;p&gt;尽管在 Spring 应用中，可以通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Value&lt;/code&gt; 或者 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Environment&lt;/code&gt; 的方式获取外部配置，其代码简洁性以及类型转换灵活性存在明显的不足。因此，Spring Boot  提出了外部化配置（External Configuration）的感念，即通过程序以外的配置源，动态地绑定指定类型。&lt;/p&gt;

&lt;p&gt;随着 Spring Boot / Spring Cloud 应用的流行，开发人员逐渐地接受并且使用 Spring Boot 外部化配置（External Configuration），即通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application.properties&lt;/code&gt; 或者 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap.properties&lt;/code&gt; 装配配置 Bean。&lt;/p&gt;

&lt;p&gt;下列表格记录了 Dubbo 内置配置类：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;配置类&lt;/th&gt;
      &lt;th&gt;标签&lt;/th&gt;
      &lt;th&gt;用途&lt;/th&gt;
      &lt;th&gt;解释&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProtocolConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:protocol/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;协议配置&lt;/td&gt;
      &lt;td&gt;用于配置提供服务的协议信息，协议由提供方指定，消费方被动接受&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:application/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;应用配置&lt;/td&gt;
      &lt;td&gt;用于配置当前应用信息，不管该应用是提供者还是消费者&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ModuleConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:module/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;模块配置&lt;/td&gt;
      &lt;td&gt;用于配置当前模块信息，可选&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegistryConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:registry/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;注册中心配置&lt;/td&gt;
      &lt;td&gt;用于配置连接注册中心相关信息&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MonitorConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:monitor/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;监控中心配置&lt;/td&gt;
      &lt;td&gt;用于配置连接监控中心相关信息，可选&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProviderConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:provider/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;提供方配置&lt;/td&gt;
      &lt;td&gt;当 ProtocolConfig 和 ServiceConfig 某属性没有配置时，采用此缺省值，可选&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsumerConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:consumer/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;消费方配置&lt;/td&gt;
      &lt;td&gt;当 ReferenceConfig 某属性没有配置时，采用此缺省值，可选&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MethodConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:method/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;方法配置&lt;/td&gt;
      &lt;td&gt;用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ArgumentConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:argument/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;参数配置&lt;/td&gt;
      &lt;td&gt;用于指定方法参数配置&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;通过申明对应的 Spring 扩展标签，在 Spring 应用上下文中将自动生成相应的配置 Bean。&lt;/p&gt;

&lt;p&gt;在 Dubbo 官方用户手册的&lt;a href=&quot;http://dubbo.io/books/dubbo-user-book/configuration/properties.html&quot;&gt;“属性配置”&lt;/a&gt;章节中，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.properties&lt;/code&gt; 配置属性能够映射到  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt; 、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProtocolConfig&lt;/code&gt; 以及 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegistryConfig&lt;/code&gt; 的字段。从某种意义上来说，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.properties&lt;/code&gt;  也是 Dubbo 的外部化配置。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;注：更多外部化配置的详情，请参考&lt;a href=&quot;https://github.com/mercyblitz/blogs/blob/master/java/dubbo/Dubbo-Externalized-Configuration.md&quot;&gt;《Dubbo 外部化配置（Externalized Configuration）》&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;现场演示环节&quot;&gt;现场演示环节&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;本环境为分享后部分，现在编码 + 演示环境，当前文字仅提供代码实现。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&quot;dubbo-整合-hystrix-示例&quot;&gt;Dubbo 整合 Hystrix 示例&lt;/h4&gt;

&lt;blockquote&gt;
  &lt;p&gt;本示例出现在分享议程的代码演示，将其放置此处，方便阅读理解&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5 id=&quot;dubbo-客户端实现&quot;&gt;Dubbo 客户端实现&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;实现 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HystrixCommand&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ResultHystrixCommand&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HystrixCommand&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Invoker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invoker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Invocation&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invocation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ResultHystrixCommand&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Invoker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invoker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Invocation&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invocation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HystrixCommandGroupKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Factory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;asKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;ResultHystrixCommand&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
                &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 设置超时时间&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 关联 Dubbo Invoker 和 Invocation&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;invoker&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invoker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;invocation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invocation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Result&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 远程方法调用执行&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invoker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;invocation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;当目标方法执行时间超过 100 ms 时，触发熔断，并抛出 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new UnsupportedOperationException(&quot;No fallback available.&quot;)&lt;/code&gt;。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Dubbo  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Filter&lt;/code&gt; 整合 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResultHystrixCommand&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nd&quot;&gt;@Activate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CONSUMER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;hystrix&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 命名当前 Filter 为 &quot;hystrix&quot;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HystrixFilter&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Filter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Result&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Invoker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invoker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Invocation&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invocation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RpcException&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ResultHystrixCommand&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;invoker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invocation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;创建并配置 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Filter&lt;/code&gt; SPI 配置文件&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;在相对于 ClassPath 资源 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;META-INF/dubbo/&lt;/code&gt; 下创建 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.alibaba.dubbo.rpc.Filter&lt;/code&gt;，并配置如下：&lt;/p&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;py&quot;&gt;hystrix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;com.alibaba.boot.dubbo.demo.consumer.filter.HystrixFilter&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;配置 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Reference&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filter&lt;/code&gt; 属性&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nd&quot;&gt;@RestController&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DemoConsumerController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Reference&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;${demo.service.version}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;application&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;${dubbo.application.id}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;dubbo://localhost:12345&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;hystrix&quot;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 指向 HystrixFilter 实现&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DemoService&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;demoService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@RequestMapping&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/sayHello&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@RequestParam&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;demoService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;dubbo-服务端实现&quot;&gt;Dubbo 服务端实现&lt;/h6&gt;

&lt;ul&gt;
  &lt;li&gt;服务提供者实现&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nd&quot;&gt;@Service&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;${demo.service.version}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;application&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;${dubbo.application.id}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;protocol&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;dubbo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;registry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;${dubbo.registry.id}&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DefaultDemoService&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DemoService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Random&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;hold&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Say : Hello, &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; (from Spring Boot)&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hold&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 随机等待 &amp;lt; 200 ms，当时间超过 100 ms 时，触发客户端熔断&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;nextInt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;To hold &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; ms!&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;InterruptedException&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;currentThread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;interrupt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;测试客户端-rest-服务&quot;&gt;测试客户端 REST 服务&lt;/h5&gt;

&lt;p&gt;依次启动服务端 和客户端 Spring Boot 应用，&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; 命令&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;mercyblitz$ curl http://localhost:8080/sayHello?name=Hello
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;测试结果&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;{&quot;timestamp&quot;:&quot;2018-06-23T01:33:58.682+0000&quot;,&quot;status&quot;:500,&quot;error&quot;:&quot;Internal Server Error&quot;,&quot;message&quot;:&quot;ResultHystrixCommand timed-out and no fallback available.&quot;,&quot;path&quot;:&quot;/sayHello&quot;}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;运行结果说明服务端方法执行超过 100 ms，引起客户端熔断。&lt;/p&gt;

&lt;p&gt;（EOF）&lt;/p&gt;

&lt;h2 id=&quot;参考资源&quot;&gt;参考资源&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://dubbo.apache.org/&quot;&gt;Dubbo 官网&lt;/a&gt;：https://dubbo.apache.org/&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/apache/incubator-dubbo&quot;&gt;Dubbo 工程&lt;/a&gt;：https://github.com/apache/incubator-dubbo&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/apache/incubator-dubbo-spring-boot-project&quot;&gt;Dubbo Spring Boot 工程&lt;/a&gt;：https://github.com/apache/incubator-dubbo-spring-boot-project&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://landscape.cncf.io/&quot;&gt;CNCF Landscape&lt;/a&gt;：https://landscape.cncf.io/&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://projects.spring.io/spring-cloud/&quot;&gt;Spring Cloud 官网&lt;/a&gt;：https://projects.spring.io/spring-cloud/&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://konghq.com/kong-community-edition/&quot;&gt;Kong 社区官网&lt;/a&gt;：https://konghq.com/kong-community-edition/&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://opentracing.io/&quot;&gt;Opentracing 官网&lt;/a&gt;：http://opentracing.io/&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.jaegertracing.io/&quot;&gt;Jaeger 官网&lt;/a&gt;：https://www.jaegertracing.io/&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://prometheus.io/&quot;&gt;Prometheus 官网&lt;/a&gt;：https://prometheus.io/&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://opentsdb.net/&quot;&gt;OpenTsdb 官网&lt;/a&gt;：http://opentsdb.net/&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://grafana.com/&quot;&gt;Grafana 官网&lt;/a&gt;：https://grafana.com/&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mercyblitz&quot;&gt;小马哥 Github&lt;/a&gt;：https://github.com/mercyblitz&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 28 Jun 2018 00:00:00 +0000</pubDate>
        <link>https://weibo.com/mercyblitz/2018/06/28/Dubbo-Cloud-Native-%E5%AE%9E%E8%B7%B5%E4%B8%8E%E6%80%9D%E8%80%83/</link>
        <guid isPermaLink="true">https://weibo.com/mercyblitz/2018/06/28/Dubbo-Cloud-Native-%E5%AE%9E%E8%B7%B5%E4%B8%8E%E6%80%9D%E8%80%83/</guid>
        
        
      </item>
    
      <item>
        <title>Spring Boot web 应用加速</title>
        <description>&lt;h1 id=&quot;spring-boot-web-应用加速&quot;&gt;Spring Boot Web 应用加速&lt;/h1&gt;

&lt;p&gt;默认情况下，Spring Boot Web 应用会装配一些功能组件 Bean。&lt;/p&gt;

&lt;p&gt;在大多数 Web 应用场景下，可以选择性地关闭一下自动装配的Spring 组件 Bean，以达到提升性能的目的。&lt;/p&gt;

&lt;h2 id=&quot;配置项优化&quot;&gt;配置项优化&lt;/h2&gt;

&lt;h3 id=&quot;spring-boot-web-应用加速-完整配置项&quot;&gt;Spring Boot Web 应用加速 完整配置项&lt;/h3&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;py&quot;&gt;management.add-application-context-header&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;spring.mvc.formcontent.putfilter.enabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;false&lt;/span&gt;

&lt;span class=&quot;py&quot;&gt;spring.autoconfigure.exclude&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.actuate.autoconfigure.TraceRepositoryAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;配置项汇总&quot;&gt;配置项汇总&lt;/h3&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;py&quot;&gt;spring.autoconfigure.exclude&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;org.springframework.boot.actuate.autoconfigure.TraceRepositoryAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;关闭-web-请求跟踪-自动装配&quot;&gt;关闭 Web 请求跟踪 自动装配&lt;/h3&gt;

&lt;h4 id=&quot;orgspringframeworkbootactuateautoconfiguretracewebfilterautoconfiguration&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;顾名思义，该自动装配用跟踪 Web 请求，通过Servlet Filter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.boot.actuate.trace.WebRequestTraceFilter&lt;/code&gt; 记录请求的信息（如：请求方法、请求头以及请求路径等），其计算的过程存在一定的开销，使用场景罕见，故可选择关闭。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;配置项&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;py&quot;&gt;spring.autoconfigure.exclude&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;orgspringframeworkbootactuateautoconfiguretracerepositoryautoconfiguration&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.boot.actuate.autoconfigure.TraceRepositoryAutoConfiguration&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;当&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration&lt;/code&gt;关闭后，其请求信息存储介质&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.boot.actuate.trace.TraceRepository&lt;/code&gt;没有存在的必要，故可选择关闭。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;配置项&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;py&quot;&gt;spring.autoconfigure.exclude&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;org.springframework.boot.actuate.autoconfigure.TraceRepositoryAutoConfiguration&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;关闭-web-请求结果指标-自动装配&quot;&gt;关闭 Web 请求结果指标 自动装配&lt;/h3&gt;

&lt;h4 id=&quot;orgspringframeworkbootactuateautoconfiguremetricfilterautoconfiguration&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;该组件将自动装配&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.boot.actuate.autoconfigure.MetricsFilter&lt;/code&gt;，该 Filter&lt;/p&gt;

&lt;p&gt;主要记录Web 请求结果指标（如：相应状态码、请求方法执行时间等），该信息一定程度上与反向代理服务器（nginx）功能重叠，故可选择关闭。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;配置项&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;py&quot;&gt;spring.autoconfigure.exclude&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;可关闭-servlet-web-组件&quot;&gt;可关闭 Servlet Web 组件&lt;/h3&gt;

&lt;h4 id=&quot;orgspringframeworkwebfilterhttpputformcontentfilter&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HttpPutFormContentFilter&lt;/code&gt;&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;引入版本&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HttpPutFormContentFilter&lt;/code&gt; 由 Spring
Framework 3.1 版本引入，分发在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework:spring-web&lt;/code&gt; 中。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;使用场景&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;通常 Web 场景中，浏览器通过 HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; 或者 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; 请求 提交 Form 数据，而非浏览
器客户端（如应用程序）可能通过 HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; 请求来实现。&lt;/p&gt;

&lt;p&gt;当 HTTP 请求头&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt; 为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/x-www-form-urlencoded&lt;/code&gt; 时
，Form 数据被 encoded。而 Servlet 规范中， &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServletRequest.getParameter*()&lt;/code&gt;
方法仅对 HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; 方法支持请求参数的获取，如：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;intetfacce&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServletRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;......&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getParameter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Enumeration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getParameterNames&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getParameterValues&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getParameterMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;......&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;故 以上方法无法支持 HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; 或 HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; 请求方法（请求头&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt;
为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/x-www-form-urlencoded&lt;/code&gt;）。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HttpPutFormContentFilter&lt;/code&gt; 正是这种场景的解
决方案。&lt;/p&gt;

&lt;p&gt;Spring Boot 默认场景下，将
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HttpPutFormContentFilter&lt;/code&gt; 被
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration&lt;/code&gt; 自动
装配，以下为 Spring Boot 1.4.1.RELEASE 以及更好版本定义（可能存在一定的差异）：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nd&quot;&gt;@Configuration&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@ConditionalOnWebApplication&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@ConditionalOnClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Servlet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DispatcherServlet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;nc&quot;&gt;WebMvcConfigurerAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@ConditionalOnMissingBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;WebMvcConfigurationSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@AutoConfigureOrder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ordered&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;HIGHEST_PRECEDENCE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@AutoConfigureAfter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DispatcherServletAutoConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;nc&quot;&gt;ValidationAutoConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebMvcAutoConfiguration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;......&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@ConditionalOnMissingBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HttpPutFormContentFilter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@ConditionalOnProperty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;spring.mvc.formcontent.putfilter&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matchIfMissing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderedHttpPutFormContentFilter&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;httpPutFormContentFilter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderedHttpPutFormContentFilter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;......&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;综上所述，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HttpPutFormContentFilter&lt;/code&gt; 在绝大
多数 Web 使用场景下为非必须组件。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;配置项&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如果应用依赖 Spring Boot 版本 为 1.4.1.RELEASE 以及更高的版本，可通过如下配置，
进行将 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HttpPutFormContentFilter&lt;/code&gt; 关闭：&lt;/p&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;py&quot;&gt;spring.mvc.formcontent.putfilter.enabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;false&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;orgspringframeworkwebfilterhiddenhttpmethodfilter&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HiddenHttpMethodFilter&lt;/code&gt;&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;引入版本&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HiddenHttpMethodFilter&lt;/code&gt; 由 Spring
Framework 3.0 版本引入，分发在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework:spring-web&lt;/code&gt; 中。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;使用场景&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;当 Web 服务端同一资源（URL）提供了多请求方法的实现，例如 URI ：/update 提供了
HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; 以及 HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; 实现），通常 Web 场景中，浏览器仅支持 HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt;
或者 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; 请求方法，这样的话，浏览器无法发起 HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; 请求。&lt;/p&gt;

&lt;p&gt;为了浏览器可以消费 HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; 资源， 需要在服务端将 HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; 转化成
HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; 请求，为了解决这类问题，Spring 引入
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HiddenHttpMethodFilter&lt;/code&gt; Web 组件。&lt;/p&gt;

&lt;p&gt;当浏览器 发起 HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; 请求时，可通过增加请求参数（默认参数名称：”_method”）
的方式，进行HTTP 请求方法切换，
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HiddenHttpMethodFilter&lt;/code&gt; 获取参数”_method”
值后，将参数值作为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpServletRequest#getMethod()&lt;/code&gt;的返回值，给后续 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Servlet&lt;/code&gt;
实现使用。&lt;/p&gt;

&lt;p&gt;出于通用性的考虑，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HiddenHttpMethodFilter&lt;/code&gt;
通过调用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#setMethodParam(String)&lt;/code&gt; 方法，来修改转换请求方法的参数名称。&lt;/p&gt;

&lt;p&gt;Spring Boot 默认场景下，将
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HttpPutFormContentFilter&lt;/code&gt; 被
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration&lt;/code&gt; 自动
装配，以下为 Spring Boot 1.4.1.RELEASE 以及更好版本定义（可能存在一定的差异）：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nd&quot;&gt;@Configuration&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@ConditionalOnWebApplication&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@ConditionalOnClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Servlet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DispatcherServlet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;nc&quot;&gt;WebMvcConfigurerAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@ConditionalOnMissingBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;WebMvcConfigurationSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@AutoConfigureOrder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ordered&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;HIGHEST_PRECEDENCE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@AutoConfigureAfter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DispatcherServletAutoConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;nc&quot;&gt;ValidationAutoConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebMvcAutoConfiguration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;......&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@ConditionalOnMissingBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HiddenHttpMethodFilter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderedHiddenHttpMethodFilter&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hiddenHttpMethodFilter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderedHiddenHttpMethodFilter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;......&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;综上所述，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.springframework.web.filter.HiddenHttpMethodFilter&lt;/code&gt; 也是特殊
场景下所需，故可以关闭之。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;配置项&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;按目前最新的 Spring Boot 1.5.2.RELEASE 版本中实现，也没有提供类似
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spring.mvc.formcontent.putfilter.enabled&lt;/code&gt; 这样的配置项关闭，无法关闭。&lt;/p&gt;

</description>
        <pubDate>Sat, 26 May 2018 00:00:00 +0000</pubDate>
        <link>https://weibo.com/mercyblitz/2018/05/26/Spring-Boot-Web-%E5%BA%94%E7%94%A8%E5%8A%A0%E9%80%9F/</link>
        <guid isPermaLink="true">https://weibo.com/mercyblitz/2018/05/26/Spring-Boot-Web-%E5%BA%94%E7%94%A8%E5%8A%A0%E9%80%9F/</guid>
        
        
      </item>
    
      <item>
        <title>Dubbo 外部化配置</title>
        <description>&lt;h1 id=&quot;dubbo-外部化配置externalized-configuration&quot;&gt;Dubbo 外部化配置（Externalized Configuration）&lt;/h1&gt;

&lt;h2 id=&quot;外部化配置external-configuration&quot;&gt;外部化配置（External Configuration）&lt;/h2&gt;

&lt;p&gt;在&lt;a href=&quot;Dubbo-Annotation-Driven.md&quot;&gt;Dubbo 注解驱动&lt;/a&gt;例子中，无论是服务提供方，还是服务消费方，均需要转配相关配置Bean：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dubbo-annotation-consumer&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;虽然实现类似于&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProviderConfiguration&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsumerConfiguration&lt;/code&gt; 这样的 Spring  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Configuration&lt;/code&gt; Bean 成本并不高，不过通过 Java Code 的方式定义配置 Bean，或多或少是一种 Hard Code（硬编码）的行为，缺少弹性。&lt;/p&gt;

&lt;p&gt;尽管在 Spring 应用中，可以通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Value&lt;/code&gt; 或者 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Environment&lt;/code&gt; 的方式获取外部配置，其代码简洁性以及类型转换灵活性存在明显的不足。因此，Spring Boot  提出了外部化配置（External Configuration）的感念，即通过程序以外的配置源，动态地绑定指定类型。&lt;/p&gt;

&lt;p&gt;随着 Spring Boot / Spring Cloud 应用的流行，开发人员逐渐地接受并且使用 Spring Boot 外部化配置（External Configuration），即通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application.properties&lt;/code&gt; 或者 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap.properties&lt;/code&gt; 装配配置 Bean。&lt;/p&gt;

&lt;p&gt;下列表格记录了 Dubbo 内置配置类：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;配置类&lt;/th&gt;
      &lt;th&gt;标签&lt;/th&gt;
      &lt;th&gt;用途&lt;/th&gt;
      &lt;th&gt;解释&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProtocolConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:protocol/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;协议配置&lt;/td&gt;
      &lt;td&gt;用于配置提供服务的协议信息，协议由提供方指定，消费方被动接受&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:application/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;应用配置&lt;/td&gt;
      &lt;td&gt;用于配置当前应用信息，不管该应用是提供者还是消费者&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ModuleConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:module/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;模块配置&lt;/td&gt;
      &lt;td&gt;用于配置当前模块信息，可选&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegistryConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:registry/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;注册中心配置&lt;/td&gt;
      &lt;td&gt;用于配置连接注册中心相关信息&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MonitorConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:monitor/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;监控中心配置&lt;/td&gt;
      &lt;td&gt;用于配置连接监控中心相关信息，可选&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProviderConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:provider/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;提供方配置&lt;/td&gt;
      &lt;td&gt;当 ProtocolConfig 和 ServiceConfig 某属性没有配置时，采用此缺省值，可选&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsumerConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:consumer/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;消费方配置&lt;/td&gt;
      &lt;td&gt;当 ReferenceConfig 某属性没有配置时，采用此缺省值，可选&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MethodConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:method/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;方法配置&lt;/td&gt;
      &lt;td&gt;用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ArgumentConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:argument/&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;参数配置&lt;/td&gt;
      &lt;td&gt;用于指定方法参数配置&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;通过申明对应的 Spring 扩展标签，在 Spring 应用上下文中将自动生成相应的配置 Bean。&lt;/p&gt;

&lt;p&gt;在 Dubbo 官方用户手册的&lt;a href=&quot;http://dubbo.io/books/dubbo-user-book/configuration/properties.html&quot;&gt;“属性配置”&lt;/a&gt;章节中，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.properties&lt;/code&gt; 配置属性能够映射到  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt; 、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProtocolConfig&lt;/code&gt; 以及 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegistryConfig&lt;/code&gt; 的字段。从某种意义上来说，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.properties&lt;/code&gt;  也是 Dubbo 的外部化配置。&lt;/p&gt;

&lt;p&gt;其中，引用“映射规则”的内容：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;h2 id=&quot;映射规则&quot;&gt;映射规则&lt;/h2&gt;

  &lt;p&gt;将 XML 配置的标签名，加属性名，用点分隔，多个属性拆成多行&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;比如：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.application.name=foo&lt;/code&gt;等价于&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:application name=&quot;foo&quot; /&amp;gt;&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;比如：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.registry.address=10.20.153.10:9090&lt;/code&gt;等价于&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:registryaddress=&quot;10.20.153.10:9090&quot; /&amp;gt;&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;如果 XML 有多行同名标签配置，可用 id 号区分，如果没有 id 号将对所有同名标签生效&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;比如：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.protocol.rmi.port=1234&lt;/code&gt;等价于&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:protocol id=&quot;rmi&quot; name=&quot;rmi&quot; port=&quot;1099&quot; /&amp;gt;&lt;/code&gt;&lt;a href=&quot;http://dubbo.io/books/dubbo-user-book/configuration/properties.html#fn_2&quot;&gt;2&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;比如：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.registry.china.address=10.20.153.10:9090&lt;/code&gt;等价于&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;dubbo:registry id=&quot;china&quot;address=&quot;10.20.153.10:9090&quot; /&amp;gt;&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;下面是 dubbo.properties 的一个典型配置：&lt;/p&gt;

  &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;dubbo.application.name=foo
dubbo.application.owner=bar
dubbo.registry.address=10.20.153.10:9090
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;根据“映射规则”，Dubbo 即支持单配置 Bean 映射，也支持多 Bean 映射。综合以上需求，既要兼容 Dubbo 已有的一个或多个 Bean 字段映射绑定，也支持外部化配置。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;特别提醒：外部化配置（External Configuration）并非 Spring Boot 特有，即使在 Spring Framework 场景下亦能支持。也就是说 Dubbo 外部化配置即可在 Spring Framework 中工作，也能在 Spring Boot 中运行。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dubbo 外部化配置（External Configuration） 支持起始版本为：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.5.8&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;enabledubboconfig&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig&lt;/code&gt;&lt;/h3&gt;

&lt;h4 id=&quot;起始版本258&quot;&gt;起始版本：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.5.8&lt;/code&gt;&lt;/h4&gt;

&lt;h4 id=&quot;使用说明&quot;&gt;使用说明&lt;/h4&gt;

&lt;h5 id=&quot;enabledubboconfig-定义&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig&lt;/code&gt; 定义&lt;/h5&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EnableDubboConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * It indicates whether binding to multiple Spring Beans.
     *
     * @return the default value is &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;
     * @revised 2.5.9
     */&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;multiple&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multiple&lt;/code&gt; : 表示是否支持多Dubbo 配置 Bean 绑定。默认值为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt; ，即单 Dubbo 配置 Bean 绑定&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&quot;单-dubbo-配置-bean-绑定&quot;&gt;单 Dubbo 配置 Bean 绑定&lt;/h5&gt;

&lt;p&gt;为了更好地向下兼容，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig&lt;/code&gt; 提供外部化配置属性与 Dubbo 配置类之间的绑定，其中映射关系如下：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;配置类&lt;/th&gt;
      &lt;th&gt;外部化配置属性前缀&lt;/th&gt;
      &lt;th&gt;用途&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProtocolConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.protocol&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;协议配置&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.application&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;应用配置&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ModuleConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.module&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;模块配置&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegistryConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.registry&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;注册中心配置&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MonitorConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.monitor&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;监控中心配置&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProviderConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.provider&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;提供方配置&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsumerConfig&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.consumer&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;消费方配置&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;当标注 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig&lt;/code&gt; 的类被扫描注册后，同时  Spring（Spring Boot）应用配置（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PropertySources&lt;/code&gt;）中存在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.application.*&lt;/code&gt; 时，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt;  Bean 将被注册到在 Spring 上下文。否则，不会被注册。如果出现&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.registry.*&lt;/code&gt;的配置，那么，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegistryConfig&lt;/code&gt; Bean 将会创建，以此类推。即按需装配 Dubbo 配置 Bean。&lt;/p&gt;

&lt;p&gt;如果需要指定配置 Bean的 id，可通过&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;**.id&lt;/code&gt; 属性设置，以&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.application&lt;/code&gt; 为例：&lt;/p&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;## application
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.application.id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;applicationBean&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.application.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;以上配置等同于以下 Java Config Bean：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;applicationBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dubbo-demo-application&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;大致上配置属性与配置类绑定模式 - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.application.* &lt;/code&gt; 映射到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt; 中的字段。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;注：当配置属性名称无法在配置类中找到字段时，将会忽略绑定&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5 id=&quot;多-dubbo-配置-bean-绑定&quot;&gt;多 Dubbo 配置 Bean 绑定&lt;/h5&gt;

&lt;p&gt;Dubbo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Service&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Reference&lt;/code&gt; 允许 Dubbo 应用关联&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt; Bean 或者指定多个&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegistryConfig&lt;/code&gt; Bean 等能力。换句话说，Dubbo 应用上下文中可能存在多个&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt; 等 Bean定义。&lt;/p&gt;

&lt;p&gt;为了适应以上需要，因此从Dubbo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.5.9&lt;/code&gt; 开始，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig&lt;/code&gt; 支持多 Dubbo 配置 Bean 绑定，同时按照业界规约标准，与单 Dubbo 配置 Bean 绑定约定不同，配置属性前缀均为英文复数形式：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;详情请参考 ：https://github.com/alibaba/dubbo/issues/1141&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.applications&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.modules&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.registries&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.protocols&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.monitors&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.providers&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.consumers&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;以&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.applications&lt;/code&gt; 为例，基本的模式如下：&lt;/p&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;err&quot;&gt;dubbo.applications.${bean-name}&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.property-name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${property-value}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;请读者注意，在单 Dubbo 配置 Bean 绑定时，可以通过指定&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; 属性的方式，定义&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt; Bean 的ID，即&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.application.id&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;而在多 Dubbo 配置 Bean 绑定时，Bean ID 则由&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.applications.&lt;/code&gt;与属性字段名称（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.property-name&lt;/code&gt;)之间的字符来表达。&lt;/p&gt;

&lt;p&gt;如下配置：&lt;/p&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;# multiple Bean definition
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.applications.applicationBean.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.applications.applicationBean2.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application2&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.applications.applicationBean3.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;该配置内容中，绑定了三个&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt; Bean，分别是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;applicationBean&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;applicationBean2&lt;/code&gt;以及&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;applicationBean3&lt;/code&gt;&lt;/p&gt;

&lt;h4 id=&quot;示例说明&quot;&gt;示例说明&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig&lt;/code&gt; 的使用方法很简答， 再次强调一点，当规约的外部配置存在时，相应的 Dubbo 配置类 才会提升为 Spring Bean。简言之，按需装配。&lt;/p&gt;

&lt;h5 id=&quot;单-dubbo-配置-bean-绑定-1&quot;&gt;单 Dubbo 配置 Bean 绑定&lt;/h5&gt;

&lt;h6 id=&quot;外部化配置文件&quot;&gt;外部化配置文件&lt;/h6&gt;

&lt;p&gt;将以下内容的外部化配置文件物理路径为：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;classpath:/META-INF/config.properties&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;# 单 Dubbo 配置 Bean 绑定
## application
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.application.id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;applicationBean&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.application.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## module
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.module.id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;moduleBean&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.module.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-module&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## registry
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.registry.address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;zookeeper://192.168.99.100:32770&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## protocol
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.protocol.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.protocol.port&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;20880&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## monitor
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.monitor.address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;zookeeper://127.0.0.1:32770&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## provider
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.provider.host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;127.0.0.1&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## consumer
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.consumer.client&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;netty&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;enabledubboconfig-配置-bean&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig&lt;/code&gt; 配置 Bean&lt;/h6&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * Dubbo 配置 Bean
 *
 * @author &amp;lt;a href=&quot;mailto:mercyblitz@gmail.com&quot;&amp;gt;Mercy&amp;lt;/a&amp;gt;
 */&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@EnableDubboConfig&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@PropertySource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;META-INF/config.properties&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Configuration&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DubboConfiguration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;实现引导类&quot;&gt;实现引导类&lt;/h6&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * Dubbo 配置引导类
 *
 * @author &amp;lt;a href=&quot;mailto:mercyblitz@gmail.com&quot;&amp;gt;Mercy&amp;lt;/a&amp;gt;
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DubboConfigurationBootstrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 创建配置上下文&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 注册当前配置 Bean&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DubboConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;refresh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
 	    &lt;span class=&quot;c1&quot;&gt;// application&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// module&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ModuleConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;moduleConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;moduleBean&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ModuleConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;moduleBean.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;moduleConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// registry&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;RegistryConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registryConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RegistryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;registryConfig.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAddress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// protocol&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ProtocolConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;protocolConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ProtocolConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;protocolConfig.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;protocolConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;protocolConfig.port = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;protocolConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getPort&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// monitor&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;MonitorConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;monitorConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MonitorConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;monitorConfig.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;monitorConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAddress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// provider&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ProviderConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;providerConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ProviderConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;providerConfig.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;providerConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getHost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// consumer&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ConsumerConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumerConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ConsumerConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;consumerConfig.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumerConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;执行结果&quot;&gt;执行结果&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;applicationBean.name = dubbo-demo-application 
moduleBean.name = dubbo-demo-module 
registryConfig.name = zookeeper://192.168.99.100:32770 
protocolConfig.name = dubbo 
protocolConfig.port = 20880 
monitorConfig.name = zookeeper://127.0.0.1:32770 
providerConfig.name = 127.0.0.1 
consumerConfig.name = netty 
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;不难发现，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig&lt;/code&gt; 配置 Bean 配合外部化文件 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;classpath:/META-INF/config.properties&lt;/code&gt;，与执行输出内容相同。&lt;/p&gt;

&lt;h5 id=&quot;多-dubbo-配置-bean-绑定-1&quot;&gt;多 Dubbo 配置 Bean 绑定&lt;/h5&gt;

&lt;h6 id=&quot;外部化配置文件-1&quot;&gt;外部化配置文件&lt;/h6&gt;

&lt;p&gt;将以下内容的外部化配置文件物理路径为：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;classpath:/META-INF/multiple-config.properties&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;# 多 Dubbo 配置 Bean 绑定
## dubbo.applications
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.applications.applicationBean.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.applications.applicationBean2.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application2&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.applications.applicationBean3.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;enabledubboconfig--配置-bean多&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig&lt;/code&gt;  配置 Bean（多）&lt;/h6&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;nd&quot;&gt;@EnableDubboConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;multiple&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@PropertySource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;META-INF/multiple-config.properties&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DubboMultipleConfiguration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;	
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;实现引导类-1&quot;&gt;实现引导类&lt;/h6&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * Dubbo 配置引导类
 *
 * @author &amp;lt;a href=&quot;mailto:mercyblitz@gmail.com&quot;&amp;gt;Mercy&amp;lt;/a&amp;gt;
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DubboConfigurationBootstrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 创建配置上下文&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 注册当前配置 Bean&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DubboMultipleConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;refresh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 获取 ApplicationConfig Bean：&quot;applicationBean&quot;、&quot;applicationBean2&quot; 和 &quot;applicationBean3&quot;&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean2&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean3&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean2.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean3.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;执行结果-1&quot;&gt;执行结果&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;applicationBean.name = dubbo-demo-application 
applicationBean2.name = dubbo-demo-application2 
applicationBean3.name = dubbo-demo-application3 
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig(multiple = true)&lt;/code&gt; 执行后，运行结果说明&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt; Bean 以及 ID 的定义方式。&lt;/p&gt;

&lt;h3 id=&quot;enabledubboconfigbinding--enabledubboconfigbindings&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfigBinding&lt;/code&gt; &amp;amp; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfigBindings&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig&lt;/code&gt;适合绝大多数外部化配置场景，然而无论是单 Bean 绑定，还是多 Bean 绑定，其&lt;strong&gt;外部化配置属性前缀&lt;/strong&gt;是固化的，如&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.application&lt;/code&gt; 以及 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.applications&lt;/code&gt; 。&lt;/p&gt;

&lt;p&gt;当应用需要自定义&lt;strong&gt;外部化配置属性前缀&lt;/strong&gt;，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfigBinding&lt;/code&gt;能提供更大的弹性，支持单个外部化配置属性前缀（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefix&lt;/code&gt;) 与 Dubbo 配置 Bean 类型（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AbstractConfig&lt;/code&gt; 子类）绑定，如果需要多次绑定时，可使用&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfigBindings&lt;/code&gt;。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;尽管 Dubbo 推荐使用 Java 8 ，然而实际的情况，运行时的 JDK 的版本可能从 6到8 均有。因此，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfigBinding&lt;/code&gt; 没有实现&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.lang.annotation.Repeatable&lt;/code&gt;，即允许实现类不支持重复标注&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfigBinding&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfigBinding&lt;/code&gt;  在支持外部化配置属性与 Dubbo 配置类绑定时，与 Dubbo 过去的映射行为不同，被绑定的 Dubbo 配置类将会提升为 Spring Bean，无需提前装配 Dubbo 配置类。同时，支持多 Dubbo 配置Bean 装配。其 Bean 的绑定规则与&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfig&lt;/code&gt;一致。&lt;/p&gt;

&lt;h4 id=&quot;起始版本-258&quot;&gt;起始版本： &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.5.8&lt;/code&gt;&lt;/h4&gt;

&lt;h4 id=&quot;使用说明-1&quot;&gt;使用说明&lt;/h4&gt;

&lt;h5 id=&quot;enabledubboconfigbinding-定义&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfigBinding&lt;/code&gt; 定义&lt;/h5&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EnableDubboConfigBinding&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * The name prefix of the properties that are valid to bind to {@link AbstractConfig Dubbo Config}.
     *
     * @return the name prefix of the properties to bind
     */&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * @return The binding type of {@link AbstractConfig Dubbo Config}.
     * @see AbstractConfig
     * @see ApplicationConfig
     * @see ModuleConfig
     * @see RegistryConfig
     */&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;?&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * It indicates whether {@link #prefix()} binding to multiple Spring Beans.
     *
     * @return the default value is &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;
     */&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;multiple&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefix()&lt;/code&gt; : 指定待绑定 Dubbo 配置类的外部化配置属性的前缀，比如&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.application&lt;/code&gt;  为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt; 的外部化配置属性的前缀。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefix()&lt;/code&gt; 支持占位符（Placeholder）, 并且其关联前缀值是否以”.” 作为结尾字符是可选的，即&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefix() = &quot;dubbo.application&quot;&lt;/code&gt; 与 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefix() = &quot;dubbo.application.&quot;&lt;/code&gt; 效果相同&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type()&lt;/code&gt; : 指定 Dubbo 配置类，所有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AbstractConfig&lt;/code&gt; 的实现子类即可，如&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt; 、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RegistryConfig&lt;/code&gt; 以及 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProtocolConfig&lt;/code&gt; 等&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;multiple()&lt;/code&gt; : 表明是否需要将&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefix()&lt;/code&gt;   作为多个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type()&lt;/code&gt;   类型的 Spring Bean 外部化配置属性。默认值为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;，即默认支持单个类型的 Spring 配置 Bean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;假设标注 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfigBinding&lt;/code&gt; 的实现类被 Spring 应用上下文扫描并且注册后，其中&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefix()&lt;/code&gt; =  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dubbo.app&lt;/code&gt; 、 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type()&lt;/code&gt; = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig.class&lt;/code&gt; ，且外部配置内容为：&lt;/p&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;py&quot;&gt;dubbo.app.id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;applicationBean&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.app.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Spring 应用上下文启动后，一个 ID 为 “applicationBean”   的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt;  Bean 被初始化，其 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; 字段被设置为 “dubbo-demo-application”。&lt;/p&gt;

&lt;h5 id=&quot;enabledubboconfigbindings-定义&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EnableDubboConfigBindings&lt;/code&gt; 定义&lt;/h5&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EnableDubboConfigBindings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;cm&quot;&gt;/**
     * The value of {@link EnableDubboConfigBindings}
     *
     * @return non-null
     */&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;EnableDubboConfigBinding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; : 指定多个&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EnableDubboConfigBinding&lt;/code&gt;，用于实现外部化配置属性前缀（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefix&lt;/code&gt;) 与 Dubbo 配置 Bean 类型（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AbstractConfig&lt;/code&gt; 子类）绑定。&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;示例说明-1&quot;&gt;示例说明&lt;/h4&gt;

&lt;h5 id=&quot;外部化配置文件-2&quot;&gt;外部化配置文件&lt;/h5&gt;

&lt;p&gt;将以下内容的外部化配置文件物理路径为：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;classpath:/META-INF/bindings.properties&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;c&quot;&gt;# classpath:/META-INF/bindings.properties
## 占位符值 : ApplicationConfig 外部配置属性前缀
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;applications.prefix&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo.apps.&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## 多 ApplicationConfig Bean 绑定
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.apps.applicationBean.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.apps.applicationBean2.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application2&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.apps.applicationBean3.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-application3&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## 单 ModuleConfig Bean 绑定
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.module.id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;moduleBean&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dubbo.module.name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dubbo-demo-module&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;## 单 RegistryConfig Bean 绑定
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;dubbo.registry.address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;zookeeper://192.168.99.100:32770&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;enabledubboconfigbindings-配置-bean&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EnableDubboConfigBindings&lt;/code&gt; 配置 Bean&lt;/h5&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DubboConfiguration&lt;/code&gt; 作为 Dubbo 配置 Bean，除通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@EnableDubboConfigBinding&lt;/code&gt; 绑定之外，还需要 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@PropertySource&lt;/code&gt; 指定外部化配置文件（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;classpath:/META-INF/bindings.properties&lt;/code&gt;）:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * Dubbo 配置 Bean
 *
 * @author &amp;lt;a href=&quot;mailto:mercyblitz@gmail.com&quot;&amp;gt;Mercy&amp;lt;/a&amp;gt;
 */&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@EnableDubboConfigBindings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;({&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;@EnableDubboConfigBinding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;${applications.prefix}&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;multiple&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 多 ApplicationConfig Bean 绑定&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;@EnableDubboConfigBinding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;dubbo.module&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 不带 &quot;.&quot; 后缀&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ModuleConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 单 ModuleConfig Bean 绑定&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;@EnableDubboConfigBinding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;dubbo.registry.&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 带 &quot;.&quot; 后缀&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RegistryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 单 RegistryConfig Bean 绑定&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@PropertySource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;META-INF/bindings.properties&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Configuration&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DubboConfiguration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;实现引导类-2&quot;&gt;实现引导类&lt;/h5&gt;

&lt;p&gt;通过之前的使用说明，当 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EnableDubboConfigBinding&lt;/code&gt; 将外部配置化文件&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;classpath:/META-INF/dubbo.properties&lt;/code&gt; 绑定到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApplicationConfig&lt;/code&gt;后，其中 Spring Bean “applicationBean” 的 name 字段被设置成 “dubbo-demo-application”。同时， &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EnableDubboConfigBinding&lt;/code&gt;  所标注的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DubboConfiguration&lt;/code&gt; 需要被 Sring 应用上下文注册：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * Dubbo 配置引导类
 *
 * @author &amp;lt;a href=&quot;mailto:mercyblitz@gmail.com&quot;&amp;gt;Mercy&amp;lt;/a&amp;gt;
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DubboConfigurationBootstrap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 创建配置上下文&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AnnotationConfigApplicationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 注册当前配置 Bean&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DubboConfiguration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;refresh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
 		&lt;span class=&quot;c1&quot;&gt;// 获取 ApplicationConfig Bean：&quot;applicationBean&quot;、&quot;applicationBean2&quot; 和 &quot;applicationBean3&quot;&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean2&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean3&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean2.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applicationBean3.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;applicationBean3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 获取 ModuleConfig Bean：&quot;moduleBean&quot;&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ModuleConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;moduleBean&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;moduleBean&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ModuleConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;moduleBean.name = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;moduleBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 获取 RegistryConfig Bean&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;RegistryConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RegistryConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;registry.address = %s \n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAddress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;运行结果&quot;&gt;运行结果&lt;/h5&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DubboConfigurationBootstrap&lt;/code&gt; 运行后控制台输出：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;applicationBean.name = dubbo-demo-application 
applicationBean2.name = dubbo-demo-application2 
applicationBean3.name = dubbo-demo-application3 
moduleBean.name = dubbo-demo-module 
registry.address = zookeeper://192.168.99.100:32770 
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;输出的内容与&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;classpath:/META-INF/bindings.properties&lt;/code&gt; 绑定的内容一致，符合期望。&lt;/p&gt;
</description>
        <pubDate>Thu, 18 Jan 2018 00:00:00 +0000</pubDate>
        <link>https://weibo.com/mercyblitz/2018/01/18/Dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE/</link>
        <guid isPermaLink="true">https://weibo.com/mercyblitz/2018/01/18/Dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE/</guid>
        
        
      </item>
    
  </channel>
</rss>
