blob: 33697df6d02397552ed3c0ba66f9adf65c71228f [file] [log] [blame]
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Apache Dubbo – SPI 扩展实现</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/</link><description>Recent content in SPI 扩展实现 on Apache Dubbo</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><atom:link href="https://dubbo.apache.org/zh-cn/docs/references/spis/index.xml" rel="self" type="application/rss+xml"/><item><title>Docs: 协议扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/protocol/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/protocol/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/protocol/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>RPC 协议扩展,封装远程调用细节。&lt;/p>
&lt;p>契约:&lt;/p>
&lt;ul>
&lt;li>当用户调用 &lt;code>refer()&lt;/code> 所返回的 &lt;code>Invoker&lt;/code> 对象的 &lt;code>invoke()&lt;/code> 方法时,协议需相应执行同 URL 远端 &lt;code>export()&lt;/code> 传入的 &lt;code>Invoker&lt;/code> 对象的 &lt;code>invoke()&lt;/code> 方法。&lt;/li>
&lt;li>其中,&lt;code>refer()&lt;/code> 返回的 &lt;code>Invoker&lt;/code> 由协议实现,协议通常需要在此 &lt;code>Invoker&lt;/code> 中发送远程请求,&lt;code>export()&lt;/code> 传入的 &lt;code>Invoker&lt;/code> 由框架实现并传入,协议不需要关心。&lt;/li>
&lt;/ul>
&lt;p>注意:&lt;/p>
&lt;ul>
&lt;li>协议不关心业务接口的透明代理,以 &lt;code>Invoker&lt;/code> 为中心,由外层将 &lt;code>Invoker&lt;/code> 转换为业务接口。&lt;/li>
&lt;li>协议不一定要是 TCP 网络通讯,比如通过共享文件,IPC 进程间通讯等。&lt;/li>
&lt;/ul>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.rpc.Protocol&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.Exporter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.Invoker&lt;/code>&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &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 style="color:#586e75"> * 暴露远程服务:&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 1. 协议在接收请求时,应记录请求来源方地址信息:RpcContext.getContext().setRemoteAddress();&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 2. export()必须是幂等的,也就是暴露同一个URL的Invoker两次,和暴露一次没有区别。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 3. export()传入的Invoker由框架实现并传入,协议不需要关心。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param &amp;lt;T&amp;gt; 服务的类型
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param invoker 服务的执行体
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return exporter 暴露服务的引用,用于取消暴露
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @throws RpcException 当暴露服务出错时抛出,比如端口已占用
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Exporter&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">export&lt;/span>(Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> invoker) &lt;span style="color:#268bd2">throws&lt;/span> RpcException;
&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"> * 引用远程服务:&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 1. 当用户调用refer()所返回的Invoker对象的invoke()方法时,协议需相应执行同URL远端export()传入的Invoker对象的invoke()方法。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 2. refer()返回的Invoker由协议实现,协议通常需要在此Invoker中发送远程请求。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 3. 当url中有设置check=false时,连接失败不能抛出异常,需内部自动恢复。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param &amp;lt;T&amp;gt; 服务的类型
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param type 服务的类型
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param url 远程服务的URL地址
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return invoker 服务的本地代理
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @throws RpcException 当连接服务提供方失败时抛出
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">refer&lt;/span>(Class&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> type, URL url) &lt;span style="color:#268bd2">throws&lt;/span> RpcException;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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:#586e75">&amp;lt;!-- 声明协议,如果没有配置id,将以name为id --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:protocol&lt;/span> id=&lt;span style="color:#2aa198">&amp;#34;xxx1&amp;#34;&lt;/span> name=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 引用协议,如果没有配置protocol属性,将在ApplicationContext中自动扫描protocol配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:service&lt;/span> protocol=&lt;span style="color:#2aa198">&amp;#34;xxx1&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 引用协议缺省值,当&amp;lt;dubbo:service&amp;gt;没有配置prototol属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> protocol=&lt;span style="color:#2aa198">&amp;#34;xxx1&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.protocol.rmi.RmiProtocol&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.protocol.http.HttpProtocol&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.protocol.http.hessian.HessianProtocol&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.support.MockProtocol&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxProtocol.java (实现Protocol接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxExporter.java (实现Exporter接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxInvoker.java (实现Invoker接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.rpc.Protocol (纯文本文件,内容为:xxx=com.xxx.XxxProtocol)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxProtocol.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Protocol;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxProtocol&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Protocol {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Exporter&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">export&lt;/span>(Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> invoker) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> XxxExporter(invoker);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">refer&lt;/span>(Class&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> type, URL url) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> XxxInvoker(type, url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxExporter.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.support.AbstractExporter;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxExporter&lt;/span>&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">extends&lt;/span> AbstractExporter&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">XxxExporter&lt;/span>(Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> invoker) &lt;span style="color:#268bd2">throws&lt;/span> RemotingException{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">super&lt;/span>(invoker);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">unexport&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">super&lt;/span>.unexport();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxInvoker.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.support.AbstractInvoker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxInvoker&lt;/span>&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">extends&lt;/span> AbstractInvoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">XxxInvoker&lt;/span>(Class&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> type, URL url) &lt;span style="color:#268bd2">throws&lt;/span> RemotingException{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">super&lt;/span>(type, url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">protected&lt;/span> Result &lt;span style="color:#268bd2">doInvoke&lt;/span>(Invocation invocation) &lt;span style="color:#268bd2">throws&lt;/span> Throwable {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.rpc.Protocol:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxProtocol&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 调用拦截扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/filter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/filter/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/filter/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>服务提供方和服务消费方调用过程拦截,Dubbo 本身的大多功能均基于此扩展点实现,每次远程方法执行,该拦截都会被执行,请注意对性能的影响。&lt;/p>
&lt;p>约定:&lt;/p>
&lt;ul>
&lt;li>用户自定义 filter 默认在内置 filter 之后。&lt;/li>
&lt;li>特殊值 &lt;code>default&lt;/code>,表示缺省扩展点插入的位置。比如:&lt;code>filter=&amp;quot;xxx,default,yyy&amp;quot;&lt;/code>,表示 &lt;code>xxx&lt;/code> 在缺省 filter 之前,&lt;code>yyy&lt;/code> 在缺省 filter 之后。&lt;/li>
&lt;li>特殊符号 &lt;code>-&lt;/code>,表示剔除。比如:&lt;code>filter=&amp;quot;-foo1&amp;quot;&lt;/code>,剔除添加缺省扩展点 &lt;code>foo1&lt;/code>。比如:&lt;code>filter=&amp;quot;-default&amp;quot;&lt;/code>,剔除添加所有缺省扩展点。&lt;/li>
&lt;li>provider 和 service 同时配置的 filter 时,累加所有 filter,而不是覆盖。比如:&lt;code>&amp;lt;dubbo:provider filter=&amp;quot;xxx,yyy&amp;quot;/&amp;gt;&lt;/code> 和 &lt;code>&amp;lt;dubbo:service filter=&amp;quot;aaa,bbb&amp;quot; /&amp;gt;&lt;/code>,则 &lt;code>xxx&lt;/code>,&lt;code>yyy&lt;/code>,&lt;code>aaa&lt;/code>,&lt;code>bbb&lt;/code> 均会生效。如果要覆盖,需配置:&lt;code>&amp;lt;dubbo:service filter=&amp;quot;-xxx,-yyy,aaa,bbb&amp;quot; /&amp;gt;&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.rpc.Filter&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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:#586e75">&amp;lt;!-- 消费方调用过程拦截 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:reference&lt;/span> filter=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 消费方调用过程缺省拦截器,将拦截所有reference --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:consumer&lt;/span> filter=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span>&lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 提供方调用过程拦截 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:service&lt;/span> filter=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 提供方调用过程缺省拦截器,将拦截所有service --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> filter=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span>&lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.EchoFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.GenericFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.GenericImplFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.TokenFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.AccessLogFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.CountFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.ActiveLimitFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.ClassLoaderFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.ContextFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.ConsumerContextFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.ExceptionFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.ExecuteLimitFilter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.filter.DeprecatedFilter&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxFilter.java (实现Filter接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.rpc.Filter (纯文本文件,内容为:xxx=com.xxx.XxxFilter)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxFilter.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Filter;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Invoker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Invocation;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Result;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.RpcException;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxFilter&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Filter {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Result &lt;span style="color:#268bd2">invoke&lt;/span>(Invoker&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> invoker, Invocation invocation) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// before filter ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Result result &lt;span style="color:#719e07">=&lt;/span> invoker.invoke(invocation);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// after filter ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> result;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.rpc.Filter:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxFilter&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 引用监听扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/invoker-listener/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/invoker-listener/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/invoker-listener/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>当有服务引用时,触发该事件。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.rpc.InvokerListener&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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:#586e75">&amp;lt;!-- 引用服务监听 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:reference&lt;/span> listener=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 引用服务缺省监听器 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:consumer&lt;/span> listener=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.rpc.listener.DeprecatedInvokerListener&lt;/code>&lt;/p>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxInvokerListener.java (实现InvokerListener接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.rpc.InvokerListener (纯文本文件,内容为:xxx=com.xxx.XxxInvokerListener)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxInvokerListener.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.InvokerListener;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Invoker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.RpcException;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxInvokerListener&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> InvokerListener {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">referred&lt;/span>(Invoker&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> invoker) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">destroyed&lt;/span>(Invoker&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> invoker) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.rpc.InvokerListener:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxInvokerListener&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 暴露监听扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/exporter-listener/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/exporter-listener/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/exporter-listener/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>当有服务暴露时,触发该事件。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.rpc.ExporterListener&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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:#586e75">&amp;lt;!-- 暴露服务监听 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:service&lt;/span> listener=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 暴露服务缺省监听器 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> listener=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.registry.directory.RegistryExporterListener&lt;/code>&lt;/p>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxExporterListener.java (实现ExporterListener接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.rpc.ExporterListener (纯文本文件,内容为:xxx=com.xxx.XxxExporterListener)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxExporterListener.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.ExporterListener;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Exporter;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.RpcException;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxExporterListener&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> ExporterListener {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">exported&lt;/span>(Exporter&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> exporter) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">unexported&lt;/span>(Exporter&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> exporter) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.rpc.ExporterListener:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxExporterListener&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 集群扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/cluster/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/cluster/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/cluster/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>当有多个服务提供方时,将多个服务提供方组织成一个集群,并伪装成一个提供方。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.rpc.cluster.Cluster&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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> cluster=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值配置,如果&amp;lt;dubbo:protocol&amp;gt;没有配置cluster时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> cluster=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.support.FailoverCluster&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.support.FailfastCluster&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.support.FailsafeCluster&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.support.FailbackCluster&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.support.ForkingCluster&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.support.AvailableCluster&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.support.MergeableCluster&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.support.BroadcastCluster&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxCluster.java (实现Cluster接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.rpc.cluster.Cluster (纯文本文件,内容为:xxx=com.xxx.XxxCluster)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxCluster.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.cluster.Cluster;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.cluster.Directory;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.cluster.LoadBalance;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Invoker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Invocation;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Result;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.RpcException;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxCluster&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Cluster {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">merge&lt;/span>(Directory&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> directory) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> AbstractClusterInvoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span>(directory) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Result &lt;span style="color:#268bd2">doInvoke&lt;/span>(Invocation invocation, List&lt;span style="color:#719e07">&amp;lt;&lt;/span>Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&amp;gt;&lt;/span> invokers, LoadBalance loadbalance) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> };
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.rpc.cluster.Cluster:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxCluster&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 路由扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/router/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/router/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/router/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>从多个服务提供方中选择一个进行调用。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.RouterFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.Router&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.router.ScriptRouterFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.router.FileRouterFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.router.condition.config.AppRouterFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.CacheableRouterFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.router.mock.MockRouterFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouterFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.router.tag.TagRouterFactory&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxRouterFactory.java (实现RouterFactory接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.rpc.cluster.RouterFactory (纯文本文件,内容为:xxx=com.xxx.XxxRouterFactory)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxRouterFactory.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.cluster.RouterFactory;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Invoker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Invocation;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.RpcException;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxRouterFactory&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> RouterFactory {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Router &lt;span style="color:#268bd2">getRouter&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.rpc.cluster.RouterFactory:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxRouterFactory&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 负载均衡扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/load-balance/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/load-balance/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/load-balance/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>从多个服务提供方中选择一个进行调用&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.rpc.cluster.LoadBalance&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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> loadbalance=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:protocol&amp;gt;没有配置loadbalance时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> loadbalance=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.loadbalance.ShortestResponseLoadBalance&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxLoadBalance.java (实现LoadBalance接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.rpc.cluster.LoadBalance (纯文本文件,内容为:xxx=com.xxx.XxxLoadBalance)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxLoadBalance.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.cluster.LoadBalance;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Invoker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Invocation;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.RpcException;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxLoadBalance&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> LoadBalance {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">select&lt;/span>(List&lt;span style="color:#719e07">&amp;lt;&lt;/span>Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&amp;gt;&lt;/span> invokers, Invocation invocation) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxLoadBalance&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 合并结果扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/merger/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/merger/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/merger/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>合并返回结果,用于分组聚合。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.rpc.cluster.Merger&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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:method&lt;/span> merger=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.ArrayMerger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.ListMerger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.SetMerger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.MapMerger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.ByteArrayMerger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.CharArrayMerger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.ShortArrayMerger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.IntArrayMerger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.LongArrayMerger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.FloatArrayMerger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.DoubleArrayMerger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.cluster.merger.BooleanArrayMerger&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxMerger.java (实现Merger接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.rpc.cluster.Merger (纯文本文件,内容为:xxx=com.xxx.XxxMerger)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxMerger.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.cluster.Merger;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxMerger&lt;/span>&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Merger&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> T &lt;span style="color:#268bd2">merge&lt;/span>(T... results) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.rpc.cluster.Merger:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxMerger&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 注册中心扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/registry/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/registry/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/registry/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>负责服务的注册与发现。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.registry.RegistryFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.registry.Registry&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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:#586e75">&amp;lt;!-- 定义注册中心 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:registry&lt;/span> id=&lt;span style="color:#2aa198">&amp;#34;xxx1&amp;#34;&lt;/span> address=&lt;span style="color:#2aa198">&amp;#34;xxx://ip:port&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 引用注册中心,如果没有配置registry属性,将在ApplicationContext中自动扫描registry配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:service&lt;/span> registry=&lt;span style="color:#2aa198">&amp;#34;xxx1&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 引用注册中心缺省值,当&amp;lt;dubbo:service&amp;gt;没有配置registry属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> registry=&lt;span style="color:#2aa198">&amp;#34;xxx1&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="扩展契约">扩展契约&lt;/h2>
&lt;p>RegistryFactory.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">interface&lt;/span> &lt;span style="color:#268bd2">RegistryFactory&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 连接注册中心.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 连接注册中心需处理契约:&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 1. 当设置check=false时表示不检查连接,否则在连接不上时抛出异常。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 2. 支持URL上的username:password权限认证。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 3. 支持backup=10.20.153.10备选注册中心集群地址。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 4. 支持file=registry.cache本地磁盘文件缓存。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 5. 支持timeout=1000请求超时设置。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 6. 支持session=60000会话超时或过期设置。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param url 注册中心地址,不允许为空
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return 注册中心引用,总不返回空
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Registry &lt;span style="color:#268bd2">getRegistry&lt;/span>(URL url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>RegistryService.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">interface&lt;/span> &lt;span style="color:#268bd2">RegistryService&lt;/span> { &lt;span style="color:#586e75">// Registry extends RegistryService &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 注册服务.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 注册需处理契约:&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 1. 当URL设置了check=false时,注册失败后不报错,在后台定时重试,否则抛出异常。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 2. 当URL设置了dynamic=false参数,则需持久存储,否则,当注册者出现断电等情况异常退出时,需自动删除。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 3. 当URL设置了category=overrides时,表示分类存储,缺省类别为providers,可按分类部分通知数据。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 4. 当注册中心重启,网络抖动,不能丢失数据,包括断线自动删除数据。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 5. 允许URI相同但参数不同的URL并存,不能覆盖。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param url 注册信息,不允许为空,如:dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&amp;amp;application=kylin
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">register&lt;/span>(URL url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 取消注册服务.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 取消注册需处理契约:&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 1. 如果是dynamic=false的持久存储数据,找不到注册数据,则抛IllegalStateException,否则忽略。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 2. 按全URL匹配取消注册。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param url 注册信息,不允许为空,如:dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&amp;amp;application=kylin
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">unregister&lt;/span>(URL url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 订阅服务.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 订阅需处理契约:&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 1. 当URL设置了check=false时,订阅失败后不报错,在后台定时重试。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 2. 当URL设置了category=overrides,只通知指定分类的数据,多个分类用逗号分隔,并允许星号通配,表示订阅所有分类数据。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 3. 允许以interface,group,version,classifier作为条件查询,如:interface=com.alibaba.foo.BarService&amp;amp;version=1.0.0&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 4. 并且查询条件允许星号通配,订阅所有接口的所有分组的所有版本,或:interface=*&amp;amp;group=*&amp;amp;version=*&amp;amp;classifier=*&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 5. 当注册中心重启,网络抖动,需自动恢复订阅请求。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 6. 允许URI相同但参数不同的URL并存,不能覆盖。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 7. 必须阻塞订阅过程,等第一次通知完后再返回。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param url 订阅条件,不允许为空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&amp;amp;application=kylin
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param listener 变更事件监听器,不允许为空
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">subscribe&lt;/span>(URL url, NotifyListener listener);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 取消订阅服务.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 取消订阅需处理契约:&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 1. 如果没有订阅,直接忽略。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 2. 按全URL匹配取消订阅。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param url 订阅条件,不允许为空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&amp;amp;application=kylin
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param listener 变更事件监听器,不允许为空
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">unsubscribe&lt;/span>(URL url, NotifyListener listener);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 查询注册列表,与订阅的推模式相对应,这里为拉模式,只返回一次结果。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @see org.apache.dubbo.registry.NotifyListener#notify(List)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param url 查询条件,不允许为空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&amp;amp;application=kylin
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @return 已注册信息列表,可能为空,含义同{@link org.apache.dubbo.registry.NotifyListener#notify(List&amp;lt;URL&amp;gt;)}的参数。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> List&lt;span style="color:#719e07">&amp;lt;&lt;/span>URL&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">lookup&lt;/span>(URL url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>NotifyListener.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">interface&lt;/span> &lt;span style="color:#268bd2">NotifyListener&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 当收到服务变更通知时触发。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 通知需处理契约:&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 1. 总是以服务接口和数据类型为维度全量通知,即不会通知一个服务的同类型的部分数据,用户不需要对比上一次通知结果。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 2. 订阅时的第一次通知,必须是一个服务的所有类型数据的全量通知。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 3. 中途变更时,允许不同类型的数据分开通知,比如:providers, consumers, routes, overrides,允许只通知其中一种类型,但该类型的数据必须是全量的,不是增量的。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 4. 如果一种类型的数据为空,需通知一个empty协议并带category参数的标识性URL数据。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * 5. 通知者(即注册中心实现)需保证通知的顺序,比如:单线程推送,队列串行化,带版本对比。&amp;lt;br&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> * @param urls 已注册信息列表,总不为空,含义同{@link org.apache.dubbo.registry.RegistryService#lookup(URL)}的返回值。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">notify&lt;/span>(List&lt;span style="color:#719e07">&amp;lt;&lt;/span>URL&lt;span style="color:#719e07">&amp;gt;&lt;/span> urls);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.registry.support.dubbo.DubboRegistryFactory&lt;/code>&lt;/p>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxRegistryFactoryjava (实现RegistryFactory接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxRegistry.java (实现Registry接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.registry.RegistryFactory (纯文本文件,内容为:xxx=com.xxx.XxxRegistryFactory)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxRegistryFactory.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.registry.RegistryFactory;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.registry.Registry;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.URL;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxRegistryFactory&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> RegistryFactory {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Registry &lt;span style="color:#268bd2">getRegistry&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> XxxRegistry(url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxRegistry.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.registry.Registry;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.registry.NotifyListener;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.URL;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxRegistry&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Registry {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">register&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">unregister&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">subscribe&lt;/span>(URL url, NotifyListener listener) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">unsubscribe&lt;/span>(URL url, NotifyListener listener) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.registry.RegistryFactory:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxRegistryFactory&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 监控中心扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/monitor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/monitor/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/monitor/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>负责服务调用次和调用时间的监控。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.monitor.MonitorFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.monitor.Monitor&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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:#586e75">&amp;lt;!-- 定义监控中心 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:monitor&lt;/span> address=&lt;span style="color:#2aa198">&amp;#34;xxx://ip:port&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;p>org.apache.dubbo.monitor.support.dubbo.DubboMonitorFactory&lt;/p>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxMonitorFactoryjava (实现MonitorFactory接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxMonitor.java (实现Monitor接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.monitor.MonitorFactory (纯文本文件,内容为:xxx=com.xxx.XxxMonitorFactory)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxMonitorFactory.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.monitor.MonitorFactory;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.monitor.Monitor;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.URL;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxMonitorFactory&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> MonitorFactory {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Monitor &lt;span style="color:#268bd2">getMonitor&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> XxxMonitor(url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxMonitor.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.monitor.Monitor;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxMonitor&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Monitor {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">count&lt;/span>(URL statistics) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.monitor.MonitorFactory:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxMonitorFactory&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 扩展点加载扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/extension-factory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/extension-factory/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/extension-factory/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>扩展点本身的加载容器,可从不同容器加载扩展点。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.common.extension.ExtensionFactory&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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:application&lt;/span> compiler=&lt;span style="color:#2aa198">&amp;#34;jdk&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.common.extension.factory.SpiExtensionFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.config.spring.extension.SpringExtensionFactory&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxExtensionFactory.java (实现ExtensionFactory接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.common.extension.ExtensionFactory (纯文本文件,内容为:xxx=com.xxx.XxxExtensionFactory)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxExtensionFactory.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.extension.ExtensionFactory;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxExtensionFactory&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> ExtensionFactory {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Object &lt;span style="color:#268bd2">getExtension&lt;/span>(Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> type, String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.common.extension.ExtensionFactory:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxExtensionFactory&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 动态代理扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/proxy-factory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/proxy-factory/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/proxy-factory/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>将 &lt;code>Invoker&lt;/code> 接口转换成业务接口。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.rpc.ProxyFactory&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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> proxy=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值配置,当&amp;lt;dubbo:protocol&amp;gt;没有配置proxy属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> proxy=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.rpc.proxy.JdkProxyFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.proxy.JavassistProxyFactory&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxProxyFactory.java (实现ProxyFactory接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.rpc.ProxyFactory (纯文本文件,内容为:xxx=com.xxx.XxxProxyFactory)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxProxyFactory.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.ProxyFactory;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.Invoker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.rpc.RpcException;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxProxyFactory&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> ProxyFactory {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> T &lt;span style="color:#268bd2">getProxy&lt;/span>(Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> invoker) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">getInvoker&lt;/span>(T proxy, Class&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> type, URL url) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.rpc.ProxyFactory:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxProxyFactory&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 编译器扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/compiler/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/compiler/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/compiler/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>Java 代码编译器,用于动态生成字节码,加速调用。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.common.compiler.Compiler&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&lt;p>自动加载&lt;/p>
&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.common.compiler.support.JdkCompiler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.compiler.support.JavassistCompiler&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxCompiler.java (实现Compiler接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.common.compiler.Compiler (纯文本文件,内容为:xxx=com.xxx.XxxCompiler)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxCompiler.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.compiler.Compiler;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxCompiler&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Compiler {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Object &lt;span style="color:#268bd2">getExtension&lt;/span>(Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> type, String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.common.compiler.Compiler:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxCompiler&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 配置中心扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/config-center/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/config-center/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/config-center/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="设计目的">设计目的&lt;/h2>
&lt;p>配置中心的核心功能是作为 Key-Value 存储,Dubbo 框架告知配置中心其关心的 key,配置中心返回该key对应的 value 值。&lt;/p>
&lt;p>按照应用场景划分,配置中心在 Dubbo 框架中主要承担以下职责:&lt;/p>
&lt;ul>
&lt;li>作为外部化配置中心,即存储 dubbo.properties 配置文件,此时,key 值通常为文件名如 dubbo.properties,value 则为配置文件内容。&lt;/li>
&lt;li>存储单个配置项,如各种开关项、常量值等。&lt;/li>
&lt;li>存储服务治理规则,此时key通常按照 &amp;ldquo;服务名+规则类型&amp;rdquo; 的格式来组织,而 value 则为具体的治理规则。&lt;/li>
&lt;/ul>
&lt;p>为了进一步实现对 key-value 的分组管理,Dubbo 的配置中心还加入了 namespace、group 的概念,这些概念在很多专业的第三方配置中心中都有体现,通常情况下,namespace 用来隔离不同的租户,group 用来对同一租户的key集合做分组。&lt;/p>
&lt;p>当前,Dubbo 配置中心实现了对 Zookeeper、Nacos、Etcd、Consul、Apollo 的对接,接下来我们具体看一下 Dubbo 抽象的配置中心是怎么映射到具体的第三方实现中的。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.configcenter.DynamicConfigurationFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.configcenter.DynamicConfiguration&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.configcenter.support.nacos.NacosDynamicConfigurationFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.configcenter.support.etcd.EtcdDynamicConfigurationFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.configcenter.consul.ConsulDynamicConfigurationFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.configcenter.support.apollo.ApolloDynamicConfigurationFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfigurationFactory&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="实现原理">实现原理&lt;/h2>
&lt;h3 id="zookeeper">Zookeeper&lt;/h3>
&lt;p>zookeeper提供了一个树状的存储模型,其实现原理如下:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/dev/configcenter_zk_model.jpg" alt="image-20190127225608553">&lt;/p>
&lt;p>namespace, group, key 等分别对应不同层级的 ZNode 节点,而 value 则作为根 ZNode 节点的值存储。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>外部化配置中心 dubbo.properties&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/dev/configcenter_zk_properties.jpg" alt="image-20190127225608553">&lt;/p>
&lt;p>上图展示了两个不同作用域的 dubbo.properties 文件在 zookeeper 中的存储结构:&lt;/p>
&lt;ul>
&lt;li>命名空间namespace都为:dubbo&lt;/li>
&lt;li>分组 group:全局级别为 dubbo,所有应用共享;应用级别为应用名 demo-provider,只对该应用生效&lt;/li>
&lt;li>key:dubbo.properties&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>单个配置项&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/dev/configcenter_zk_singleitem.jpg" alt="image-20190127225608553">&lt;/p>
&lt;p>设置优雅停机事件为15000:&lt;/p>
&lt;ul>
&lt;li>命名空间 namespace:dubbo&lt;/li>
&lt;li>分组 group:dubbo&lt;/li>
&lt;li>key:dubbo.service.shutdown.wait&lt;/li>
&lt;li>value:15000&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>服务治理规则&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/dev/configcenter_zk_rule.jpg" alt="image-20190127225608553">&lt;/p>
&lt;p>上图展示了一条应用级别的条件路由规则:&lt;/p>
&lt;ul>
&lt;li>命名空间 namespace:dubbo&lt;/li>
&lt;li>分组 group:dubbo&lt;/li>
&lt;li>key:governance-conditionrouter-consumer.condition-router,其中 governance-conditionrouter-consumer 为应用名,condition-router 代表条件路由&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>注意:&lt;/p>
&lt;p>Dubbo同时支持应用、服务两种粒度的服务治理规则,对于这两种粒度,其key取值规则如下:&lt;/p>
&lt;ul>
&lt;li>应用粒度 {应用名 + 规则后缀}。如: &lt;code>demo-application.configurators&lt;/code>、&lt;code>demo-application.tag-router&lt;/code>等&lt;/li>
&lt;li>服务粒度 {服务接口名:[服务版本]:[服务分组] + 规则后缀},其中服务版本、服务分组是可选的,如果它们有配置则在key中体现,没被配置则用&amp;quot;:&amp;ldquo;占位。如
&lt;code>org.apache.dubbo.demo.DemoService::.configurators&lt;/code>、&lt;code>org.apache.dubbo.demo.DemoService:1.0.0:group1.configurators&lt;/code>&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;/li>
&lt;/ol>
&lt;h3 id="etcd--consul">Etcd &amp;amp; Consul&lt;/h3>
&lt;p>Etcd 和 Consul 本质上也是一种类似 zookeeper 的树状存储结构,实现请参考 zookeeper。&lt;/p>
&lt;h3 id="nacos">Nacos&lt;/h3>
&lt;p>&lt;a href="https://nacos.io/">Nacos&lt;/a> 作为一个专业的第三方配置中心,拥有专门为配置中心设计的存储结构,包括内置的 namespace、group、dataid 等概念。并且这几个概念基本上与 Dubbo 框架抽象的配置中心是一一对应的。&lt;/p>
&lt;p>与 Zookeeper 实现的对应关系如下:&lt;/p>
&lt;p>&lt;img src="https://dubbo.apache.org/imgs/dev/configcenter_nacos_model.jpg" alt="image-20190127225608553">&lt;/p>
&lt;p>参考上文关于 zookeeper 实现中描述的示例,这里的 dataid 可能为:&lt;/p>
&lt;ul>
&lt;li>外部化配置中心:dubbo.properties&lt;/li>
&lt;li>单个配置项:dubbo.service.shutdown.wait&lt;/li>
&lt;li>服务治理规则:org.apache.dubbo.demo.DemoService:1.0.0:group1.configurators&lt;/li>
&lt;/ul>
&lt;h3 id="apollo">Apollo&lt;/h3>
&lt;p>Apollo 与 Nacos 类似,请参考动态配置中心使用文档中关于 Apollo 部分的描述。&lt;/p></description></item><item><title>Docs: 消息派发扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/dispatcher/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/dispatcher/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/dispatcher/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>通道信息派发器,用于指定线程池模型。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.remoting.Dispatcher&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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> dispatcher=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:protocol&amp;gt;没有配置dispatcher属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> dispatcher=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.remoting.transport.dispatcher.all.AllDispatcher&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.transport.dispatcher.direct.DirectDispatcher&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.transport.dispatcher.message.MessageOnlyDispatcher&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.transport.dispatcher.execution.ExecutionDispatcher&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.transport.dispatcher.connection.ConnectionOrderedDispatcher&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxDispatcher.java (实现Dispatcher接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.remoting.Dispatcher (纯文本文件,内容为:xxx=com.xxx.XxxDispatcher)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxDispatcher.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.remoting.Dispatcher;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxDispatcher&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Dispatcher {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Group &lt;span style="color:#268bd2">lookup&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.remoting.Dispatcher:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxDispatcher&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 线程池扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/threadpool/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/threadpool/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/threadpool/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>服务提供方线程池实现策略,当服务器收到一个请求时,需要在线程池中创建一个线程去执行服务提供方业务逻辑。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.common.threadpool.ThreadPool&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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> threadpool=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:protocol&amp;gt;没有配置threadpool时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> threadpool=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.common.threadpool.FixedThreadPool&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.threadpool.CachedThreadPool&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxThreadPool.java (实现ThreadPool接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.common.threadpool.ThreadPool (纯文本文件,内容为:xxx=com.xxx.XxxThreadPool)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxThreadPool.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.threadpool.ThreadPool;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> java.util.concurrent.Executor;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxThreadPool&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> ThreadPool {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Executor &lt;span style="color:#268bd2">getExecutor&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.common.threadpool.ThreadPool:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxThreadPool&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 序列化扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/serialize/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/serialize/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/serialize/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>将对象转成字节流,用于网络传输,以及将字节流转为对象,用于在收到字节流数据后还原成对象。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.common.serialize.Serialization&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.serialize.ObjectInput&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.serialize.ObjectOutput&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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:#586e75">&amp;lt;!-- 协议的序列化方式 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:protocol&lt;/span> serialization=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:protocol&amp;gt;没有配置serialization时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> serialization=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.common.serialize.dubbo.DubboSerialization&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.serialize.hessian.Hessian2Serialization&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.serialize.java.JavaSerialization&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.serialize.java.CompactedJavaSerialization&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxSerialization.java (实现Serialization接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxObjectInput.java (实现ObjectInput接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxObjectOutput.java (实现ObjectOutput接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.common.serialize.Serialization (纯文本文件,内容为:xxx=com.xxx.XxxSerialization)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxSerialization.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.serialize.Serialization;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.serialize.ObjectInput;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.serialize.ObjectOutput;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxSerialization&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Serialization {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> ObjectOutput &lt;span style="color:#268bd2">serialize&lt;/span>(Parameters parameters, OutputStream output) &lt;span style="color:#268bd2">throws&lt;/span> IOException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> XxxObjectOutput(output);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> ObjectInput &lt;span style="color:#268bd2">deserialize&lt;/span>(Parameters parameters, InputStream input) &lt;span style="color:#268bd2">throws&lt;/span> IOException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> XxxObjectInput(input);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.common.serialize.Serialization:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxSerialization&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 网络传输扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/remoting/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/remoting/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/remoting/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>远程通讯的服务器及客户端传输实现。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.remoting.Transporter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.Server&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.Client&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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:#586e75">&amp;lt;!-- 服务器和客户端使用相同的传输实现 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:protocol&lt;/span> transporter=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 服务器和客户端使用不同的传输实现 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:protocol&lt;/span> server=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> client=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:protocol&amp;gt;没有配置transporter/server/client属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> transporter=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> server=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> client=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.remoting.transport.transporter.netty.NettyTransporter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.transport.transporter.mina.MinaTransporter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.transport.transporter.grizzly.GrizzlyTransporter&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxTransporter.java (实现Transporter接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxServer.java (实现Server接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxClient.java (实现Client接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.remoting.Transporter (纯文本文件,内容为:xxx=com.xxx.XxxTransporter)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxTransporter.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.remoting.Transporter;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxTransporter&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Transporter {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Server &lt;span style="color:#268bd2">bind&lt;/span>(URL url, ChannelHandler handler) &lt;span style="color:#268bd2">throws&lt;/span> RemotingException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> XxxServer(url, handler);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Client &lt;span style="color:#268bd2">connect&lt;/span>(URL url, ChannelHandler handler) &lt;span style="color:#268bd2">throws&lt;/span> RemotingException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> XxxClient(url, handler);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxServer.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.remoting.transport.transporter.AbstractServer;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxServer&lt;/span> &lt;span style="color:#268bd2">extends&lt;/span> AbstractServer {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">XxxServer&lt;/span>(URL url, ChannelHandler handler) &lt;span style="color:#268bd2">throws&lt;/span> RemotingException{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">super&lt;/span>(url, handler);
&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">protected&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">doOpen&lt;/span>() &lt;span style="color:#268bd2">throws&lt;/span> Throwable {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">protected&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">doClose&lt;/span>() &lt;span style="color:#268bd2">throws&lt;/span> Throwable {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Collection&lt;span style="color:#719e07">&amp;lt;&lt;/span>Channel&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">getChannels&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Channel &lt;span style="color:#268bd2">getChannel&lt;/span>(InetSocketAddress remoteAddress) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxClient.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.remoting.transport.transporter.AbstractClient;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxClient&lt;/span> &lt;span style="color:#268bd2">extends&lt;/span> AbstractClient {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">XxxServer&lt;/span>(URL url, ChannelHandler handler) &lt;span style="color:#268bd2">throws&lt;/span> RemotingException{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">super&lt;/span>(url, handler);
&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">protected&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">doOpen&lt;/span>() &lt;span style="color:#268bd2">throws&lt;/span> Throwable {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">protected&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">doClose&lt;/span>() &lt;span style="color:#268bd2">throws&lt;/span> Throwable {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">protected&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">doConnect&lt;/span>() &lt;span style="color:#268bd2">throws&lt;/span> Throwable {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Channel &lt;span style="color:#268bd2">getChannel&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.remoting.Transporter:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxTransporter&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 信息交换扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/exchanger/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/exchanger/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/exchanger/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>基于传输层之上,实现 Request-Response 信息交换语义。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.remoting.exchange.Exchanger&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.exchange.ExchangeServer&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.exchange.ExchangeClient&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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> exchanger=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:protocol&amp;gt;没有配置exchanger属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> exchanger=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.remoting.exchange.exchanger.HeaderExchanger&lt;/code>&lt;/p>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxExchanger.java (实现Exchanger接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxExchangeServer.java (实现ExchangeServer接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxExchangeClient.java (实现ExchangeClient接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.remoting.exchange.Exchanger (纯文本文件,内容为:xxx=com.xxx.XxxExchanger)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxExchanger.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.remoting.exchange.Exchanger;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxExchanger&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Exchanger {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> ExchangeServer &lt;span style="color:#268bd2">bind&lt;/span>(URL url, ExchangeHandler handler) &lt;span style="color:#268bd2">throws&lt;/span> RemotingException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> XxxExchangeServer(url, handler);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> ExchangeClient &lt;span style="color:#268bd2">connect&lt;/span>(URL url, ExchangeHandler handler) &lt;span style="color:#268bd2">throws&lt;/span> RemotingException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> XxxExchangeClient(url, handler);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxExchangeServer.java:&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>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.remoting.exchange.ExchangeServer;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxExchangeServer&lt;/span> impelements ExchangeServer {
&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>XxxExchangeClient.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.remoting.exchange.ExchangeClient;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxExchangeClient&lt;/span> impelments ExchangeClient {
&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>META-INF/dubbo/org.apache.dubbo.remoting.exchange.Exchanger:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxExchanger&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 对等网络节点组网器扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/page/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/page/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/page/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h1 id="页面扩展">页面扩展&lt;/h1>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>对等网络节点组网器。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.container.page.PageHandler&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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> page=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:protocol&amp;gt;没有配置page属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> page=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.container.page.pages.HomePageHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.container.page.pages.StatusPageHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.container.page.pages.LogPageHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.container.page.pages.SystemPageHandler&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxPageHandler.java (实现PageHandler接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.container.page.PageHandler (纯文本文件,内容为:xxx=com.xxx.XxxPageHandler)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxPageHandler.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.container.page.PageHandler;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxPageHandler&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> PageHandler {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Group &lt;span style="color:#268bd2">lookup&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.container.page.PageHandler:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxPageHandler&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 组网扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/networker/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/networker/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/networker/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>对等网络节点组网器。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.remoting.p2p.Networker&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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> networker=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:protocol&amp;gt;没有配置networker属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> networker=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.remoting.p2p.support.MulticastNetworker&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.p2p.support.FileNetworker&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxNetworker.java (实现Networker接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.remoting.p2p.Networker (纯文本文件,内容为:xxx=com.xxx.XxxNetworker)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxNetworker.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.remoting.p2p.Networker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxNetworker&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Networker {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Group &lt;span style="color:#268bd2">lookup&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.remoting.p2p.Networker:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxNetworker&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: Telnet 命令扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/telnet-handler/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/telnet-handler/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/telnet-handler/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>所有服务器均支持 telnet 访问,用于人工干预。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.remoting.telnet.TelnetHandler&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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> telnet=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:protocol&amp;gt;没有配置telnet属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> telnet=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.remoting.telnet.support.ClearTelnetHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.telnet.support.ExitTelnetHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.telnet.support.HelpTelnetHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.remoting.telnet.support.StatusTelnetHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.dubbo.telnet.ListTelnetHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.dubbo.telnet.ChangeTelnetHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.dubbo.telnet.CurrentTelnetHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.dubbo.telnet.InvokeTelnetHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.dubbo.telnet.TraceTelnetHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.dubbo.telnet.CountTelnetHandler&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.dubbo.telnet.PortTelnetHandler&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxTelnetHandler.java (实现TelnetHandler接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.remoting.telnet.TelnetHandler (纯文本文件,内容为:xxx=com.xxx.XxxTelnetHandler)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxTelnetHandler.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.remoting.telnet.TelnetHandler;
&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">@Help&lt;/span>(parameter&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">&amp;#34;...&amp;#34;&lt;/span>, summary&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">&amp;#34;...&amp;#34;&lt;/span>, detail&lt;span style="color:#719e07">=&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:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxTelnetHandler&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> TelnetHandler {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> String &lt;span style="color:#268bd2">telnet&lt;/span>(Channel channel, String message) &lt;span style="color:#268bd2">throws&lt;/span> RemotingException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.remoting.telnet.TelnetHandler:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxTelnetHandler&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="用法">用法&lt;/h2>
&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-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>telnet 127.0.0.1 &lt;span style="color:#2aa198">20880&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dubbo&amp;gt; xxx args
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 状态检查扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/status-checker/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/status-checker/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/status-checker/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>检查服务依赖各种资源的状态,此状态检查可同时用于 telnet 的 status 命令和 hosting 的 status 页面。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.common.status.StatusChecker&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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> status=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:protocol&amp;gt;没有配置status属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> status=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.common.status.support.MemoryStatusChecker&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.status.support.LoadStatusChecker&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.dubbo.status.ServerStatusChecker&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.dubbo.status.ThreadPoolStatusChecker&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.registry.directory.RegistryStatusChecker&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.config.spring.status.SpringStatusChecker&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.rpc.config.spring.status.DataSourceStatusChecker&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxStatusChecker.java (实现StatusChecker接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.common.status.StatusChecker (纯文本文件,内容为:xxx=com.xxx.XxxStatusChecker)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxStatusChecker.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.status.StatusChecker;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxStatusChecker&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> StatusChecker {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Status &lt;span style="color:#268bd2">check&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.common.status.StatusChecker:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxStatusChecker&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 容器扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/container/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/container/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/container/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>服务容器扩展,用于自定义加载内容。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.container.Container&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>java org.apache.dubbo.container.Main spring jetty log4j
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.container.spring.SpringContainer&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.container.spring.JettyContainer&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.container.spring.Log4jContainer&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxContainer.java (实现Container接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.container.Container (纯文本文件,内容为:xxx=com.xxx.XxxContainer)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxContainer.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>org.apache.dubbo.container.Container;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxContainer&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Container {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Status &lt;span style="color:#268bd2">start&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Status &lt;span style="color:#268bd2">stop&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.container.Container:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxContainer&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 缓存扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/cache/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/cache/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/cache/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>用请求参数作为 key,缓存返回结果。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.cache.CacheFactory&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:service&lt;/span> cache=&lt;span style="color:#2aa198">&amp;#34;lru&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 方法级缓存 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:service&amp;gt;&amp;lt;dubbo:method&lt;/span> cache=&lt;span style="color:#2aa198">&amp;#34;lru&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&amp;lt;/dubbo:service&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:service&amp;gt;没有配置cache属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> cache=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.cache.support.lru.LruCacheFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.cache.support.jcache.JCacheFactory&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxCacheFactory.java (实现CacheFactory接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.cache.CacheFactory (纯文本文件,内容为:xxx=com.xxx.XxxCacheFactory)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxCacheFactory.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.cache.CacheFactory;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxCacheFactory&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> CacheFactory {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Cache &lt;span style="color:#268bd2">getCache&lt;/span>(URL url, String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> &lt;span style="color:#719e07">new&lt;/span> XxxCache(url, name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxCache.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.cache.Cache;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxCache&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Cache {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">Cache&lt;/span>(URL url, String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">put&lt;/span>(Object key, Object value) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Object &lt;span style="color:#268bd2">get&lt;/span>(Object key) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.cache.CacheFactory:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxCacheFactory&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 验证扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/validation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/validation/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/validation/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>参数验证扩展点。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.validation.Validation&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:service&lt;/span> validation=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75">&amp;lt;!-- 缺省值设置,当&amp;lt;dubbo:service&amp;gt;没有配置validation属性时,使用此配置 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">&amp;lt;dubbo:provider&lt;/span> validation=&lt;span style="color:#2aa198">&amp;#34;xxx,yyy&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.validation.support.jvalidation.JValidation&lt;/code>&lt;/p>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxValidation.java (实现Validation接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.validation.Validation (纯文本文件,内容为:xxx=com.xxx.XxxValidation)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxValidation.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.validation.Validation;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxValidation&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Validation {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Object &lt;span style="color:#268bd2">getValidator&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxValidator.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.validation.Validator;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxValidator&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Validator {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">XxxValidator&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">validate&lt;/span>(Invocation invocation) &lt;span style="color:#268bd2">throws&lt;/span> Exception {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>META-INF/dubbo/org.apache.dubbo.validation.Validation:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxValidation&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 日志适配扩展</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/logger-adapter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/logger-adapter/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/logger-adapter/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="扩展说明">扩展说明&lt;/h2>
&lt;p>日志输出适配扩展点。&lt;/p>
&lt;h2 id="扩展接口">扩展接口&lt;/h2>
&lt;p>&lt;code>org.apache.dubbo.common.logger.LoggerAdapter&lt;/code>&lt;/p>
&lt;h2 id="扩展配置">扩展配置&lt;/h2>
&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:application&lt;/span> logger=&lt;span style="color:#2aa198">&amp;#34;xxx&amp;#34;&lt;/span> &lt;span style="color:#268bd2">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>或者:&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-sh" data-lang="sh">&lt;span style="display:flex;">&lt;span>-Ddubbo:application.logger&lt;span style="color:#719e07">=&lt;/span>xxx
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="已知扩展">已知扩展&lt;/h2>
&lt;ul>
&lt;li>&lt;code>org.apache.dubbo.common.logger.slf4j.Slf4jLoggerAdapter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.logger.jcl.JclLoggerAdapter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.logger.log4j.Log4jLoggerAdapter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.logger.log4j2.Log4j2LoggerAdapter&lt;/code>&lt;/li>
&lt;li>&lt;code>org.apache.dubbo.common.logger.jdk.JdkLoggerAdapter&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="扩展示例">扩展示例&lt;/h2>
&lt;p>Maven 项目结构:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span>src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-java
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-XxxLoggerAdapter.java (实现LoggerAdapter接口)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-resources
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-META-INF
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-dubbo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> |-org.apache.dubbo.common.logger.LoggerAdapter (纯文本文件,内容为:xxx=com.xxx.XxxLoggerAdapter)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxLoggerAdapter.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.logger.LoggerAdapter;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxLoggerAdapter&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> LoggerAdapter {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> Logger &lt;span style="color:#268bd2">getLogger&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>XxxLogger.java:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> com.xxx;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.logger.Logger;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">XxxLogger&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> Logger {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">XxxLogger&lt;/span>(URL url) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">info&lt;/span>(String msg) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span 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>META-INF/dubbo/org.apache.dubbo.common.logger.LoggerAdapter:&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-properties" data-lang="properties">&lt;span style="display:flex;">&lt;span>xxx&lt;span style="color:#719e07">=&lt;/span>&lt;span style="color:#2aa198">com.xxx.XxxLoggerAdapter&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docs: 扩展点开发指南</title><link>https://dubbo.apache.org/zh-cn/docs/references/spis/dubbo-spi/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/docs/references/spis/dubbo-spi/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅&lt;a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/overview/">最新版本&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="1简介">1.简介&lt;/h2>
&lt;p>SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。
Dubbo 中,SPI 主要有两种用法,一种是加载固定的扩展类,另一种是加载自适应扩展类。这两种方式会在下面详细的介绍。
需要特别注意的是: 在 Dubbo 中,基于 SPI 扩展加载的类是单例的。&lt;/p>
&lt;h3 id="11-加载固定的扩展类">1.1 加载固定的扩展类&lt;/h3>
&lt;p>如果让你来设计加载固定扩展类,你会怎么做了?
一种常见思路是读取特定目录下的配置文件,然后解析出全类名,通过反射机制来实例化这个类,然后将这个类放在集合中存起来,如果有需要的时候,直接从集合中取。Dubbo 中的实现也是这么一个思路。
不过在 Dubbo 中,实现的更加完善,它实现类了 IOC 和 AOP 的功能。IOC 就是说如果这个扩展类依赖其他属性,Dubbo 会自动的将这个属性进行注入。这个功能如何实现了?一个常见思路是获取这个扩展类的 setter
方法,调用 setter 方法进行属性注入。AOP 指的是什么了?这个说的是 Dubbo 能够为扩展类注入其包装类。比如 DubboProtocol 是 Protocol 的扩展类,ProtocolListenerWrapper 是 DubboProtocol 的包装类。&lt;/p>
&lt;h3 id="12-加载自适应扩展类">1.2 加载自适应扩展类&lt;/h3>
&lt;p>先说明下自适应扩展类的使用场景。比如我们有需求,在调用某一个方法时,基于参数选择调用到不同的实现类。和工厂方法有些类似,基于不同的参数,构造出不同的实例对象。
在 Dubbo 中实现的思路和这个差不多,不过 Dubbo 的实现更加灵活,它的实现和策略模式有些类似。每一种扩展类相当于一种策略,基于 URL 消息总线,将参数传递给 ExtensionLoader,通过 ExtensionLoader 基于参数加载对应的扩展类,实现运行时动态调用到目标实例上。&lt;/p>
&lt;h2 id="2-dubbo-spi-源码分析">2. Dubbo SPI 源码分析&lt;/h2>
&lt;h3 id="21-加载固定的扩展类">2.1 加载固定的扩展类&lt;/h3>
&lt;p>Dubbo 中,SPI 加载固定扩展类的入口是 ExtensionLoader 的 getExtension 方法,下面我们对拓展类对象的获取过程进行详细的分析。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> T &lt;span style="color:#268bd2">getExtension&lt;/span>(String name) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (name &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span> &lt;span style="color:#719e07">||&lt;/span> name.length() &lt;span style="color:#719e07">==&lt;/span> 0)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalArgumentException(&lt;span style="color:#2aa198">&amp;#34;Extension name == null&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (&lt;span style="color:#2aa198">&amp;#34;true&amp;#34;&lt;/span>.equals(name)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 获取默认的拓展实现类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> getDefaultExtension();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// Holder,顾名思义,用于持有目标对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Holder&lt;span style="color:#719e07">&amp;lt;&lt;/span>Object&lt;span style="color:#719e07">&amp;gt;&lt;/span> holder &lt;span style="color:#719e07">=&lt;/span> cachedInstances.get(name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 这段逻辑保证了只有一个线程能够创建 Holder 对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (holder &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cachedInstances.putIfAbsent(name, &lt;span style="color:#719e07">new&lt;/span> Holder&lt;span style="color:#719e07">&amp;lt;&lt;/span>Object&lt;span style="color:#719e07">&amp;gt;&lt;/span>());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> holder &lt;span style="color:#719e07">=&lt;/span> cachedInstances.get(name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Object instance &lt;span style="color:#719e07">=&lt;/span> holder.get();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 双重检查&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (instance &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">synchronized&lt;/span> (holder) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> instance &lt;span style="color:#719e07">=&lt;/span> holder.get();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (instance &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 创建拓展实例&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> instance &lt;span style="color:#719e07">=&lt;/span> createExtension(name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 设置实例到 holder 中&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> holder.set(instance);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> (T) instance;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面代码的逻辑比较简单,首先检查缓存,缓存未命中则创建拓展对象。下面我们来看一下创建拓展对象的过程是怎样的。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> T &lt;span style="color:#268bd2">createExtension&lt;/span>(String name, &lt;span style="color:#dc322f">boolean&lt;/span> wrap) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 从配置文件中加载所有的拓展类,可得到“配置项名称”到“配置类”的映射关系表&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> clazz &lt;span style="color:#719e07">=&lt;/span> getExtensionClasses().get(name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 如果没有该接口的扩展,或者该接口的实现类不允许重复但实际上重复了,直接抛出异常&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (clazz &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span> &lt;span style="color:#719e07">||&lt;/span> unacceptableExceptions.contains(name)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> findException(name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> T instance &lt;span style="color:#719e07">=&lt;/span> (T) EXTENSION_INSTANCES.get(clazz);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 这段代码保证了扩展类只会被构造一次,也就是单例的.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (instance &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> instance &lt;span style="color:#719e07">=&lt;/span> (T) EXTENSION_INSTANCES.get(clazz);
&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> injectExtension(instance);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 如果启用包装的话,则自动为进行包装.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 比如我基于 Protocol 定义了 DubboProtocol 的扩展,但实际上在 Dubbo 中不是直接使用的 DubboProtocol, 而是其包装类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// ProtocolListenerWrapper&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (wrap) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> List&lt;span style="color:#719e07">&amp;lt;&lt;/span>Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&amp;gt;&lt;/span> wrapperClassesList &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> ArrayList&lt;span style="color:#719e07">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (cachedWrapperClasses &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> wrapperClassesList.addAll(cachedWrapperClasses);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> wrapperClassesList.sort(WrapperComparator.COMPARATOR);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Collections.reverse(wrapperClassesList);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 循环创建 Wrapper 实例&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (CollectionUtils.isNotEmpty(wrapperClassesList)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> wrapperClass : wrapperClassesList) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Wrapper wrapper &lt;span style="color:#719e07">=&lt;/span> wrapperClass.getAnnotation(Wrapper.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (wrapper &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">||&lt;/span> (ArrayUtils.contains(wrapper.matches(), name) &lt;span style="color:#719e07">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#719e07">!&lt;/span>ArrayUtils.contains(wrapper.mismatches(), name))) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 将当前 instance 作为参数传给 Wrapper 的构造方法,并通过反射创建 Wrapper 实例。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 然后向 Wrapper 实例中注入依赖,最后将 Wrapper 实例再次赋值给 instance 变量&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> instance &lt;span style="color:#719e07">=&lt;/span> injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&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> initExtension(instance);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> instance;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Throwable t) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(&lt;span style="color:#2aa198">&amp;#34;Extension instance (name: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> name &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, class: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> type &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;) couldn&amp;#39;t be instantiated: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> t.getMessage(), t);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>createExtension 方法的逻辑稍复杂一下,包含了如下的步骤:&lt;/p>
&lt;ol>
&lt;li>通过 getExtensionClasses 获取所有的拓展类&lt;/li>
&lt;li>通过反射创建拓展对象&lt;/li>
&lt;li>向拓展对象中注入依赖&lt;/li>
&lt;li>将拓展对象包裹在相应的 Wrapper 对象中&lt;/li>
&lt;li>初始化拓展对象&lt;/li>
&lt;/ol>
&lt;p>以上步骤中,第一个步骤是加载拓展类的关键,第三和第四个步骤是 Dubbo IOC 与 AOP 的具体实现。在接下来的章节中,将会重点分析 getExtensionClasses 方法的逻辑,以及简单介绍 Dubbo IOC 的具体实现。&lt;/p>
&lt;h3 id="211-获取所有的拓展类">2.1.1 获取所有的拓展类&lt;/h3>
&lt;p>我们在通过名称获取拓展类之前,首先需要根据配置文件解析出拓展项名称到拓展类的映射关系表(Map&amp;lt;名称, 拓展类&amp;gt;),之后再根据拓展项名称从映射关系表中取出相应的拓展类即可。相关过程的代码分析如下:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&amp;gt;&lt;/span> getExtensionClasses() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 从缓存中获取已加载的拓展类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&amp;gt;&lt;/span> classes &lt;span style="color:#719e07">=&lt;/span> cachedClasses.get();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 双重检查&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (classes &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">synchronized&lt;/span> (cachedClasses) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> classes &lt;span style="color:#719e07">=&lt;/span> cachedClasses.get();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (classes &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 加载拓展类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> classes &lt;span style="color:#719e07">=&lt;/span> loadExtensionClasses();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cachedClasses.set(classes);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> classes;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这里也是先检查缓存,若缓存未命中,则通过 synchronized 加锁。加锁后再次检查缓存,并判空。此时如果 classes 仍为 null,则通过 loadExtensionClasses 加载拓展类。下面分析 loadExtensionClasses 方法的逻辑。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&amp;gt;&lt;/span> loadExtensionClasses() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 缓存默认的 SPI 扩展名&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cacheDefaultExtensionName();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&amp;gt;&lt;/span> extensionClasses &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> HashMap&lt;span style="color:#719e07">&amp;lt;&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:#586e75">// 基于策略来加载指定文件夹下的文件&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 目前有四种策略,分别读取 META-INF/services/ META-INF/dubbo/ META-INF/dubbo/internal/ META-INF/dubbo/external/ 这四个目录下的配置文件&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (LoadingStrategy strategy : strategies) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> loadDirectory(extensionClasses, strategy.directory(), type.getName().replace(&lt;span style="color:#2aa198">&amp;#34;org.apache&amp;#34;&lt;/span>, &lt;span style="color:#2aa198">&amp;#34;com.alibaba&amp;#34;&lt;/span>), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> extensionClasses;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>loadExtensionClasses 方法总共做了两件事情,一是对 SPI 注解进行解析,二是调用 loadDirectory 方法加载指定文件夹配置文件。SPI 注解解析过程比较简单,无需多说。下面我们来看一下 loadDirectory 做了哪些事情。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">loadDirectory&lt;/span>(Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&amp;gt;&lt;/span> extensionClasses, String dir, String type,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">boolean&lt;/span> extensionLoaderClassLoaderFirst, &lt;span style="color:#dc322f">boolean&lt;/span> overridden, String... excludedPackages) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// fileName = 文件夹路径 + type 全限定名 &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String fileName &lt;span style="color:#719e07">=&lt;/span> dir &lt;span style="color:#719e07">+&lt;/span> type;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Enumeration&lt;span style="color:#719e07">&amp;lt;&lt;/span>java.net.URL&lt;span style="color:#719e07">&amp;gt;&lt;/span> urls &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ClassLoader classLoader &lt;span style="color:#719e07">=&lt;/span> findClassLoader();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// try to load from ExtensionLoader&amp;#39;s ClassLoader first&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (extensionLoaderClassLoaderFirst) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ClassLoader extensionLoaderClassLoader &lt;span style="color:#719e07">=&lt;/span> ExtensionLoader.class.getClassLoader();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (ClassLoader.getSystemClassLoader() &lt;span style="color:#719e07">!=&lt;/span> extensionLoaderClassLoader) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> urls &lt;span style="color:#719e07">=&lt;/span> extensionLoaderClassLoader.getResources(fileName);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 根据文件名加载所有的同名文件&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (urls &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span> &lt;span style="color:#719e07">||&lt;/span> &lt;span style="color:#719e07">!&lt;/span>urls.hasMoreElements()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (classLoader &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> urls &lt;span style="color:#719e07">=&lt;/span> classLoader.getResources(fileName);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> urls &lt;span style="color:#719e07">=&lt;/span> ClassLoader.getSystemResources(fileName);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (urls &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">while&lt;/span> (urls.hasMoreElements()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> java.net.URL resourceURL &lt;span style="color:#719e07">=&lt;/span> urls.nextElement();
&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> loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Throwable t) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.error(&lt;span style="color:#2aa198">&amp;#34;Exception occurred when loading extension class (interface: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> type &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, description file: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> fileName &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;).&amp;#34;&lt;/span>, t);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>loadDirectory 方法先通过 classLoader 获取所有资源链接,然后再通过 loadResource 方法加载资源。我们继续跟下去,看一下 loadResource 方法的实现。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">loadResource&lt;/span>(Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&amp;gt;&lt;/span> extensionClasses, ClassLoader classLoader,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> java.net.URL resourceURL, &lt;span style="color:#dc322f">boolean&lt;/span> overridden, String... excludedPackages) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> (BufferedReader reader &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> BufferedReader(&lt;span style="color:#719e07">new&lt;/span> InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String line;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String clazz &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 按行读取配置内容&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">while&lt;/span> ((line &lt;span style="color:#719e07">=&lt;/span> reader.readLine()) &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 定位 # 字符&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">final&lt;/span> &lt;span style="color:#dc322f">int&lt;/span> ci &lt;span style="color:#719e07">=&lt;/span> line.indexOf(&lt;span style="color:#2aa198">&amp;#39;#&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (ci &lt;span style="color:#719e07">&amp;gt;=&lt;/span> 0) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 截取 # 之前的字符串,# 之后的内容为注释,需要忽略&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> line &lt;span style="color:#719e07">=&lt;/span> line.substring(0, ci);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> line &lt;span style="color:#719e07">=&lt;/span> line.trim();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (line.length() &lt;span style="color:#719e07">&amp;gt;&lt;/span> 0) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String name &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 以等于号 = 为界,截取键与值&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">int&lt;/span> i &lt;span style="color:#719e07">=&lt;/span> line.indexOf(&lt;span style="color:#2aa198">&amp;#39;=&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (i &lt;span style="color:#719e07">&amp;gt;&lt;/span> 0) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#719e07">=&lt;/span> line.substring(0, i).trim();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> clazz &lt;span style="color:#719e07">=&lt;/span> line.substring(i &lt;span style="color:#719e07">+&lt;/span> 1).trim();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> clazz &lt;span style="color:#719e07">=&lt;/span> line;
&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">// 加载类,并通过 loadClass 方法对类进行缓存&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (StringUtils.isNotEmpty(clazz) &lt;span style="color:#719e07">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#719e07">!&lt;/span>isExcluded(clazz, excludedPackages)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> loadClass(extensionClasses, resourceURL, Class.forName(clazz, &lt;span style="color:#cb4b16">true&lt;/span>, classLoader), name, overridden);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Throwable t) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> IllegalStateException e &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(&lt;span style="color:#2aa198">&amp;#34;Failed to load extension class (interface: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> type &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, class line: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> line &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;) in &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> resourceURL &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, cause: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> t.getMessage(), t);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exceptions.put(line, e);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Throwable t) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.error(&lt;span style="color:#2aa198">&amp;#34;Exception occurred when loading extension class (interface: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> type &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, class file: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> resourceURL &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;) in &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> resourceURL, t);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>loadResource 方法用于读取和解析配置文件,并通过反射加载类,最后调用 loadClass 方法进行其他操作。loadClass 方法用于主要用于操作缓存,该方法的逻辑如下:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">loadClass&lt;/span>(Map&lt;span style="color:#719e07">&amp;lt;&lt;/span>String, Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&amp;gt;&lt;/span> extensionClasses, java.net.URL resourceURL, Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> clazz, String name,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">boolean&lt;/span> overridden) &lt;span style="color:#268bd2">throws&lt;/span> NoSuchMethodException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (&lt;span style="color:#719e07">!&lt;/span>type.isAssignableFrom(clazz)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(&lt;span style="color:#2aa198">&amp;#34;Error occurred when loading extension class (interface: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> type &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, class line: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> clazz.getName() &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;), class &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">+&lt;/span> clazz.getName() &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34; is not subtype of interface.&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">// 检测目标类上是否有 Adaptive 注解&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (clazz.isAnnotationPresent(Adaptive.class)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cacheAdaptiveClass(clazz, overridden);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">else&lt;/span> &lt;span style="color:#719e07">if&lt;/span> (isWrapperClass(clazz)) {
&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> cacheWrapperClass(clazz);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 进入到这里,表明只是该类只是一个普通的拓展类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 检测 clazz 是否有默认的构造方法,如果没有,则抛出异常&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> clazz.getConstructor();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (StringUtils.isEmpty(name)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 如果 name 为空,则尝试从 Extension 注解中获取 name,或使用小写的类名作为 name&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#719e07">=&lt;/span> findAnnotationName(clazz);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (name.length() &lt;span style="color:#719e07">==&lt;/span> 0) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(&lt;span style="color:#2aa198">&amp;#34;No such extension name for the class &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> clazz.getName() &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34; in the config &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> resourceURL);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String&lt;span style="color:#719e07">[]&lt;/span> names &lt;span style="color:#719e07">=&lt;/span> NAME_SEPARATOR.split(name);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (ArrayUtils.isNotEmpty(names)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 如果类上有 Activate 注解,则使用 names 数组的第一个元素作为键,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 存储 name 到 Activate 注解对象的映射关系&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cacheActivateClass(clazz, names&lt;span style="color:#719e07">[&lt;/span>0&lt;span style="color:#719e07">]&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (String n : names) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 存储 Class 到名称的映射关系&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cacheName(clazz, n);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 存储 name 到 Class 的映射关系.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 如果存在同一个扩展名对应多个实现类,基于 override 参数是否允许覆盖,如果不允许,则抛出异常.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> saveInExtensionClass(extensionClasses, clazz, n, overridden);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如上,loadClass 方法操作了不同的缓存,比如 cachedAdaptiveClass、cachedWrapperClasses 和 cachedNames 等等。除此之外,该方法没有其他什么逻辑了。&lt;/p>
&lt;p>到此,关于缓存类加载的过程就分析完了。整个过程没什么特别复杂的地方,大家按部就班的分析即可,不懂的地方可以调试一下。接下来,我们来聊聊 Dubbo IOC 方面的内容。&lt;/p>
&lt;h3 id="212-dubbo-ioc">2.1.2 Dubbo IOC&lt;/h3>
&lt;p>Dubbo IOC 是通过 setter 方法注入依赖。Dubbo 首先会通过反射获取到实例的所有方法,然后再遍历方法列表,检测方法名是否具有 setter 方法特征。若有,则通过 ObjectFactory 获取依赖对象,最后通过反射调用 setter 方法将依赖设置到目标对象中。整个过程对应的代码如下:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> T &lt;span style="color:#268bd2">injectExtension&lt;/span>(T instance) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (objectFactory &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> instance;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 遍历目标类的所有方法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (Method method : instance.getClass().getMethods()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 检测方法是否以 set 开头,且方法仅有一个参数,且方法访问级别为 public&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (&lt;span style="color:#719e07">!&lt;/span>isSetter(method)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">continue&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"> * 检测是否有 DisableInject 注解修饰.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#586e75"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (method.getAnnotation(DisableInject.class) &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">continue&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> Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> pt &lt;span style="color:#719e07">=&lt;/span> method.getParameterTypes()&lt;span style="color:#719e07">[&lt;/span>0&lt;span style="color:#719e07">]&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (ReflectUtils.isPrimitives(pt)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">continue&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 获取属性名,比如 setName 方法对应属性名 name&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String property &lt;span style="color:#719e07">=&lt;/span> getSetterProperty(method);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 从 ObjectFactory 中获取依赖对象&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Object object &lt;span style="color:#719e07">=&lt;/span> objectFactory.getExtension(pt, property);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (object &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 注入&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> method.invoke(instance, object);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Exception e) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.error(&lt;span style="color:#2aa198">&amp;#34;Failed to inject via method &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> method.getName()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34; of interface &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> type.getName() &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> e.getMessage(), e);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Exception e) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.error(e.getMessage(), e);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> instance;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在上面代码中,objectFactory 变量的类型为 AdaptiveExtensionFactory,AdaptiveExtensionFactory 内部维护了一个 ExtensionFactory 列表,用于存储其他类型的 ExtensionFactory。Dubbo 目前提供了两种 ExtensionFactory,分别是 SpiExtensionFactory 和 SpringExtensionFactory。前者用于创建自适应的拓展,后者是用于从 Spring 的 IOC 容器中获取所需的拓展。这两个类的类的代码不是很复杂,这里就不一一分析了。&lt;/p>
&lt;p>Dubbo IOC 目前仅支持 setter 方式注入,总的来说,逻辑比较简单易懂。&lt;/p>
&lt;h3 id="22-加载自适应扩展类">2.2 加载自适应扩展类&lt;/h3>
&lt;p>自适应扩展类的含义是说,基于参数,在运行时动态选择到具体的目标类,然后执行。
在 Dubbo 中,很多拓展都是通过 SPI 机制进行加载的,比如 Protocol、Cluster、LoadBalance 等。有时,有些拓展并不想在框架启动阶段被加载,而是希望在拓展方法被调用时,根据运行时参数进行加载。这听起来有些矛盾。拓展未被加载,那么拓展方法就无法被调用(静态方法除外)。拓展方法未被调用,拓展就无法被加载。对于这个矛盾的问题,Dubbo 通过自适应拓展机制很好的解决了。自适应拓展机制的实现逻辑比较复杂,首先 Dubbo 会为拓展接口生成具有代理功能的代码。然后通过 javassist 或 jdk 编译这段代码,得到 Class 类。最后再通过反射创建代理类,整个过程比较复杂。&lt;/p>
&lt;p>加载自适应扩展类的入口是 ExtensionLoader 的 getAdaptiveExtension 方法。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> T &lt;span style="color:#268bd2">getAdaptiveExtension&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 从缓存中获取自适应拓展&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Object instance &lt;span style="color:#719e07">=&lt;/span> cachedAdaptiveInstance.get();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (instance &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 如果存在异常,则直接抛出&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (createAdaptiveInstanceError &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(&lt;span style="color:#2aa198">&amp;#34;Failed to create adaptive instance: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> createAdaptiveInstanceError.toString(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> createAdaptiveInstanceError);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">synchronized&lt;/span> (cachedAdaptiveInstance) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> instance &lt;span style="color:#719e07">=&lt;/span> cachedAdaptiveInstance.get();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// double check&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (instance &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 创建自适应拓展&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 这里分为两种情况:一种是存在 Adaptive 类,另一个是需要生成 Adaptive 类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> instance &lt;span style="color:#719e07">=&lt;/span> createAdaptiveExtension();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cachedAdaptiveInstance.set(instance);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Throwable t) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> createAdaptiveInstanceError &lt;span style="color:#719e07">=&lt;/span> t;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(&lt;span style="color:#2aa198">&amp;#34;Failed to create adaptive instance: &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> t.toString(), t);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> (T) instance;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>getAdaptiveExtension 方法首先会检查缓存,缓存未命中,则调用 createAdaptiveExtension 方法创建自适应拓展。下面,我们看一下 createAdaptiveExtension 方法的代码。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> T &lt;span style="color:#268bd2">createAdaptiveExtension&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 获取自适应拓展类,并通过反射实例化&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> injectExtension((T) getAdaptiveExtensionClass().newInstance());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">catch&lt;/span> (Exception e) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(&lt;span style="color:#2aa198">&amp;#34;Can not create adaptive extension ...&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>createAdaptiveExtension 方法的代码比较少,但却包含了三个逻辑,分别如下:&lt;/p>
&lt;ol>
&lt;li>调用 getAdaptiveExtensionClass 方法获取自适应拓展 Class 对象&lt;/li>
&lt;li>通过反射进行实例化&lt;/li>
&lt;li>调用 injectExtension 方法向拓展实例中注入依赖&lt;/li>
&lt;/ol>
&lt;p>前两个逻辑比较好理解,第三个逻辑用于向自适应拓展对象中注入依赖。这个逻辑看似多余,但有存在的必要,这里简单说明一下。前面说过,Dubbo 中有两种类型的自适应拓展,一种是手工编码的,一种是自动生成的。手工编码的自适应拓展中可能存在着一些依赖,而自动生成的 Adaptive 拓展则不会依赖其他类。这里调用 injectExtension 方法的目的是为手工编码的自适应拓展注入依赖,这一点需要大家注意一下。关于 injectExtension 方法,前文已经分析过了,这里不再赘述。接下来,分析 getAdaptiveExtensionClass 方法的逻辑。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> getAdaptiveExtensionClass() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 通过 SPI 获取所有的拓展类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> getExtensionClasses();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 检查缓存,若缓存不为空,则直接返回缓存&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (cachedAdaptiveClass &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> cachedAdaptiveClass;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 创建自适应拓展类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> cachedAdaptiveClass &lt;span style="color:#719e07">=&lt;/span> createAdaptiveExtensionClass();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>getAdaptiveExtensionClass 方法同样包含了三个逻辑,如下:&lt;/p>
&lt;ol>
&lt;li>调用 getExtensionClasses 获取所有的拓展类&lt;/li>
&lt;li>检查缓存,若缓存不为空,则返回缓存&lt;/li>
&lt;li>若缓存为空,则调用 createAdaptiveExtensionClass 创建自适应拓展类&lt;/li>
&lt;/ol>
&lt;p>这三个逻辑看起来平淡无奇,似乎没有多讲的必要。但是这些平淡无奇的代码中隐藏了着一些细节,需要说明一下。首先从第一个逻辑说起,getExtensionClasses 这个方法用于获取某个接口的所有实现类。比如该方法可以获取 Protocol 接口的 DubboProtocol、HttpProtocol、InjvmProtocol 等实现类。在获取实现类的过程中,如果某个实现类被 Adaptive 注解修饰了,那么该类就会被赋值给 cachedAdaptiveClass 变量。此时,上面步骤中的第二步条件成立(缓存不为空),直接返回 cachedAdaptiveClass 即可。如果所有的实现类均未被 Adaptive 注解修饰,那么执行第三步逻辑,创建自适应拓展类。相关代码如下:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> Class&lt;span style="color:#719e07">&amp;lt;?&amp;gt;&lt;/span> createAdaptiveExtensionClass() {
&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 code &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ClassLoader classLoader &lt;span style="color:#719e07">=&lt;/span> findClassLoader();
&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> org.apache.dubbo.common.compiler.Compiler compiler &lt;span style="color:#719e07">=&lt;/span> ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 编译代码,生成 Class&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> compiler.compile(code, classLoader);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>createAdaptiveExtensionClass 方法用于生成自适应拓展类,该方法首先会生成自适应拓展类的源码,然后通过 Compiler 实例(Dubbo 默认使用 javassist 作为编译器)编译源码,得到代理类 Class 实例。接下来,我们把重点放在代理类代码生成的逻辑上,其他逻辑大家自行分析。&lt;/p>
&lt;h3 id="221-自适应拓展类代码生成">2.2.1 自适应拓展类代码生成&lt;/h3>
&lt;p>AdaptiveClassCodeGenerator#generate 方法生成扩展类代码&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> String &lt;span style="color:#268bd2">generate&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 如果该接口中没有方法被 @Adaptive 注解修饰,直接抛出异常&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (&lt;span style="color:#719e07">!&lt;/span>hasAdaptiveMethod()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(&lt;span style="color:#2aa198">&amp;#34;No adaptive method exist on extension &amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span> type.getName() &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;, refuse to create the adaptive class!&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> StringBuilder code &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> StringBuilder();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 生成包名、import、方法等.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> code.append(generatePackageInfo());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> code.append(generateImports());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> code.append(generateClassDeclaration());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Method&lt;span style="color:#719e07">[]&lt;/span> methods &lt;span style="color:#719e07">=&lt;/span> type.getMethods();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">for&lt;/span> (Method method : methods) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> code.append(generateMethod(method));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> code.append(&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:#719e07">if&lt;/span> (logger.isDebugEnabled()) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.debug(code.toString());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> code.toString();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="222-生成方法">2.2.2 生成方法&lt;/h4>
&lt;p>上面代码中,生成方法的逻辑是最关键的,我们详细分析下。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> String &lt;span style="color:#268bd2">generateMethod&lt;/span>(Method method) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String methodReturnType &lt;span style="color:#719e07">=&lt;/span> method.getReturnType().getCanonicalName();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String methodName &lt;span style="color:#719e07">=&lt;/span> method.getName();
&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 methodContent &lt;span style="color:#719e07">=&lt;/span> generateMethodContent(method);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String methodArgs &lt;span style="color:#719e07">=&lt;/span> generateMethodArguments(method);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String methodThrows &lt;span style="color:#719e07">=&lt;/span> generateMethodThrows(method);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>generateMethodContent 分析&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">private&lt;/span> String &lt;span style="color:#268bd2">generateMethodContent&lt;/span>(Method method) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 该方法上必须有 @Adaptive 注解修饰&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Adaptive adaptiveAnnotation &lt;span style="color:#719e07">=&lt;/span> method.getAnnotation(Adaptive.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> StringBuilder code &lt;span style="color:#719e07">=&lt;/span> &lt;span style="color:#719e07">new&lt;/span> StringBuilder(512);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (adaptiveAnnotation &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 没有 @Adaptive 注解修饰,生成异常信息&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> generateUnsupported(method);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 获取 URL 在参数列表上的索引&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">int&lt;/span> urlTypeIndex &lt;span style="color:#719e07">=&lt;/span> getUrlTypeIndex(method);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (urlTypeIndex &lt;span style="color:#719e07">!=&lt;/span> &lt;span style="color:#719e07">-&lt;/span>1) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 如果参数列表上存在 URL,生成对 URL 进行空检查&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> code.append(generateUrlNullCheck(urlTypeIndex));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#719e07">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 如果参数列表不存在 URL 类型的参数,那么就看参数列表上参数对象中是否包含 getUrl 方法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 有的话,生成 URL 空检查&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> code.append(generateUrlAssignmentIndirectly(method));
&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">// 解析 Adaptive 注解上的 value 属性&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> String&lt;span style="color:#719e07">[]&lt;/span> value &lt;span style="color:#719e07">=&lt;/span> getMethodAdaptiveValue(adaptiveAnnotation);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 如果参数列表上有 Invocation 类型的参数,生成空检查并获取 methodName.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">boolean&lt;/span> hasInvocation &lt;span style="color:#719e07">=&lt;/span> hasInvocationArgument(method);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> code.append(generateInvocationArgumentNullCheck(method));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 这段逻辑主要就是为了生成 extName(也就是扩展名)&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">// 1.defaultExtName 是否存在&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 2.参数中是否存在 invocation 类型参数&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 3.是否是为 protocol 生成代理&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 为什么要对 protocol 单独考虑了?因为 URL 中有获取 protocol 值的方法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> code.append(generateExtNameAssignment(value, hasInvocation));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// check extName == null?&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> code.append(generateExtNameNullCheck(value));
&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">// 生成获取扩展(使用 ExtensionLoader.getExtension 方法)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> code.append(generateExtensionAssignment());
&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> code.append(generateReturnAndInvocation(method));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> code.toString();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面那段逻辑主要做了如下几件事:
1.检查方法上是否 Adaptive 注解修饰
2.为方法生成代码的时候,参数列表上要有 URL(或参数对象中有 URL)
3.使用 ExtensionLoader.getExtension 获取扩展
4.执行对应的方法&lt;/p>
&lt;h3 id="223-附一个动态生成代码后的例子">2.2.3 附一个动态生成代码后的例子&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">package&lt;/span> org.apache.dubbo.common.extension.adaptive;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#719e07">import&lt;/span> org.apache.dubbo.common.extension.ExtensionLoader;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">HasAdaptiveExt$Adaptive&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> java.lang.String &lt;span style="color:#268bd2">echo&lt;/span>(org.apache.dubbo.common.URL arg0,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> java.lang.String arg1) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// URL 空校验&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (arg0 &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalArgumentException(&lt;span style="color:#2aa198">&amp;#34;url == null&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> org.apache.dubbo.common.URL url &lt;span style="color:#719e07">=&lt;/span> arg0;
&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 extName &lt;span style="color:#719e07">=&lt;/span> url.getParameter(&lt;span style="color:#2aa198">&amp;#34;has.adaptive.ext&amp;#34;&lt;/span>, &lt;span style="color:#2aa198">&amp;#34;adaptive&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 扩展名空校验&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">if&lt;/span> (extName &lt;span style="color:#719e07">==&lt;/span> &lt;span style="color:#cb4b16">null&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">throw&lt;/span> &lt;span style="color:#719e07">new&lt;/span> IllegalStateException(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#2aa198">&amp;#34;Failed to get extension (org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt) name from url (&amp;#34;&lt;/span> &lt;span style="color:#719e07">+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url.toString() &lt;span style="color:#719e07">+&lt;/span> &lt;span style="color:#2aa198">&amp;#34;) use keys([has.adaptive.ext])&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> org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt extension &lt;span style="color:#719e07">=&lt;/span> (org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt) ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt.class)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .getExtension(extName);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#586e75">// 执行对应的方法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> extension.echo(arg0, arg1);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="3spi-扩展示例">3.SPI 扩展示例&lt;/h2>
&lt;h3 id="31--加载固定扩展类">3.1 加载固定扩展类&lt;/h3>
&lt;h3 id="311-编写-spi-接口及实现类">3.1.1 编写 SPI 接口及实现类&lt;/h3>
&lt;p>不管是 Java SPI,还是 Dubbo 中实现的 SPI,都需要编写接口。不过 Dubbo 中的接口需要被 @SPI 注解修饰。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">@SPI&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">interface&lt;/span> &lt;span style="color:#268bd2">DemoSpi&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">say&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">DemoSpiImpl&lt;/span> &lt;span style="color:#268bd2">implements&lt;/span> DemoSpi {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">say&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="312-将实现类放在特定目录下">3.1.2 将实现类放在特定目录下&lt;/h4>
&lt;p>从上面的代码可知,dubbo 在加载扩展类的时候,会从四个目录中读取。我们在 META-INF/dubbo 目录下新建一个以 DemoSpi 接口名为文件名的文件,内容如下:&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-text" data-lang="text">&lt;span style="display:flex;">&lt;span>demoSpiImpl = com.xxx.xxx.DemoSpiImpl(为 DemoSpi 接口实现类的全类名)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="313-使用">3.1.3 使用&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>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">DubboSPITest&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">@Test&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">sayHello&lt;/span>() &lt;span style="color:#268bd2">throws&lt;/span> Exception {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ExtensionLoader&lt;span style="color:#719e07">&amp;lt;&lt;/span>DemoSpi&lt;span style="color:#719e07">&amp;gt;&lt;/span> extensionLoader &lt;span style="color:#719e07">=&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ExtensionLoader.getExtensionLoader(DemoSpi.class);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> DemoSpi dmeoSpi &lt;span style="color:#719e07">=&lt;/span> extensionLoader.getExtension(&lt;span style="color:#2aa198">&amp;#34;demoSpiImpl&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> optimusPrime.sayHello();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="32-加载自适应扩展类">3.2 加载自适应扩展类&lt;/h3>
&lt;p>这个以 Protocol 为例进行说明&lt;/p>
&lt;h3 id="321-protocol-接口抽取部分核心方法">3.2.1 Protocol 接口(抽取部分核心方法)&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">@SPI&lt;/span>(&lt;span style="color:#2aa198">&amp;#34;dubbo&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">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:#268bd2">@Adaptive&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Exporter&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">export&lt;/span>(Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> invoker) &lt;span style="color:#268bd2">throws&lt;/span> RpcException;
&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">@Adaptive&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">refer&lt;/span>(Class&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> type, URL url) &lt;span style="color:#268bd2">throws&lt;/span> RpcException;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">DubboProtocol&lt;/span> &lt;span style="color:#268bd2">extends&lt;/span> AbstractProtocol {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ......
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">refer&lt;/span>(Class&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> type, URL url) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> protocolBindingRefer(type, url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> Exporter&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> &lt;span style="color:#268bd2">export&lt;/span>(Invoker&lt;span style="color:#719e07">&amp;lt;&lt;/span>T&lt;span style="color:#719e07">&amp;gt;&lt;/span> invoker) &lt;span style="color:#268bd2">throws&lt;/span> RpcException {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ......
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#719e07">return&lt;/span> exporter;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="322-将实现类放在特定目录下">3.2.2 将实现类放在特定目录下&lt;/h3>
&lt;p>在 dubbo 中,该配置路径 META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol&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-text" data-lang="text">&lt;span style="display:flex;">&lt;span>dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>需要说明一点的是,在 dubbo 中,并不是直接使用 DubboProtocol 的,而是使用的是其包装类。&lt;/p>
&lt;h3 id="323-使用">3.2.3 使用&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#268bd2">class&lt;/span> &lt;span style="color:#268bd2">DubboAdaptiveTest&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">@Test&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#268bd2">public&lt;/span> &lt;span style="color:#dc322f">void&lt;/span> &lt;span style="color:#268bd2">sayHello&lt;/span>() &lt;span style="color:#268bd2">throws&lt;/span> Exception {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> URL url &lt;span style="color:#719e07">=&lt;/span> URL.valueOf(&lt;span style="color:#2aa198">&amp;#34;dubbo://localhost/test&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Protocol adaptiveProtocol &lt;span style="color:#719e07">=&lt;/span> ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> adaptiveProtocol.refer(type, url);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item></channel></rss>