<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>源码架构 on Apache Dubbo</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/</link><description>Recent content in 源码架构 on Apache Dubbo</description><generator>Hugo</generator><language>zh-cn</language><atom:link href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/index.xml" rel="self" type="application/rss+xml"/><item><title>单端口多协议实现原理解析</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol/</guid><description>&lt;p>通过对protocol进行配置，dubbo3可以支持端口的协议复用。
比如使用Triple协议启动端口复用后，可以在相同的端口上为服务增加
Dubbo协议支持，以及Qos协议支持。这些协议的识别都是由一个统一的端口复用
服务器进行处理的，可以用于服务的协议迁移，并且可以节约端口以及相关的资源，减少运维的复杂性。&lt;/p>
&lt;p>&lt;img alt="pu-server-image1" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/blog/pu-server/pu-server-flow.png">&lt;/p>
&lt;ul>
&lt;li>
&lt;p>在服务的创建阶段，通过从Config层获取到服务导出的协议配置从而创建不同的Protocol对象进行导出。在导出的过程
中，如果不是第一次创建端口复用的Server，那么Exchanger会将Protcol层传递的数据保存到Server，用于后续处理该协议类型的消息。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>当客户端的消息传递过来后，首先会通过Server传递给ProtocolDetector，如果完成了识别，那么就会标记该客户端为对应的协议。并通过WireProtocol配置对应的处理逻辑，最后交给ChannelOperator完成底层的IO框架和对应的Dubbo框架的处理逻辑的绑定。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>以上的协议识别完成之后，Channel已经确定了如何处理远程的客户端消息，通过对应的ServerPipeline进行处理即可（在处理的过程中也会根据配置信息决定消息的处理线程）。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="使用场景">使用场景&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>最常用的是用于服务发现。这允许应用程序通过网络发现服务，然后使用同一端口与它们通信，有助于降低网络通信的复杂性，并使其更易于管理。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>可以用于负载平衡。这允许应用程序在多个远程服务或服务集群之间平衡负载，有助于提高服务的可扩展性、可靠性和可用性。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>可以用于服务监控。这允许应用程序监视远程服务的运行状况，并在服务出现故障或变得不可用时发出警报，有助于确保服务的可用性并减少停机时间。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>参考用例
&lt;a href="https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification">https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-port-unification&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;h2 id="使用方式">使用方式&lt;/h2>
&lt;p>在同一主机上部署多个服务或需要通过负载均衡器访问多个服务。&lt;/p>
&lt;blockquote>
&lt;p>关于Dubbo支持的配置方式 &lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/config/">配置说明&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;h3 id="服务多协议导出">服务多协议导出&lt;/h3>
&lt;p>ext-protocol参数支持配置多个不同的协议，协议之间通过&amp;quot;,&amp;ldquo;进行分隔。&lt;/p>
&lt;h4 id="xml-配置">xml 配置&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:protocol&lt;/span> name=&lt;span style="color:#2aa198">&amp;#34;dubbo&amp;#34;&lt;/span> port=&lt;span style="color:#2aa198">&amp;#34;-1&amp;#34;&lt;/span> ext-protocol=&lt;span style="color:#2aa198">&amp;#34;tri,&amp;#34;&lt;/span>&lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;bean&lt;/span> id=&lt;span style="color:#2aa198">&amp;#34;greetingService&amp;#34;&lt;/span> class=&lt;span style="color:#2aa198">&amp;#34;org.apache.dubbo.demo.provider.GreetingServiceImpl&amp;#34;&lt;/span>&lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:service&lt;/span> delay=&lt;span style="color:#2aa198">&amp;#34;5000&amp;#34;&lt;/span> version=&lt;span style="color:#2aa198">&amp;#34;1.0.0&amp;#34;&lt;/span> group=&lt;span style="color:#2aa198">&amp;#34;greeting&amp;#34;&lt;/span> timeout=&lt;span style="color:#2aa198">&amp;#34;5000&amp;#34;&lt;/span> interface=&lt;span style="color:#2aa198">&amp;#34;org.apache.dubbo.demo.GreetingService&amp;#34;&lt;/span> ref=&lt;span style="color:#2aa198">&amp;#34;greetingService&amp;#34;&lt;/span> protocol=&lt;span style="color:#2aa198">&amp;#34;dubbo&amp;#34;&lt;/span>&lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="api-配置">API 配置&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>ProtocolConfig config &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ProtocolConfig(CommonConstants.TRIPLE, &lt;span style="color:#719e07">-&lt;/span>1);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>config.setExtProtocol(CommonConstants.DUBBO&lt;span style="color:#719e07">+&lt;/span>&lt;span style="color:#2aa198">&amp;#34;,&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="yaml-配置">yaml 配置&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">dubbo&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">application&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">name&lt;/span>: dubbo-springboot-demo-provider
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">protocol&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">name&lt;/span>: tri
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">port&lt;/span>: -&lt;span style="color:#2aa198">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">ext-protocol&lt;/span>: dubbo,
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="properties-配置">properties 配置&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>dubbo.protocol.name&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">tri&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dubbo.protocol.ext-protocol&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">dubbo,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dubbo.protocol.port&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">20880&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="qos接入">Qos接入&lt;/h3>
&lt;h4 id="qos模块导入">Qos模块导入&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;groupId&amp;gt;&lt;/span>org.apache.dubbo&lt;span style="color:#268bd2">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">&amp;lt;artifactId&amp;gt;&lt;/span>dubbo-qos&lt;span style="color:#268bd2">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;/dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>完成Qos模块的导入之后，相关的配置项可参考&lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/qos/overview/">Qos操作手册&lt;/a>进行配置。&lt;/p></description></item><item><title>代码架构</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/code-architecture/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/code-architecture/</guid><description>&lt;h2 id="整体设计">整体设计&lt;/h2>
&lt;p>&lt;img alt="/dev-guide/images/dubbo-framework.jpg" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/dev/dubbo-framework.jpg">&lt;/p>
&lt;p>图例说明：&lt;/p>
&lt;ul>
&lt;li>图中左边淡蓝背景的为服务消费方使用的接口，右边淡绿色背景的为服务提供方使用的接口，位于中轴线上的为双方都用到的接口。&lt;/li>
&lt;li>图中从下至上分为十层，各层均为单向依赖，右边的黑色箭头代表层之间的依赖关系，每一层都可以剥离上层被复用，其中，Service 和 Config 层为 API，其它各层均为 SPI。&lt;/li>
&lt;li>图中绿色小块的为扩展接口，蓝色小块为实现类，图中只显示用于关联各层的实现类。&lt;/li>
&lt;li>图中蓝色虚线为初始化过程，即启动时组装链，红色实线为方法调用过程，即运行时调用链，紫色三角箭头为继承，可以把子类看作父类的同一个节点，线上的文字为调用的方法。&lt;/li>
&lt;/ul>
&lt;h2 id="各层说明">各层说明&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Config 配置层&lt;/strong>：对外配置接口，以 &lt;code>ServiceConfig&lt;/code>, &lt;code>ReferenceConfig&lt;/code> 为中心，可以直接初始化配置类，也可以通过 spring 解析配置生成配置类&lt;/li>
&lt;li>&lt;strong>Proxy 服务代理层&lt;/strong>：服务接口透明代理，生成服务的客户端 Stub 和服务器端 Skeleton, 以 &lt;code>ServiceProxy&lt;/code> 为中心，扩展接口为 &lt;code>ProxyFactory&lt;/code>&lt;/li>
&lt;li>&lt;strong>Registry 注册中心层&lt;/strong>：封装服务地址的注册与发现，以服务 URL 为中心，扩展接口为 &lt;code>RegistryFactory&lt;/code>, &lt;code>Registry&lt;/code>, &lt;code>RegistryService&lt;/code>&lt;/li>
&lt;li>&lt;strong>Cluster 路由层&lt;/strong>：封装多个提供者的路由及负载均衡，并桥接注册中心，以 &lt;code>Invoker&lt;/code> 为中心，扩展接口为 &lt;code>Cluster&lt;/code>, &lt;code>Directory&lt;/code>, &lt;code>Router&lt;/code>, &lt;code>LoadBalance&lt;/code>&lt;/li>
&lt;li>&lt;strong>Monitor 监控层&lt;/strong>：RPC 调用次数和调用时间监控，以 &lt;code>Statistics&lt;/code> 为中心，扩展接口为 &lt;code>MonitorFactory&lt;/code>, &lt;code>Monitor&lt;/code>, &lt;code>MonitorService&lt;/code>&lt;/li>
&lt;li>&lt;strong>Protocol 远程调用层&lt;/strong>：封装 RPC 调用，以 &lt;code>Invocation&lt;/code>, &lt;code>Result&lt;/code> 为中心，扩展接口为 &lt;code>Protocol&lt;/code>, &lt;code>Invoker&lt;/code>, &lt;code>Exporter&lt;/code>&lt;/li>
&lt;li>&lt;strong>Exchange 信息交换层&lt;/strong>：封装请求响应模式，同步转异步，以 &lt;code>Request&lt;/code>, &lt;code>Response&lt;/code> 为中心，扩展接口为 &lt;code>Exchanger&lt;/code>, &lt;code>ExchangeChannel&lt;/code>, &lt;code>ExchangeClient&lt;/code>, &lt;code>ExchangeServer&lt;/code>&lt;/li>
&lt;li>&lt;strong>Transport 网络传输层&lt;/strong>：抽象 mina 和 netty 为统一接口，以 &lt;code>Message&lt;/code> 为中心，扩展接口为 &lt;code>Channel&lt;/code>, &lt;code>Transporter&lt;/code>, &lt;code>Client&lt;/code>, &lt;code>Server&lt;/code>, &lt;code>Codec&lt;/code>&lt;/li>
&lt;li>&lt;strong>Serialize 数据序列化层&lt;/strong>：可复用的一些工具，扩展接口为 &lt;code>Serialization&lt;/code>, &lt;code>ObjectInput&lt;/code>, &lt;code>ObjectOutput&lt;/code>, &lt;code>ThreadPool&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="关系说明">关系说明&lt;/h2>
&lt;ul>
&lt;li>在 RPC 中，Protocol 是核心层，也就是只要有 Protocol + Invoker + Exporter 就可以完成非透明的 RPC 调用，然后在 Invoker 的主过程上 Filter 拦截点。&lt;/li>
&lt;li>图中的 Consumer 和 Provider 是抽象概念，只是想让看图者更直观的了解哪些类分属于客户端与服务器端，不用 Client 和 Server 的原因是 Dubbo 在很多场景下都使用 Provider, Consumer, Registry, Monitor 划分逻辑拓扑节点，保持统一概念。&lt;/li>
&lt;li>而 Cluster 是外围概念，所以 Cluster 的目的是将多个 Invoker 伪装成一个 Invoker，这样其它人只要关注 Protocol 层 Invoker 即可，加上 Cluster 或者去掉 Cluster 对其它层都不会造成影响，因为只有一个提供者时，是不需要 Cluster 的。&lt;/li>
&lt;li>Proxy 层封装了所有接口的透明化代理，而在其它层都以 Invoker 为中心，只有到了暴露给用户使用时，才用 Proxy 将 Invoker 转成接口，或将接口实现转成 Invoker，也就是去掉 Proxy 层 RPC 是可以 Run 的，只是不那么透明，不那么看起来像调本地服务一样调远程服务。&lt;/li>
&lt;li>而 Remoting 实现是 Dubbo 协议的实现，如果你选择 RMI 协议，整个 Remoting 都不会用上，Remoting 内部再划为 Transport 传输层和 Exchange 信息交换层，Transport 层只负责单向消息传输，是对 Mina, Netty, Grizzly 的抽象，它也可以扩展 UDP 传输，而 Exchange 层是在传输层之上封装了 Request-Response 语义。&lt;/li>
&lt;li>Registry 和 Monitor 实际上不算一层，而是一个独立的节点，只是为了全局概览，用层的方式画在一起。&lt;/li>
&lt;/ul>
&lt;h2 id="模块分包">模块分包&lt;/h2>
&lt;p>&lt;img alt="/dev-guide/images/dubbo-modules.jpg" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/dev/dubbo-modules.jpg">&lt;/p></description></item><item><title>服务调用扩展点</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/service-invocation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/service-invocation/</guid><description>&lt;p>&lt;img alt="dubbo-architucture" src="https://deploy-preview-3199--dubbo.netlify.app/imgs/v3/concepts/invoke-arch.jpg">&lt;/p>
&lt;p>如上图所示，从服务调用的角度来看，Dubbo 在链路中提供了丰富的扩展点，覆盖了负载均衡方式、选址前后的拦截器、服务端处理拦截器等。
简单来说 Dubbo 发起远程调用的时候，主要工作流程可以分为消费端和服务端两个部分。&lt;/p>
&lt;p>消费端的工作流程如下：&lt;/p>
&lt;ul>
&lt;li>通过 Stub 接收来自用户的请求，并且封装在 &lt;code>Invocation&lt;/code> 对象中&lt;/li>
&lt;li>将 &lt;code>Invocation&lt;/code> 对象传递给 &lt;code>ClusterFilter&lt;/code>（&lt;strong>扩展点&lt;/strong>）做选址前的请求预处理，如请求参数的转换、请求日志记录、限流等操作都是在此阶段进行的&lt;/li>
&lt;li>将 &lt;code>Invocation&lt;/code> 对象传递给 &lt;code>Cluster&lt;/code>（&lt;strong>扩展点&lt;/strong>）进行集群调用逻辑的决策，如快速失败模式、安全失败模式等决策都是在此阶段进行的
&lt;ul>
&lt;li>&lt;code>Cluster&lt;/code> 调用 &lt;code>Directory&lt;/code> 获取所有可用的服务端地址信息&lt;/li>
&lt;li>&lt;code>Directory&lt;/code> 调用 &lt;code>StateRouter&lt;/code>（&lt;strong>扩展点&lt;/strong>，推荐使用） 和 &lt;code>Router&lt;/code>（&lt;strong>扩展点&lt;/strong>） 对服务端的地址信息进行路由筛选，此阶段主要是从全量的地址信息中筛选出本次调用允许调用到的目标，如基于打标的流量路由就是在此阶段进行的&lt;/li>
&lt;li>&lt;code>Cluster&lt;/code> 获得从 &lt;code>Directory&lt;/code> 提供的可用服务端信息后，会调用 &lt;code>LoadBalance&lt;/code> （&lt;strong>扩展点&lt;/strong>）从多个地址中选择出一个本次调用的目标，如随机调用、轮询调用、一致性哈希等策略都是在此阶段进行的&lt;/li>
&lt;li>&lt;code>Cluster&lt;/code> 获得目标的 &lt;code>Invoker&lt;/code> 以后将 &lt;code>Invocation&lt;/code> 传递给对应的 &lt;code>Invoker&lt;/code>，并等待返回结果，如果出现报错则执行对应的决策（如快速失败、安全失败等）&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>经过上面的处理，得到了带有目标地址信息的 &lt;code>Invoker&lt;/code>，会再调用 &lt;code>Filter&lt;/code>（&lt;strong>扩展点&lt;/strong>）进行选址后的请求处理（由于在消费端侧创建的 &lt;code>Filter&lt;/code> 数量级和服务端地址量级一致，如无特殊需要建议使用 &lt;code>ClusterFilter&lt;/code> 进行扩展拦截，以提高性能）&lt;/li>
&lt;li>最后 &lt;code>Invocation&lt;/code> 会被通过网络发送给服务端&lt;/li>
&lt;/ul>
&lt;p>服务端的工作流程如下：&lt;/p>
&lt;ul>
&lt;li>服务端通信层收到请求以后，会将请求传递给协议层构建出 &lt;code>Invocation&lt;/code>&lt;/li>
&lt;li>将 &lt;code>Invocation&lt;/code> 对象传递给 &lt;code>Filter&lt;/code> （&lt;strong>扩展点&lt;/strong>）做服务端请求的预处理，如服务端鉴权、日志记录、限流等操作都是在此阶段进行的&lt;/li>
&lt;li>将 &lt;code>Invocation&lt;/code> 对象传递给动态代理做真实的服务端调用&lt;/li>
&lt;/ul>
&lt;h2 id="filter拦截器">Filter（拦截器）&lt;/h2>
&lt;p>拦截器可以实现服务提供方和服务消费方调用过程拦截，Dubbo 本身的大多功能均基于此扩展点实现，每次远程方法执行，该拦截都会被执行，请注意对性能的影响。
其中在消费端侧，&lt;code>ClusterFilter&lt;/code> 用于选址前的拦截和 &lt;code>Filter&lt;/code> 用于选址后的拦截。如无特殊需要使用 &lt;code>ClusterFilter&lt;/code> 进行扩展拦截，以提高性能。&lt;/p></description></item><item><title>扩展点开发指南</title><link>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/</guid><description>&lt;h2 id="1-dubbo-spi-扩展简介">1. Dubbo SPI 扩展简介&lt;/h2>
&lt;p>Dubbo 中的扩展机制与 &lt;a href="https://www.baeldung.com/java-spi" target="_blank">JDK 标准的 SPI 扩展点&lt;/a> 原理类似。Dubbo 对其做了一定的改造与加强：&lt;/p>
&lt;ul>
&lt;li>JDK 标准的 SPI 会一次性实例化扩展点所有实现，如果有扩展实现初始化很耗时，但如果没用上也加载，会很浪费资源。&lt;/li>
&lt;li>如果扩展点加载失败，JDK SPI 没给出详细信息，不方便定位问题，Dubbo SPI 在失败时记录真正的失败原因，并打印出来&lt;/li>
&lt;li>增加 &lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#23-ioc-机制">IOC&lt;/a>、&lt;a href="https://deploy-preview-3199--dubbo.netlify.app/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#24-aop-机制">AOP&lt;/a> 能力&lt;/li>
&lt;li>增加排序能力&lt;/li>
&lt;li>增加条件激活能力&lt;/li>
&lt;li>提供了一系列更灵活的 API，如&lt;code>获取所有 SPI 扩展实现&lt;/code>、&lt;code>根据名称查询某个扩展实现&lt;/code>、根据类型查询扩展实现、查询匹配条件的扩展实现等。&lt;/li>
&lt;/ul>
&lt;h3 id="11-spi定义">1.1 SPI定义&lt;/h3>
&lt;p>Dubbo 中的 SPI 插件是标准的 Java Interface 定义，并且必须包含 &lt;code>@org.apache.dubbo.common.extension.SPI&lt;/code> 注解：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">@SPI&lt;/span>(value &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#2aa198">&amp;#34;dubbo&amp;#34;&lt;/span>, scope &lt;span style="color:#719e07">=&lt;/span> ExtensionScope.FRAMEWORK)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">interface&lt;/span> &lt;span style="color:#268bd2">Protocol&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>@SPI&lt;/code> 注解的定义如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">@Documented&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">@Retention&lt;/span>(RetentionPolicy.RUNTIME)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">@Target&lt;/span>({ElementType.TYPE})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">@interface&lt;/span> SPI {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * default extension name
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String &lt;span style="color:#268bd2">value&lt;/span>() &lt;span style="color:#719e07">default&lt;/span> &lt;span style="color:#2aa198">&amp;#34;&amp;#34;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * scope of SPI, default value is application scope.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ExtensionScope &lt;span style="color:#268bd2">scope&lt;/span>() &lt;span style="color:#719e07">default&lt;/span> ExtensionScope.APPLICATION;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="12-spi加载流程">1.2 SPI加载流程&lt;/h3>
&lt;p>Dubbo 加载扩展的整个流程如下：&lt;/p></description></item></channel></rss>