| <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Apache Dubbo – 配置框架与服务行为</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/</link><description>Recent content in 配置框架与服务行为 on Apache Dubbo</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><atom:link href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/index.xml" rel="self" type="application/rss+xml"/><item><title>Overview: 端口协议复用</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/port-unification/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/port-unification/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>通过对protocol进行配置,dubbo3可以支持端口的协议复用。 |
| 比如使用Triple协议启动端口复用后,可以在相同的端口上为服务增加 |
| Dubbo协议支持,以及Qos协议支持。这些协议的识别都是由一个统一的端口复用 |
| 服务器进行处理的,可以用于服务的协议迁移,并且可以节约端口以及相关的资源,减少运维的复杂性。</p> |
| <p><img src="https://dubbo.apache.org/imgs/blog/pu-server/pu-server-flow.png" alt="pu-server-image1"></p> |
| <ul> |
| <li> |
| <p>在服务的创建阶段,通过从Config层获取到服务导出的协议配置从而创建不同的Protocol对象进行导出。在导出的过程 |
| 中,如果不是第一次创建端口复用的Server,那么Exchanger会将Protcol层传递的数据保存到Server,用于后续处理该协议类型的消息。</p> |
| </li> |
| <li> |
| <p>当客户端的消息传递过来后,首先会通过Server传递给ProtocolDetector,如果完成了识别,那么就会标记该客户端为对应的协议。并通过WireProtocol配置对应的处理逻辑,最后交给ChannelOperator完成底层的IO框架和对应的Dubbo框架的处理逻辑的绑定。</p> |
| </li> |
| <li> |
| <p>以上的协议识别完成之后,Channel已经确定了如何处理远程的客户端消息,通过对应的ServerPipeline进行处理即可(在处理的过程中也会根据配置信息决定消息的处理线程)。</p> |
| </li> |
| </ul> |
| <h2 id="使用场景">使用场景</h2> |
| <ul> |
| <li> |
| <p>最常用的是用于服务发现。这允许应用程序通过网络发现服务,然后使用同一端口与它们通信,有助于降低网络通信的复杂性,并使其更易于管理。</p> |
| </li> |
| <li> |
| <p>可以用于负载平衡。这允许应用程序在多个远程服务或服务集群之间平衡负载,有助于提高服务的可扩展性、可靠性和可用性。</p> |
| </li> |
| <li> |
| <p>可以用于服务监控。这允许应用程序监视远程服务的运行状况,并在服务出现故障或变得不可用时发出警报,有助于确保服务的可用性并减少停机时间。</p> |
| </li> |
| </ul> |
| <blockquote> |
| <p>参考用例 |
| <a href="https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification">https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-port-unification</a></p> |
| </blockquote> |
| <h2 id="使用方式">使用方式</h2> |
| <p>在同一主机上部署多个服务或需要通过负载均衡器访问多个服务。</p> |
| <blockquote> |
| <p>关于Dubbo支持的配置方式 <a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/config/">配置说明</a></p> |
| </blockquote> |
| <h3 id="服务多协议导出">服务多协议导出</h3> |
| <p>ext-protocol参数支持配置多个不同的协议,协议之间通过&quot;,&ldquo;进行分隔。</p> |
| <h4 id="xml-配置">xml 配置</h4> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:protocol</span> name=<span style="color:#2aa198">&#34;dubbo&#34;</span> port=<span style="color:#2aa198">&#34;-1&#34;</span> ext-protocol=<span style="color:#2aa198">&#34;tri,&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;bean</span> id=<span style="color:#2aa198">&#34;greetingService&#34;</span> class=<span style="color:#2aa198">&#34;org.apache.dubbo.demo.provider.GreetingServiceImpl&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> delay=<span style="color:#2aa198">&#34;5000&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> group=<span style="color:#2aa198">&#34;greeting&#34;</span> timeout=<span style="color:#2aa198">&#34;5000&#34;</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.demo.GreetingService&#34;</span> ref=<span style="color:#2aa198">&#34;greetingService&#34;</span> protocol=<span style="color:#2aa198">&#34;dubbo&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h4 id="api-配置">API 配置</h4> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>ProtocolConfig config <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ProtocolConfig(CommonConstants.TRIPLE, <span style="color:#719e07">-</span>1); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>config.setExtProtocol(CommonConstants.DUBBO<span style="color:#719e07">+</span><span style="color:#2aa198">&#34;,&#34;</span>); |
| </span></span></code></pre></div><h4 id="yaml-配置">yaml 配置</h4> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#268bd2">dubbo</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">application</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">name</span>: dubbo-springboot-demo-provider |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">protocol</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">name</span>: tri |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">port</span>: -<span style="color:#2aa198">1</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">ext-protocol</span>: dubbo, |
| </span></span></code></pre></div><h4 id="properties-配置">properties 配置</h4> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-properties" data-lang="properties"><span style="display:flex;"><span>dubbo.protocol.name<span style="color:#719e07">=</span><span style="color:#2aa198">tri</span> |
| </span></span><span style="display:flex;"><span>dubbo.protocol.ext-protocol<span style="color:#719e07">=</span><span style="color:#2aa198">dubbo,</span> |
| </span></span><span style="display:flex;"><span>dubbo.protocol.port<span style="color:#719e07">=</span><span style="color:#2aa198">20880</span> |
| </span></span></code></pre></div><h3 id="qos接入">Qos接入</h3> |
| <h4 id="qos模块导入">Qos模块导入</h4> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.apache.dubbo<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>dubbo-qos<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span></code></pre></div><p>完成Qos模块的导入之后,相关的配置项可参考<a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/qos/overview/">Qos操作手册</a>进行配置。</p> |
| <p>默认情况下,基于端口复用的Qos服务在模块导入后是启动的。</p> |
| <h3 id="qos使用">Qos使用</h3> |
| <p>将Qos协议接入到端口复用的场景下,需要在建立连接之后,客户端先向服务端发送消息,对比将Qos协议通过单个端口提供服务,端口复用版的Qos协议在处理telnet连接的情况下需要用户执行一些操作,完成协议识别(二选一)。</p> |
| <ol> |
| <li> |
| <p>直接调用命令</p> |
| <p>直接调用telnet支持的命令也可以完成识别,在用户不熟悉的情况下可以调用help指令完成识别</p> |
| <p><img src="https://dubbo.apache.org/imgs/blog/pu-server/qos-telnet-directcall.png" alt="pu-server-image2"></p> |
| </li> |
| <li> |
| <p>发送telnet命令识别</p> |
| <p>通过telnet命令建立连接之后,执行以下几个步骤:</p> |
| <ol> |
| <li>使用 crtl + &ldquo;]&rdquo; 进入到telnet交互界面(telnet默认的escape character)</li> |
| <li>调用 &ldquo;send ayt&rdquo; 向服务端发送特殊识别字段(为telnet协议的一个特殊字段)</li> |
| <li>回车完成消息发送并进入到dubbo的交互界面</li> |
| </ol> |
| <p><img src="https://dubbo.apache.org/imgs/blog/pu-server/qos-telnet-sendayt.png" alt="pu-server-imgs3"></p> |
| </li> |
| </ol> |
| <h3 id="服务引用">服务引用</h3> |
| <p>以<a href="https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification">dubbo-samples-port-unification</a>中的例子作为基础, 引用不同协议的服务和非端口复用情况下的配置是一致的,下面通过Consumer端的InvokerListener输出调用过程中的URL信息。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>ReferenceConfig<span style="color:#719e07">&lt;</span>GreetingService<span style="color:#719e07">&gt;</span> reference <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ReferenceConfig<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span>reference.setInterface(GreetingService.class); |
| </span></span><span style="display:flex;"><span>reference.setListener(<span style="color:#2aa198">&#34;consumer&#34;</span>); |
| </span></span><span style="display:flex;"><span>reference.setProtocol(<span style="color:#719e07">this</span>.protocol); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// reference.setProtocol(CommonConstants.DUBBO);</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// reference.setProtocol(CommonConstants.TRIPLE);</span> |
| </span></span></code></pre></div><p><img src="https://dubbo.apache.org/imgs/blog/pu-server/reference-service.png" alt="pu-server-imgs4"></p></description></item><item><title>Overview: 分布式事务</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/transaction/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/transaction/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>分布式事务提供对补偿事务的支持,能够在事务失败时回滚事务的影响,支持全局事务超时,能够指定事务完成的超时时间,对日志提供支持,能够查看分布式应用程序中所有服务中发生的事务的历史记录,能够轻松地调试和排除事务。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <ul> |
| <li>电商:当客户在线购买商品时,提供分布式交易。可以确保订单和付款在不同的数据库和服务中保持同步,有助于防止付款丢失和订单错误。</li> |
| <li>银行:当客户在账户之间转账时,提供分布式交易。可以确保资金正确转移,所有数据库和服务保持同步。</li> |
| <li>医疗保健:用于在患者接受医疗治疗时提供分布式事务。可以确保医疗记录、账单信息和患者信息在多个系统中保持同步。</li> |
| <li>供应链管理:当材料从一个地点运送到另一个地点时,提供分布式事务。可以确保库存水平、订单和装运信息在多个系统中保持同步。</li> |
| </ul> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="第一步"><strong>第一步</strong></h3> |
| <p>首先访问: <a href="https://seata.io/zh-cn/blog/download.html">https://seata.io/zh-cn/blog/download.html</a></p> |
| <p>下载我们需要使用的 seata1.5.2 服务</p> |
| <h3 id="第二步"><strong>第二步</strong></h3> |
| <p>1.在你的参与全局事务的数据库中加入 undo_log 这张表(TCC,SAGA,XA 可跳过这步)</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#586e75">-- for AT mode you must to init this sql for you business database. the seata server not need it. |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span><span style="color:#719e07">CREATE</span> <span style="color:#719e07">TABLE</span> <span style="color:#719e07">IF</span> <span style="color:#719e07">NOT</span> <span style="color:#719e07">EXISTS</span> <span style="color:#719e07">`</span>undo_log<span style="color:#719e07">`</span> |
| </span></span><span style="display:flex;"><span>( |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>branch_id<span style="color:#719e07">`</span> <span style="color:#b58900">BIGINT</span>(<span style="color:#2aa198">20</span>) <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span> <span style="color:#719e07">COMMENT</span> <span style="color:#2aa198">&#39;branch transaction id&#39;</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>xid<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">100</span>) <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span> <span style="color:#719e07">COMMENT</span> <span style="color:#2aa198">&#39;global transaction id&#39;</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>context<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">128</span>) <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span> <span style="color:#719e07">COMMENT</span> <span style="color:#2aa198">&#39;undo_log context,such as serialization&#39;</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>rollback_info<span style="color:#719e07">`</span> LONGBLOB <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span> <span style="color:#719e07">COMMENT</span> <span style="color:#2aa198">&#39;rollback info&#39;</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>log_status<span style="color:#719e07">`</span> <span style="color:#b58900">INT</span>(<span style="color:#2aa198">11</span>) <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span> <span style="color:#719e07">COMMENT</span> <span style="color:#2aa198">&#39;0:normal status,1:defense status&#39;</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>log_created<span style="color:#719e07">`</span> DATETIME(<span style="color:#2aa198">6</span>) <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span> <span style="color:#719e07">COMMENT</span> <span style="color:#2aa198">&#39;create datetime&#39;</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>log_modified<span style="color:#719e07">`</span> DATETIME(<span style="color:#2aa198">6</span>) <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span> <span style="color:#719e07">COMMENT</span> <span style="color:#2aa198">&#39;modify datetime&#39;</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">UNIQUE</span> <span style="color:#719e07">KEY</span> <span style="color:#719e07">`</span>ux_undo_log<span style="color:#719e07">`</span> (<span style="color:#719e07">`</span>xid<span style="color:#719e07">`</span>, <span style="color:#719e07">`</span>branch_id<span style="color:#719e07">`</span>) |
| </span></span><span style="display:flex;"><span>) ENGINE <span style="color:#719e07">=</span> InnoDB |
| </span></span><span style="display:flex;"><span> AUTO_INCREMENT <span style="color:#719e07">=</span> <span style="color:#2aa198">1</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">DEFAULT</span> CHARSET <span style="color:#719e07">=</span> utf8 <span style="color:#719e07">COMMENT</span> <span style="color:#719e07">=</span><span style="color:#2aa198">&#39;AT transaction mode undo table&#39;</span>; |
| </span></span></code></pre></div><p>2.在你的 mysql 数据库中创建名为 seata 的库,并使用以下下 sql</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#586e75">-- -------------------------------- The script used when storeMode is &#39;db&#39; -------------------------------- |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75">-- the table to store GlobalSession data |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span><span style="color:#719e07">CREATE</span> <span style="color:#719e07">TABLE</span> <span style="color:#719e07">IF</span> <span style="color:#719e07">NOT</span> <span style="color:#719e07">EXISTS</span> <span style="color:#719e07">`</span>global_table<span style="color:#719e07">`</span> |
| </span></span><span style="display:flex;"><span>( |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>xid<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">128</span>) <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>transaction_id<span style="color:#719e07">`</span> <span style="color:#b58900">BIGINT</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>status<span style="color:#719e07">`</span> TINYINT <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>application_id<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">32</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>transaction_service_group<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">32</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>transaction_name<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">128</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>timeout<span style="color:#719e07">`</span> <span style="color:#b58900">INT</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>begin_time<span style="color:#719e07">`</span> <span style="color:#b58900">BIGINT</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>application_data<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">2000</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>gmt_create<span style="color:#719e07">`</span> DATETIME, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>gmt_modified<span style="color:#719e07">`</span> DATETIME, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">PRIMARY</span> <span style="color:#719e07">KEY</span> (<span style="color:#719e07">`</span>xid<span style="color:#719e07">`</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">KEY</span> <span style="color:#719e07">`</span>idx_gmt_modified_status<span style="color:#719e07">`</span> (<span style="color:#719e07">`</span>gmt_modified<span style="color:#719e07">`</span>, <span style="color:#719e07">`</span>status<span style="color:#719e07">`</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">KEY</span> <span style="color:#719e07">`</span>idx_transaction_id<span style="color:#719e07">`</span> (<span style="color:#719e07">`</span>transaction_id<span style="color:#719e07">`</span>) |
| </span></span><span style="display:flex;"><span>) ENGINE <span style="color:#719e07">=</span> InnoDB |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">DEFAULT</span> CHARSET <span style="color:#719e07">=</span> utf8; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">-- the table to store BranchSession data |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span><span style="color:#719e07">CREATE</span> <span style="color:#719e07">TABLE</span> <span style="color:#719e07">IF</span> <span style="color:#719e07">NOT</span> <span style="color:#719e07">EXISTS</span> <span style="color:#719e07">`</span>branch_table<span style="color:#719e07">`</span> |
| </span></span><span style="display:flex;"><span>( |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>branch_id<span style="color:#719e07">`</span> <span style="color:#b58900">BIGINT</span> <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>xid<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">128</span>) <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>transaction_id<span style="color:#719e07">`</span> <span style="color:#b58900">BIGINT</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>resource_group_id<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">32</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>resource_id<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">256</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>branch_type<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">8</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>status<span style="color:#719e07">`</span> TINYINT, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>client_id<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">64</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>application_data<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">2000</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>gmt_create<span style="color:#719e07">`</span> DATETIME(<span style="color:#2aa198">6</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>gmt_modified<span style="color:#719e07">`</span> DATETIME(<span style="color:#2aa198">6</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">PRIMARY</span> <span style="color:#719e07">KEY</span> (<span style="color:#719e07">`</span>branch_id<span style="color:#719e07">`</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">KEY</span> <span style="color:#719e07">`</span>idx_xid<span style="color:#719e07">`</span> (<span style="color:#719e07">`</span>xid<span style="color:#719e07">`</span>) |
| </span></span><span style="display:flex;"><span>) ENGINE <span style="color:#719e07">=</span> InnoDB |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">DEFAULT</span> CHARSET <span style="color:#719e07">=</span> utf8; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">-- the table to store lock data |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span><span style="color:#719e07">CREATE</span> <span style="color:#719e07">TABLE</span> <span style="color:#719e07">IF</span> <span style="color:#719e07">NOT</span> <span style="color:#719e07">EXISTS</span> <span style="color:#719e07">`</span>lock_table<span style="color:#719e07">`</span> |
| </span></span><span style="display:flex;"><span>( |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>row_key<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">128</span>) <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>xid<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">96</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>transaction_id<span style="color:#719e07">`</span> <span style="color:#b58900">BIGINT</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>branch_id<span style="color:#719e07">`</span> <span style="color:#b58900">BIGINT</span> <span style="color:#719e07">NOT</span> <span style="color:#719e07">NULL</span>, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>resource_id<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">256</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span><span style="color:#719e07">table_name</span><span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">32</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>pk<span style="color:#719e07">`</span> <span style="color:#b58900">VARCHAR</span>(<span style="color:#2aa198">36</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>gmt_create<span style="color:#719e07">`</span> DATETIME, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">`</span>gmt_modified<span style="color:#719e07">`</span> DATETIME, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">PRIMARY</span> <span style="color:#719e07">KEY</span> (<span style="color:#719e07">`</span>row_key<span style="color:#719e07">`</span>), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">KEY</span> <span style="color:#719e07">`</span>idx_branch_id<span style="color:#719e07">`</span> (<span style="color:#719e07">`</span>branch_id<span style="color:#719e07">`</span>) |
| </span></span><span style="display:flex;"><span>) ENGINE <span style="color:#719e07">=</span> InnoDB |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">DEFAULT</span> CHARSET <span style="color:#719e07">=</span> utf8; |
| </span></span></code></pre></div><h3 id="第三步"><strong>第三步</strong></h3> |
| <p>在你的项目中引入 seata 依赖</p> |
| <p>spring-boot 应用:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span> &lt;dependency&gt; |
| </span></span><span style="display:flex;"><span> &lt;groupId&gt;io.seata&lt;/groupId&gt; |
| </span></span><span style="display:flex;"><span> &lt;artifactId&gt;seata-spring-boot-starter&lt;/artifactId&gt; |
| </span></span><span style="display:flex;"><span> &lt;version&gt;1.5.2&lt;/version&gt; |
| </span></span><span style="display:flex;"><span> &lt;/dependency&gt; |
| </span></span></code></pre></div><p>spring 应用:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span> &lt;dependency&gt; |
| </span></span><span style="display:flex;"><span> &lt;groupId&gt;io.seata&lt;/groupId&gt; |
| </span></span><span style="display:flex;"><span> &lt;artifactId&gt;seata-all&lt;/artifactId&gt; |
| </span></span><span style="display:flex;"><span> &lt;version&gt;1.5.2&lt;/version&gt; |
| </span></span><span style="display:flex;"><span> &lt;/dependency&gt; |
| </span></span></code></pre></div><h3 id="第四步"><strong>第四步</strong></h3> |
| <p>spring-boot 应用:</p> |
| <p>参考 <a href="https://github.com/seata/seata/tree/develop/script/client/spring">seata/script/client/spring at develop · seata/seata (github.com)</a></p> |
| <p>加到你项目的 application.yml中.</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#268bd2">seata</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">enabled</span>: <span style="color:#cb4b16">true</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">application-id</span>: applicationName |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">tx-service-group</span>: my_test_tx_group |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">enable-auto-data-source-proxy</span>: <span style="color:#cb4b16">true</span> <span style="color:#586e75">#仅AT与XA模式需要为true,开启后会自动代理数据源</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">data-source-proxy-mode</span>: AT <span style="color:#586e75">#可选AT&amp;XA</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">config</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">type</span>: nacos |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">nacos</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">#namespace: 如果配置创建在非默认namespace,请在此处填写namespace的id</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">serverAddr</span>: <span style="color:#2aa198">127.0.0.1</span>:<span style="color:#2aa198">8848</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">group</span>: SEATA_GROUP |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">username</span>: <span style="color:#2aa198">&#34;nacos&#34;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">password</span>: <span style="color:#2aa198">&#34;nacos&#34;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">data-id</span>: seata.properties |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">registry</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">type</span>: nacos |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">nacos</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">application</span>: seata-server |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">server-addr</span>: <span style="color:#2aa198">127.0.0.1</span>:<span style="color:#2aa198">8848</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">group</span>: SEATA_GROUP |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">#namespace: 如果配置创建在非默认namespace,请在此处填写namespace的id</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">username</span>: <span style="color:#2aa198">&#34;nacos&#34;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">password</span>: <span style="color:#2aa198">&#34;nacos&#34;</span> |
| </span></span></code></pre></div><p>spring 应用:</p> |
| <p>添加 <a href="https://github.com/seata/seata/tree/develop/script/client/conf">seata/script/client/conf at develop · seata/seata (github.com)</a> 下 registry.conf,由于高可用部署使用第三方配置中心,故无需 file.conf</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>registry { |
| </span></span><span style="display:flex;"><span> # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa、custom |
| </span></span><span style="display:flex;"><span> type = &#34;nacos&#34; |
| </span></span><span style="display:flex;"><span> nacos { |
| </span></span><span style="display:flex;"><span> application = &#34;seata-server&#34; |
| </span></span><span style="display:flex;"><span> serverAddr = &#34;127.0.0.1:8848&#34; |
| </span></span><span style="display:flex;"><span> group = &#34;SEATA_GROUP&#34; |
| </span></span><span style="display:flex;"><span> namespace = &#34;&#34; |
| </span></span><span style="display:flex;"><span> username = &#34;&#34; |
| </span></span><span style="display:flex;"><span> password = &#34;&#34; |
| </span></span><span style="display:flex;"><span> ##if use MSE Nacos with auth, mutex with username/password attribute |
| </span></span><span style="display:flex;"><span> #accessKey = &#34;&#34; |
| </span></span><span style="display:flex;"><span> #secretKey = &#34;&#34; |
| </span></span><span style="display:flex;"><span> ##if use Nacos naming meta-data for SLB service registry, specify nacos address pattern rules here |
| </span></span><span style="display:flex;"><span> #slbPattern = &#34;&#34; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>config { |
| </span></span><span style="display:flex;"><span> # file、nacos 、apollo、zk、consul、etcd3、springCloudConfig、custom |
| </span></span><span style="display:flex;"><span> type = &#34;nacos&#34; |
| </span></span><span style="display:flex;"><span> nacos { |
| </span></span><span style="display:flex;"><span> serverAddr = &#34;127.0.0.1:8848&#34; |
| </span></span><span style="display:flex;"><span> namespace = &#34;&#34; |
| </span></span><span style="display:flex;"><span> group = &#34;SEATA_GROUP&#34; |
| </span></span><span style="display:flex;"><span> username = &#34;&#34; |
| </span></span><span style="display:flex;"><span> password = &#34;&#34; |
| </span></span><span style="display:flex;"><span> ##if use MSE Nacos with auth, mutex with username/password attribute |
| </span></span><span style="display:flex;"><span> #accessKey = &#34;&#34; |
| </span></span><span style="display:flex;"><span> #secretKey = &#34;&#34; |
| </span></span><span style="display:flex;"><span> dataId = &#34;seata.properties&#34; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="第五步"><strong>第五步</strong></h3> |
| <p>运行你下载的 nacos,并参考 <a href="https://gitee.com/link?target=https%3A%2F%2Fgithub.com%2Fseata%2Fseata%2Ftree%2Fdevelop%2Fscript%2Fconfig-center">https://github.com/seata/seata/tree/develop/script/config-center</a> 的 config.txt 并修改</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-properties" data-lang="properties"><span style="display:flex;"><span><span style="color:#586e75">#仅client使用</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">#事务分组叫my_test_tx_group对应的seata-server集群为default</span> |
| </span></span><span style="display:flex;"><span>service.vgroupMapping.my_test_tx_group<span style="color:#719e07">=</span><span style="color:#2aa198">default</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">#以下仅server使用</span> |
| </span></span><span style="display:flex;"><span>store.mode<span style="color:#719e07">=</span><span style="color:#2aa198">db</span> |
| </span></span><span style="display:flex;"><span>store.db.datasource<span style="color:#719e07">=</span><span style="color:#2aa198">druid</span> |
| </span></span><span style="display:flex;"><span>store.db.dbType<span style="color:#719e07">=</span><span style="color:#2aa198">mysql</span> |
| </span></span><span style="display:flex;"><span>store.db.driverClassName<span style="color:#719e07">=</span><span style="color:#2aa198">com.mysql.jdbc.Driver</span> |
| </span></span><span style="display:flex;"><span>store.db.url<span style="color:#719e07">=</span><span style="color:#2aa198">jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true</span> |
| </span></span><span style="display:flex;"><span>store.db.user<span style="color:#719e07">=</span><span style="color:#2aa198">username</span> |
| </span></span><span style="display:flex;"><span>store.db.password<span style="color:#719e07">=</span><span style="color:#2aa198">password</span> |
| </span></span><span style="display:flex;"><span>store.db.minConn<span style="color:#719e07">=</span><span style="color:#2aa198">5</span> |
| </span></span><span style="display:flex;"><span>store.db.maxConn<span style="color:#719e07">=</span><span style="color:#2aa198">30</span> |
| </span></span><span style="display:flex;"><span>store.db.globalTable<span style="color:#719e07">=</span><span style="color:#2aa198">global_table</span> |
| </span></span><span style="display:flex;"><span>store.db.branchTable<span style="color:#719e07">=</span><span style="color:#2aa198">branch_table</span> |
| </span></span><span style="display:flex;"><span>store.db.queryLimit<span style="color:#719e07">=</span><span style="color:#2aa198">100</span> |
| </span></span><span style="display:flex;"><span>store.db.lockTable<span style="color:#719e07">=</span><span style="color:#2aa198">lock_table</span> |
| </span></span><span style="display:flex;"><span>store.db.maxWait<span style="color:#719e07">=</span><span style="color:#2aa198">5000</span> |
| </span></span></code></pre></div><p>打开 nacos 控制台,在对应的 namespace 下创建 dataId 为 seata.properties 的配置,并填写 group 为 SEATA_GROUP,并将以上内容填入选择类型为 properties 保存 |
| <img src="https://dubbo.apache.org/imgs/blog/Dingtalk_20220724021635.jpg" alt="Dingtalk_20220724021635.jpg.png" style="zoom:50%;" /></p> |
| <h3 id="第六步"><strong>第六步</strong></h3> |
| <p>更改 server 中的 application.yml</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#268bd2">server</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">port</span>: <span style="color:#2aa198">7091</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">spring</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">application</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">name</span>: seata-server |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">logging</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">config</span>: classpath:logback-spring.xml |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">file</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">path</span>: ${user.home}/logs/seata |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">console</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">user</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">username</span>: seata |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">password</span>: seata |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">seata</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">config</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75"># support: nacos, consul, apollo, zk, etcd3</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">type</span>: nacos |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">nacos</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">server-addr</span>: <span style="color:#2aa198">127.0.0.1</span>:<span style="color:#2aa198">8848</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">#namespace: 如果配置创建在非默认namespace,请在此处填写namespace的id</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">group</span>: SEATA_GROUP |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">username</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">password</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">##if use MSE Nacos with auth, mutex with username/password attribute</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">#access-key: &#34;&#34;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">#secret-key: &#34;&#34;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">data-id</span>: seata.properties |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">registry</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75"># support: nacos, eureka, redis, zk, consul, etcd3, sofa</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">type</span>: nacos |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">nacos</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">application</span>: seata-server |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">server-addr</span>: <span style="color:#2aa198">127.0.0.1</span>:<span style="color:#2aa198">8848</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">group</span>: SEATA_GROUP |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">namespace</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">cluster</span>: default |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">#namespace: 如果配置创建在非默认namespace,请在此处填写namespace的id</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">password</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">##if use MSE Nacos with auth, mutex with username/password attribute</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">#access-key: &#34;&#34;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">#secret-key: &#34;&#34; </span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75"># server:</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75"># service-port: 8091 #If not configured, the default is &#39;${server.port} + 1000&#39;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">security</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">secretKey</span>: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017 |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">tokenValidityInMilliseconds</span>: <span style="color:#2aa198">1800000</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">ignore</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">urls</span>: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login |
| </span></span></code></pre></div><h3 id="第七步"><strong>第七步</strong></h3> |
| <p>在全局事务调用者(发起全局事务的服务)的接口上加入 @GlobalTransactional 示例如下:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">@GetMapping</span>(value <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;testCommit&#34;</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">@GlobalTransactional</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> Object <span style="color:#268bd2">testCommit</span>(<span style="color:#268bd2">@RequestParam</span>(name <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;id&#34;</span>,defaultValue <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;1&#34;</span>) Integer id, |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@RequestParam</span>(name <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;sum&#34;</span>, defaultValue <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;1&#34;</span>) Integer sum) { |
| </span></span><span style="display:flex;"><span> Boolean ok <span style="color:#719e07">=</span> productService.reduceStock(id, sum); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">if</span> (ok) { |
| </span></span><span style="display:flex;"><span> LocalDateTime now <span style="color:#719e07">=</span> LocalDateTime.now(); |
| </span></span><span style="display:flex;"><span> Orders orders <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> Orders(); |
| </span></span><span style="display:flex;"><span> orders.setCreateTime(now); |
| </span></span><span style="display:flex;"><span> orders.setProductId(id); |
| </span></span><span style="display:flex;"><span> orders.setReplaceTime(now); |
| </span></span><span style="display:flex;"><span> orders.setSum(sum); |
| </span></span><span style="display:flex;"><span> orderService.save(orders); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;ok&#34;</span>; |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">else</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;fail&#34;</span>; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>spring 应用在使用 AT 或 XA 模式下需手动代理数据源选择事务模式和初始化事务扫描器</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">@Primary</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">@Bean</span>(<span style="color:#2aa198">&#34;dataSource&#34;</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> DataSource <span style="color:#268bd2">dataSource</span>(DataSource druidDataSource) { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//AT 代理 二选一</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#719e07">new</span> DataSourceProxy(druidDataSource); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//XA 代理</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#719e07">new</span> DataSourceProxyXA(druidDataSource) |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span> <span style="color:#268bd2">@Bean</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> GlobalTransactionScanner <span style="color:#268bd2">globalTransactionScanner</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#719e07">new</span> GlobalTransactionScanner(<span style="color:#2aa198">&#34;应用名&#34;</span>, <span style="color:#2aa198">&#34;my_test_tx_group&#34;</span>); |
| </span></span><span style="display:flex;"><span> } |
| </span></span></code></pre></div><p>如果使用 tcc 模式,需要额外在对应的 provider 的 serviceimpl 中定义两阶段的 try 和 confirm(commit) cancel(rollback)</p> |
| <p>spring-boot 应用需关闭数据源代理</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#268bd2">seata</span>: |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">enable-auto-data-source-proxy</span>: <span style="color:#cb4b16">false</span> |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">/** |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * 定义两阶段提交 name = 该tcc的bean名称,全局唯一 commitMethod = commit 为二阶段确认方法 rollbackMethod = rollback 为二阶段取消方法 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * useTCCFence=true 为开启防悬挂 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * BusinessActionContextParameter注解 传递参数到二阶段中 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @param params -入参 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @return String |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> */</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">@TwoPhaseBusinessAction</span>(name <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;beanName&#34;</span>, commitMethod <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;commit&#34;</span>, rollbackMethod <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;rollback&#34;</span>, useTCCFence <span style="color:#719e07">=</span> <span style="color:#cb4b16">true</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">insert</span>(<span style="color:#268bd2">@BusinessActionContextParameter</span>(paramName <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;params&#34;</span>) Map<span style="color:#719e07">&lt;</span>String, String<span style="color:#719e07">&gt;</span> params) { |
| </span></span><span style="display:flex;"><span> logger.info(<span style="color:#2aa198">&#34;此处可以预留资源,或者利用tcc的特点,与AT混用,二阶段时利用一阶段在此处存放的消息,通过二阶段发出,比如redis,mq等操作&#34;</span>); |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">/** |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * 确认方法、可以另命名,但要保证与commitMethod一致 context可以传递try方法的参数 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @param context 上下文 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @return boolean |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> */</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">commit</span>(BusinessActionContext context) { |
| </span></span><span style="display:flex;"><span> logger.info(<span style="color:#2aa198">&#34;预留资源真正处理,或者发出mq消息和redis入库&#34;</span>); |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">/** |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * 二阶段取消方法 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @param context 上下文 |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @return boolean |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> */</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">rollback</span>(BusinessActionContext context) { |
| </span></span><span style="display:flex;"><span> logger.info(<span style="color:#2aa198">&#34;预留资源释放,或清除一阶段准备让二阶段提交时发出的消息缓存&#34;</span>); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>linux/macos</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#b58900">cd</span> bin |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>sh seata-server.sh |
| </span></span></code></pre></div><p>windows</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span><span style="color:#b58900">cd</span> bin |
| </span></span><span style="display:flex;"><span>./seata-server.bat |
| </span></span></code></pre></div><p>运行 seata-server,成功后,运行自己的服务 dubbo provider&amp;consumer</p> |
| <h3 id="第八步高可用-seata-server-搭建"><strong>第八步高可用 Seata-server 搭建</strong></h3> |
| <p>由于 seata-server 支持计算与存储分离模式,并支持暴露服务地址至多种注册中心,仅需按照第六步配置完毕后水平扩展即可</p> |
| <blockquote> |
| <p>详情请访问: <a href="https://seata.io/">seata官网</a></p> |
| </blockquote></description></item><item><title>Overview: 分组聚合</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/group-merger/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/group-merger/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>通过分组对结果进行聚合并返回聚合后的结果,比如菜单服务,用 group 区分同一接口的多种实现,现在消费方需从每种 group 中调用一次并返回结果,对结果进行合并之后返回,这样就可以实现聚合菜单项。</p> |
| <p>相关代码可以参考 <a href="https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-merge">dubbo 项目中的示例</a></p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>将多个服务提供者分组作为一个提供者进行访问。应用程序能够像访问一个服务一样访问多个服务,并允许更有效地使用资源。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="搜索所有分组">搜索所有分组</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.xxx.MenuService&#34;</span> group=<span style="color:#2aa198">&#34;*&#34;</span> merger=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="合并指定分组">合并指定分组</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.xxx.MenuService&#34;</span> group=<span style="color:#2aa198">&#34;aaa,bbb&#34;</span> merger=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="指定方法合并">指定方法合并</h3> |
| <p>指定方法合并结果,其它未指定的方法,将只调用一个 Group</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.xxx.MenuService&#34;</span> group=<span style="color:#2aa198">&#34;*&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:method</span> name=<span style="color:#2aa198">&#34;getMenuItems&#34;</span> merger=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dubbo:reference&gt;</span> |
| </span></span></code></pre></div><h3 id="某个方法不合并">某个方法不合并</h3> |
| <p>某个方法不合并结果,其它都合并结果</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.xxx.MenuService&#34;</span> group=<span style="color:#2aa198">&#34;*&#34;</span> merger=<span style="color:#2aa198">&#34;true&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:method</span> name=<span style="color:#2aa198">&#34;getMenuItems&#34;</span> merger=<span style="color:#2aa198">&#34;false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dubbo:reference&gt;</span> |
| </span></span></code></pre></div><h3 id="指定合并策略">指定合并策略</h3> |
| <p>指定合并策略,缺省根据返回值类型自动匹配,如果同一类型有两个合并器时,需指定合并器的名称 <a href="../../../reference-manual/spi/description/merger">合并结果扩展</a></p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.xxx.MenuService&#34;</span> group=<span style="color:#2aa198">&#34;*&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:method</span> name=<span style="color:#2aa198">&#34;getMenuItems&#34;</span> merger=<span style="color:#2aa198">&#34;mymerge&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dubbo:reference&gt;</span> |
| </span></span></code></pre></div><h3 id="指定合并方法">指定合并方法</h3> |
| <p>指定合并方法,将调用返回结果的指定方法进行合并,合并方法的参数类型必须是返回结果类型本身</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.xxx.MenuService&#34;</span> group=<span style="color:#2aa198">&#34;*&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:method</span> name=<span style="color:#2aa198">&#34;getMenuItems&#34;</span> merger=<span style="color:#2aa198">&#34;.addAll&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dubbo:reference&gt;</span> |
| </span></span></code></pre></div> |
| <div class="alert alert-primary" role="alert"> |
| <h4 class="alert-heading">提示</h4> |
| <code>2.1.0</code> 开始支持 |
| </div></description></item><item><title>Overview: 服务分版本</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-versions/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-versions/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p><strong>按照以下的步骤进行版本迁移</strong></p> |
| <ol> |
| <li>在低压力时间段,先升级一半提供者为新版本</li> |
| <li>再将所有消费者升级为新版本</li> |
| <li>然后将剩下的一半提供者升级为新版本</li> |
| </ol> |
| <h4 id="配置">配置</h4> |
| <ul> |
| <li>新老版本服务提供者</li> |
| <li>新老版本服务消费者</li> |
| </ul> |
| <h2 id="使用场景">使用场景</h2> |
| <p>当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。</p> |
| <blockquote> |
| <p>参考用例 |
| <a href="https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-version">https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-version</a></p> |
| </blockquote> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="服务提供者">服务提供者</h3> |
| <p>老版本服务提供者配置</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>新版本服务提供者配置</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> version=<span style="color:#2aa198">&#34;2.0.0&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="服务消费者">服务消费者</h3> |
| <p>老版本服务消费者配置</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;barService&#34;</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>新版本服务消费者配置</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;barService&#34;</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> version=<span style="color:#2aa198">&#34;2.0.0&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="不区分版本">不区分版本</h3> |
| <p>如果不需要区分版本,可以按照以下的方式配置</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;barService&#34;</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> version=<span style="color:#2aa198">&#34;*&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div></description></item><item><title>Overview: 启动时检查</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/preflight-check/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/preflight-check/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 <code>check=&quot;true&quot;</code>。</p> |
| <p>可以通过 <code>check=&quot;false&quot;</code> 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。</p> |
| <p>另外,如果你的 Spring 容器是懒加载的,或者通过 API 编程延迟引用服务,请关闭 check,否则服务临时不可用时,会抛出异常,拿到 null 引用,如果 <code>check=&quot;false&quot;</code>,总是会返回引用,当服务恢复时,能自动连上。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <ul> |
| <li>单向依赖:有依赖关系(建议默认设置)和无依赖关系(可以设置 check=false)</li> |
| <li>相互依赖:即循环依赖,(不建议设置 check=false)</li> |
| <li>延迟加载处理</li> |
| </ul> |
| <blockquote> |
| <p>check 只用来启动时检查,运行时没有相应的依赖仍然会报错。</p> |
| </blockquote> |
| <h2 id="使用方式">使用方式</h2> |
| <p><strong>配置含义</strong></p> |
| <p><code>dubbo.reference.com.foo.BarService.check</code>,覆盖 <code>com.foo.BarService</code>的 reference 的 check 值,就算配置中有声明,也会被覆盖。</p> |
| <p><code>dubbo.consumer.check=false</code>,是设置 reference 的 <code>check</code> 的缺省值,如果配置中有显式的声明,如:<code>&lt;dubbo:reference check=&quot;true&quot;/&gt;</code>,不会受影响。</p> |
| <p><code>dubbo.registry.check=false</code>,前面两个都是指订阅成功,但提供者列表是否为空是否报错,如果注册订阅失败时,也允许启动,需使用此选项,将在后台定时重试。</p> |
| <h3 id="通过-spring-配置文件">通过 spring 配置文件</h3> |
| <p>关闭某个服务的启动时检查</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> check=<span style="color:#2aa198">&#34;false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>关闭所有服务的启动时检查</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:consumer</span> check=<span style="color:#2aa198">&#34;false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>关闭注册中心启动时检查</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> check=<span style="color:#2aa198">&#34;false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="通过-dubboproperties">通过 dubbo.properties</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-properties" data-lang="properties"><span style="display:flex;"><span>dubbo.reference.com.foo.BarService.check<span style="color:#719e07">=</span><span style="color:#2aa198">false</span> |
| </span></span><span style="display:flex;"><span>dubbo.consumer.check<span style="color:#719e07">=</span><span style="color:#2aa198">false</span> |
| </span></span><span style="display:flex;"><span>dubbo.registry.check<span style="color:#719e07">=</span><span style="color:#2aa198">false</span> |
| </span></span></code></pre></div><h3 id="通过--d-参数">通过 -D 参数</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>java -Ddubbo.reference.com.foo.BarService.check<span style="color:#719e07">=</span><span style="color:#b58900">false</span> |
| </span></span><span style="display:flex;"><span>java -Ddubbo.consumer.check<span style="color:#719e07">=</span><span style="color:#b58900">false</span> |
| </span></span><span style="display:flex;"><span>java -Ddubbo.registry.check<span style="color:#719e07">=</span><span style="color:#b58900">false</span> |
| </span></span></code></pre></div></description></item><item><title>Overview: 响应式编程</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/reactive/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/reactive/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>此特性基于 Triple 协议和 Project Reactor 实现,<code>3.1.0</code> 版本以上支持。用户仅需编写 IDL 文件,并指定 protobuf 插件的相应 Generator,即可生成并使用支持响应式API的 Stub 代码。</p> |
| <p>有四种调用模式,分别是 OneToOne、OneToMany、ManyToOne、ManyToMany,分别对应 Unary调用、服务端流、客户端流、双向流。在 Reactor 的实现中,One 对应 Mono,Many 对应 Flux。</p> |
| <p>Reactive Stream 提供了一套标准的异步流处理 API, 在能够让应用写出事件驱动的程序的同时,也通过 BackPressure 的方式保证了节点的稳定。Triple 协议在通信协议层面为 Dubbo 框架增加了流式场景的支持,在此基础上能够实现上层包括大文件传输和推送机制的业务需求。</p> |
| <p>Dubbo + Reactive Stream Stub 的组合模式可以给用户带来最方便的流式使用方式以及全链路异步性能提升。</p> |
| <blockquote> |
| <p>参考用例 |
| <a href="https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple-reactor">https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-triple-reactor</a></p> |
| </blockquote> |
| <h2 id="使用场景">使用场景</h2> |
| <p>系统需要处理大量并发请求而不会使任何服务器过载。大量用户提供实时数据的系统,希望确保系统能够处理负载而不会崩溃或变慢。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <p>Triple 使用及配置可参考 <a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/idl/">IDL 方式使用 Triple</a>,并确保 Dubbo 版本 &gt;= 3.1.0。</p> |
| <h3 id="添加必要的依赖">添加必要的依赖</h3> |
| <p>若要使用 Reactor Triple,需要额外添加如下依赖。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.reactivestreams<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>reactive-streams<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>io.projectreactor<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>reactor-core<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span></code></pre></div><h3 id="设置-protobuf-maven-插件">设置 protobuf Maven 插件</h3> |
| <p>仅需将 mainClass 修改为 <code>org.apache.dubbo.gen.tri.reactive.ReactorDubbo3TripleGenerator</code>,并确保 <code>${compiler.version}</code> &gt;= 3.1.0</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;build&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;plugins&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;plugin&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.xolstice.maven.plugins<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>protobuf-maven-plugin<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>0.6.1<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;configuration&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;protocArtifact&gt;</span>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/protocArtifact&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;pluginId&gt;</span>grpc-java<span style="color:#268bd2">&lt;/pluginId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;pluginArtifact&gt;</span>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/pluginArtifact&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;protocPlugins&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;protocPlugin&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;id&gt;</span>dubbo<span style="color:#268bd2">&lt;/id&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.apache.dubbo<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>dubbo-compiler<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>${compiler.version}<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;mainClass&gt;</span>org.apache.dubbo.gen.tri.reactive.ReactorDubbo3TripleGenerator<span style="color:#268bd2">&lt;/mainClass&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/protocPlugin&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/protocPlugins&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/configuration&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;executions&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;execution&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;goals&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;goal&gt;</span>compile<span style="color:#268bd2">&lt;/goal&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/goals&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/execution&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/executions&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/plugin&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/plugins&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/build&gt;</span> |
| </span></span></code></pre></div><h3 id="编写并编译-idl-文件">编写并编译 IDL 文件</h3> |
| <p>IDL 文件编写与原生的 Triple 协议完全一致,编译后默认会在 <code>target/generated-sources/protobuf/java</code> 目录下看到相应代码。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-protobuf" data-lang="protobuf"><span style="display:flex;"><span>syntax <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;proto3&#34;</span>; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">option</span> java_multiple_files <span style="color:#719e07">=</span> <span style="color:#cb4b16">true</span>; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">package</span> org<span style="color:#719e07">.</span>apache.dubbo.samples.triple.reactor; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// The request message containing the user&#39;s name. |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span><span style="color:#268bd2">message</span> <span style="color:#268bd2">GreeterRequest</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">string</span> name <span style="color:#719e07">=</span> <span style="color:#2aa198">1</span>; |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// The response message containing the greetings |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"></span><span style="color:#268bd2">message</span> <span style="color:#268bd2">GreeterReply</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">string</span> <span style="color:#268bd2">message</span> <span style="color:#719e07">=</span> <span style="color:#2aa198">1</span>; |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">service</span> GreeterService { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">rpc</span> greetOneToOne(GreeterRequest) <span style="color:#719e07">returns</span> (GreeterReply); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">rpc</span> greetOneToMany(GreeterRequest) <span style="color:#719e07">returns</span> (stream GreeterReply); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">rpc</span> greetManyToOne(stream GreeterRequest) <span style="color:#719e07">returns</span> (GreeterReply); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">rpc</span> greetManyToMany(stream GreeterRequest) <span style="color:#719e07">returns</span> (stream GreeterReply); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="使用示例">使用示例</h3> |
| <ol> |
| <li>添加服务端接口实现</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">package</span> org.apache.dubbo.samples.triple.reactor.impl; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.samples.triple.reactor.DubboGreeterServiceTriple; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.samples.triple.reactor.GreeterReply; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.samples.triple.reactor.GreeterRequest; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.slf4j.Logger; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.slf4j.LoggerFactory; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> reactor.core.publisher.Flux; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">GreeterServiceImpl</span> <span style="color:#268bd2">extends</span> DubboGreeterServiceTriple.GreeterServiceImplBase { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> Logger LOGGER <span style="color:#719e07">=</span> LoggerFactory.getLogger(GreeterServiceImpl.class); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Flux<span style="color:#719e07">&lt;</span>GreeterReply<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">greetManyToMany</span>(Flux<span style="color:#719e07">&lt;</span>GreeterRequest<span style="color:#719e07">&gt;</span> request) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> request.doOnNext(req <span style="color:#719e07">-&gt;</span> LOGGER.info(<span style="color:#2aa198">&#34;greetManyToMany get data: {}&#34;</span>, req)) |
| </span></span><span style="display:flex;"><span> .map(req <span style="color:#719e07">-&gt;</span> GreeterReply.newBuilder().setMessage(req.getName() <span style="color:#719e07">+</span> <span style="color:#2aa198">&#34; -&gt; server get&#34;</span>).build()) |
| </span></span><span style="display:flex;"><span> .doOnNext(res <span style="color:#719e07">-&gt;</span> LOGGER.info(<span style="color:#2aa198">&#34;greetManyToMany response data: {}&#34;</span>, res)); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><ol start="2"> |
| <li>添加服务端接口启动类</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">package</span> org.apache.dubbo.samples.triple.reactor; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.common.constants.CommonConstants; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.config.ApplicationConfig; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.config.ProtocolConfig; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.config.RegistryConfig; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.config.ServiceConfig; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.config.bootstrap.DubboBootstrap; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.samples.triple.reactor.impl.GreeterServiceImpl; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">ReactorServer</span> { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> <span style="color:#dc322f">int</span> PORT <span style="color:#719e07">=</span> 50052; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">static</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">main</span>(String<span style="color:#719e07">[]</span> args) { |
| </span></span><span style="display:flex;"><span> ServiceConfig<span style="color:#719e07">&lt;</span>GreeterService<span style="color:#719e07">&gt;</span> reactorService <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ServiceConfig<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span> reactorService.setInterface(GreeterService.class); |
| </span></span><span style="display:flex;"><span> reactorService.setRef(<span style="color:#719e07">new</span> GreeterServiceImpl()); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> DubboBootstrap bootstrap <span style="color:#719e07">=</span> DubboBootstrap.getInstance(); |
| </span></span><span style="display:flex;"><span> bootstrap.application(<span style="color:#719e07">new</span> ApplicationConfig(<span style="color:#2aa198">&#34;tri-reactor-stub-server&#34;</span>)) |
| </span></span><span style="display:flex;"><span> .registry(<span style="color:#719e07">new</span> RegistryConfig(<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2181&#34;</span>)) |
| </span></span><span style="display:flex;"><span> .protocol(<span style="color:#719e07">new</span> ProtocolConfig(CommonConstants.TRIPLE, PORT)) |
| </span></span><span style="display:flex;"><span> .service(reactorService) |
| </span></span><span style="display:flex;"><span> .start(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><ol start="3"> |
| <li>添加客户端启动类和消费程序</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">package</span> org.apache.dubbo.samples.triple.reactor; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.common.constants.CommonConstants; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.config.ApplicationConfig; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.config.ReferenceConfig; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.config.RegistryConfig; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.config.bootstrap.DubboBootstrap; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.slf4j.Logger; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.slf4j.LoggerFactory; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> reactor.core.publisher.Flux; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> reactor.core.publisher.Mono; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> java.io.IOException; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">ReactorConsumer</span> { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> Logger LOGGER <span style="color:#719e07">=</span> LoggerFactory.getLogger(ReactorConsumer.class); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> GreeterService greeterService; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">ReactorConsumer</span>() { |
| </span></span><span style="display:flex;"><span> ReferenceConfig<span style="color:#719e07">&lt;</span>GreeterService<span style="color:#719e07">&gt;</span> referenceConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ReferenceConfig<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span> referenceConfig.setInterface(GreeterService.class); |
| </span></span><span style="display:flex;"><span> referenceConfig.setProtocol(CommonConstants.TRIPLE); |
| </span></span><span style="display:flex;"><span> referenceConfig.setProxy(CommonConstants.NATIVE_STUB); |
| </span></span><span style="display:flex;"><span> referenceConfig.setTimeout(10000); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> DubboBootstrap bootstrap <span style="color:#719e07">=</span> DubboBootstrap.getInstance(); |
| </span></span><span style="display:flex;"><span> bootstrap.application(<span style="color:#719e07">new</span> ApplicationConfig(<span style="color:#2aa198">&#34;tri-reactor-stub-server&#34;</span>)) |
| </span></span><span style="display:flex;"><span> .registry(<span style="color:#719e07">new</span> RegistryConfig(<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2181&#34;</span>)) |
| </span></span><span style="display:flex;"><span> .reference(referenceConfig) |
| </span></span><span style="display:flex;"><span> .start(); |
| </span></span><span style="display:flex;"><span> GreeterService greeterService <span style="color:#719e07">=</span> referenceConfig.get(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">static</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">main</span>(String<span style="color:#719e07">[]</span> args) <span style="color:#268bd2">throws</span> IOException { |
| </span></span><span style="display:flex;"><span> ReactorConsumer reactorConsumer <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ReactorConsumer(); |
| </span></span><span style="display:flex;"><span> reactorConsumer.consumeManyToMany(); |
| </span></span><span style="display:flex;"><span> System.in.read(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">consumeManyToMany</span>() { |
| </span></span><span style="display:flex;"><span> greeterService.greetManyToMany(Flux.range(1, 10) |
| </span></span><span style="display:flex;"><span> .map(num <span style="color:#719e07">-&gt;</span> |
| </span></span><span style="display:flex;"><span> GreeterRequest.newBuilder().setName(String.valueOf(num)).build()) |
| </span></span><span style="display:flex;"><span> .doOnNext(req <span style="color:#719e07">-&gt;</span> LOGGER.info(<span style="color:#2aa198">&#34;consumeManyToMany request data: {}&#34;</span>, req))) |
| </span></span><span style="display:flex;"><span> .subscribe(res <span style="color:#719e07">-&gt;</span> LOGGER.info(<span style="color:#2aa198">&#34;consumeManyToMany get response: {}&#34;</span>, res)); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><ol start="4"> |
| <li> |
| <p>启动服务端</p> |
| </li> |
| <li> |
| <p>启动消费者端</p> |
| </li> |
| </ol></description></item><item><title>Overview: 参数校验</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/parameter-validation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/parameter-validation/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>参数验证功能是基于 <a href="https://jcp.org/en/jsr/detail?id=303">JSR303</a> 实现的,用户只需标识 JSR303 标准的验证 annotation,并通过声明 filter 来实现验证。</p> |
| <h4 id="maven-依赖">Maven 依赖</h4> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>javax.validation<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>validation-api<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>1.0.0.GA<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.hibernate<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>hibernate-validator<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>4.2.0.Final<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span></code></pre></div><h2 id="使用场景">使用场景</h2> |
| <p>服务端在向外提供接口服务时,解决各种接口参数校验问题。</p> |
| <blockquote> |
| <p>参考用例 |
| <a href="https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-validation">https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-validation</a></p> |
| </blockquote> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="参数标注示例">参数标注示例</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">import</span> java.io.Serializable; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> java.util.Date; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.constraints.Future; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.constraints.Max; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.constraints.Min; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.constraints.NotNull; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.constraints.Past; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.constraints.Pattern; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.constraints.Size; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">ValidationParameter</span> <span style="color:#268bd2">implements</span> Serializable { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> <span style="color:#dc322f">long</span> serialVersionUID <span style="color:#719e07">=</span> 7158911668568000392L; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@NotNull</span> <span style="color:#586e75">// 不允许为空</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Size</span>(min <span style="color:#719e07">=</span> 1, max <span style="color:#719e07">=</span> 20) <span style="color:#586e75">// 长度或大小范围</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> String name; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@NotNull</span>(groups <span style="color:#719e07">=</span> ValidationService.Save.class) <span style="color:#586e75">// 保存时不允许为空,更新时允许为空 ,表示不更新该字段</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Pattern</span>(regexp <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$&#34;</span>) |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> String email; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Min</span>(18) <span style="color:#586e75">// 最小值</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Max</span>(100) <span style="color:#586e75">// 最大值</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#dc322f">int</span> age; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Past</span> <span style="color:#586e75">// 必须为一个过去的时间</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> Date loginDate; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Future</span> <span style="color:#586e75">// 必须为一个未来的时间</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> Date expiryDate; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">getName</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> name; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">setName</span>(String name) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span>.name <span style="color:#719e07">=</span> name; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">getEmail</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> email; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">setEmail</span>(String email) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span>.email <span style="color:#719e07">=</span> email; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">int</span> <span style="color:#268bd2">getAge</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> age; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">setAge</span>(<span style="color:#dc322f">int</span> age) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span>.age <span style="color:#719e07">=</span> age; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Date <span style="color:#268bd2">getLoginDate</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> loginDate; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">setLoginDate</span>(Date loginDate) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span>.loginDate <span style="color:#719e07">=</span> loginDate; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Date <span style="color:#268bd2">getExpiryDate</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> expiryDate; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">setExpiryDate</span>(Date expiryDate) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span>.expiryDate <span style="color:#719e07">=</span> expiryDate; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="分组验证示例">分组验证示例</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">ValidationService</span> { <span style="color:#586e75">// 缺省可按服务接口区分验证场景,如:@NotNull(groups = ValidationService.class) </span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@interface</span> Save{} <span style="color:#586e75">// 与方法同名接口,首字母大写,用于区分验证场景,如:@NotNull(groups = ValidationService.Save.class),可选</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">save</span>(ValidationParameter parameter); |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">update</span>(ValidationParameter parameter); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="关联验证示例">关联验证示例</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.GroupSequence; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">ValidationService</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@GroupSequence</span>(Update.class) <span style="color:#586e75">// 同时验证Update组规则</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@interface</span> Save{} |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">save</span>(ValidationParameter parameter); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@interface</span> Update{} |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">update</span>(ValidationParameter parameter); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="参数验证示例">参数验证示例</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.constraints.Min; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.constraints.NotNull; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">ValidationService</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">save</span>(<span style="color:#268bd2">@NotNull</span> ValidationParameter parameter); <span style="color:#586e75">// 验证参数不为空</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">delete</span>(<span style="color:#268bd2">@Min</span>(1) <span style="color:#dc322f">int</span> id); <span style="color:#586e75">// 直接对基本类型参数验证</span> |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="在客户端验证参数">在客户端验证参数</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;validationService&#34;</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.examples.validation.api.ValidationService&#34;</span> validation=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="在服务器端验证参数">在服务器端验证参数</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.examples.validation.api.ValidationService&#34;</span> ref=<span style="color:#2aa198">&#34;validationService&#34;</span> validation=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><blockquote> |
| <p><strong>Dubbo 默认支持 hibernate-validator 版本 &lt;=6.x,若使用 hibernate-validator 7.x 版本,请将 validation 参数声明为 jvalidationNew</strong></p> |
| </blockquote> |
| <blockquote> |
| <p>如果需要启动客户端验证,并且使用jdk17,择需添加jvm启动参数<code>--add-opens java.base/java.lang=ALL-UNNAMED</code>做兼容处理.</p> |
| </blockquote> |
| <h3 id="验证异常信息">验证异常信息</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.ConstraintViolationException; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> javax.validation.ConstraintViolationException; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.springframework.context.support.ClassPathXmlApplicationContext; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.examples.validation.api.ValidationParameter; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.examples.validation.api.ValidationService; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> org.apache.dubbo.rpc.RpcException; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">ValidationConsumer</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">static</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">main</span>(String<span style="color:#719e07">[]</span> args) <span style="color:#268bd2">throws</span> Exception { |
| </span></span><span style="display:flex;"><span> String config <span style="color:#719e07">=</span> ValidationConsumer.class.getPackage().getName().replace(<span style="color:#2aa198">&#39;.&#39;</span>, <span style="color:#2aa198">&#39;/&#39;</span>) <span style="color:#719e07">+</span> <span style="color:#2aa198">&#34;/validation-consumer.xml&#34;</span>; |
| </span></span><span style="display:flex;"><span> ClassPathXmlApplicationContext context <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ClassPathXmlApplicationContext(config); |
| </span></span><span style="display:flex;"><span> context.start(); |
| </span></span><span style="display:flex;"><span> ValidationService validationService <span style="color:#719e07">=</span> (ValidationService)context.getBean(<span style="color:#2aa198">&#34;validationService&#34;</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// Error</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> parameter <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ValidationParameter(); |
| </span></span><span style="display:flex;"><span> validationService.save(parameter); |
| </span></span><span style="display:flex;"><span> System.out.println(<span style="color:#2aa198">&#34;Validation ERROR&#34;</span>); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (RpcException e) { <span style="color:#586e75">// 抛出的是RpcException</span> |
| </span></span><span style="display:flex;"><span> ConstraintViolationException ve <span style="color:#719e07">=</span> (ConstraintViolationException) e.getCause(); <span style="color:#586e75">// 里面嵌了一个ConstraintViolationException</span> |
| </span></span><span style="display:flex;"><span> Set<span style="color:#719e07">&lt;</span>ConstraintViolation<span style="color:#719e07">&lt;?&gt;&gt;</span> violations <span style="color:#719e07">=</span> ve.getConstraintViolations(); <span style="color:#586e75">// 可以拿到一个验证错误详细信息的集合</span> |
| </span></span><span style="display:flex;"><span> System.out.println(violations); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><blockquote> |
| <p><strong>验证方式可扩展,扩展方式参见开发者手册中的 <a href="../../../reference-manual/spi/description/validation">验证扩展</a></strong></p> |
| </blockquote></description></item><item><title>Overview: 服务分组</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/service-group/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/service-group/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>同一个接口针对不同的业务场景、不同的使用需求或者不同的功能模块等场景,可使用服务分组来区分不同的实现方式。同时,这些不同实现所提供的服务是可并存的,也支持互相调用。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>当一个接口有多种实现时,可以用 group 区分。</p> |
| <blockquote> |
| <p>参考用例 |
| <a href="https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-group">https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-group</a></p> |
| </blockquote> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="注解配置">注解配置</h3> |
| <h4 id="服务提供端注解配置">服务提供端(注解配置)</h4> |
| <p>使用 @DubboService 注解,添加 group 参数</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">@DubboService</span>(group <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;demo&#34;</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">DemoServiceImpl</span> <span style="color:#268bd2">implements</span> DemoService { |
| </span></span><span style="display:flex;"><span> ... |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">@DubboService</span>(group <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;demo2&#34;</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">Demo2ServiceImpl</span> <span style="color:#268bd2">implements</span> DemoService { |
| </span></span><span style="display:flex;"><span> ... |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>启动 Dubbo 服务,可在注册中心看到相同服务名不同分组的服务,以 Nacos 作为注册中心为例,显示如下内容:</p> |
| <p><img src="https://dubbo.apache.org/imgs/blog/service-group-1.png" alt="image-service-group-1.png"></p> |
| <h4 id="服务消费端注解配置">服务消费端(注解配置)</h4> |
| <p>使用 @DubboReference 注解,添加 group 参数</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">@DubboReference</span>(group <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;demo&#34;</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">private</span> DemoService demoService; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">@DubboReference</span>(group <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;demo2&#34;</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">private</span> DemoService demoService2; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">//group值为*,标识匹配任意服务分组</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">@DubboReference</span>(group <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;*&#34;</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">private</span> DemoService demoService2; |
| </span></span></code></pre></div><p>同样启动 Dubbo 服务后,可在注册中心看到相同服务名不同分组的引用者,以 Nacos 作为注册中心为例,显示如下内容: |
| <img src="https://dubbo.apache.org/imgs/blog/service-group-2.png" alt="image-service-group-2.png"></p> |
| <h3 id="xml配置">xml配置</h3> |
| <h4 id="服务提供端-xml-配置">服务提供端( xml 配置)</h4> |
| <p>使用 &lt;dubbo:service /&gt; 标签,添加 group 参数</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#719e07">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;beans</span> xmlns=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:xsi=<span style="color:#2aa198">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:dubbo=<span style="color:#2aa198">&#34;http://dubbo.apache.org/schema/dubbo&#34;</span> |
| </span></span><span style="display:flex;"><span> xsi:schemaLocation=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans |
| </span></span></span><span style="display:flex;"><span><span style="color:#2aa198"> http://www.springframework.org/schema/beans/spring-beans-4.3.xsd |
| </span></span></span><span style="display:flex;"><span><span style="color:#2aa198"> http://dubbo.apache.org/schema/dubbo |
| </span></span></span><span style="display:flex;"><span><span style="color:#2aa198"> http://dubbo.apache.org/schema/dubbo/dubbo.xsd&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> ... |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.example.service.DemoService&#34;</span> group=<span style="color:#2aa198">&#34;demo&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.example.service.DemoService&#34;</span> group=<span style="color:#2aa198">&#34;demo2&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span>... |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/beans&gt;</span> |
| </span></span></code></pre></div><p>启动 Dubbo 服务,可在注册中心看到相同服务名不同分组的服务,以 Nacos 作为注册中心为例,显示如下内容:</p> |
| <p><img src="https://dubbo.apache.org/imgs/blog/service-group-1.png" alt="image-service-group-1.png"></p> |
| <h4 id="服务消费端-xml-配置">服务消费端( xml 配置)</h4> |
| <p>使用 <a href="dubbo:reference/">dubbo:reference/</a> 注解,添加 group 参数</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#719e07">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;beans</span> xmlns=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:xsi=<span style="color:#2aa198">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:dubbo=<span style="color:#2aa198">&#34;http://dubbo.apache.org/schema/dubbo&#34;</span> |
| </span></span><span style="display:flex;"><span> xsi:schemaLocation=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans |
| </span></span></span><span style="display:flex;"><span><span style="color:#2aa198"> http://www.springframework.org/schema/beans/spring-beans-4.3.xsd |
| </span></span></span><span style="display:flex;"><span><span style="color:#2aa198"> http://dubbo.apache.org/schema/dubbo |
| </span></span></span><span style="display:flex;"><span><span style="color:#2aa198"> http://dubbo.apache.org/schema/dubbo/dubbo.xsd&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> ... |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 引用服务接口 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.example.service.DemoService&#34;</span> group=<span style="color:#2aa198">&#34;demo&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService2&#34;</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.example.service.DemoService&#34;</span> group=<span style="color:#2aa198">&#34;demo2&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- group值为*,标识匹配任意服务分组 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService3&#34;</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.example.service.DemoService&#34;</span> group=<span style="color:#2aa198">&#34;*&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> ... |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/beans&gt;</span> |
| </span></span></code></pre></div><p>同样启动 Dubbo 服务后,可在注册中心看到相同服务名不同分组的引用者,以 Nacos 作为注册中心为例,显示如下内容:</p> |
| <p><img src="https://dubbo.apache.org/imgs/blog/service-group-2.png" alt="image-service-group-2.png"></p> |
| <h3 id="api配置">API配置</h3> |
| <h4 id="服务提供端-api-配置">服务提供端( API 配置)</h4> |
| <p>使用 org.apache.dubbo.config.ServiceConfig 类,添加 group 参数</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">// ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 请自行缓存,否则可能造成内存和连接泄漏</span> |
| </span></span><span style="display:flex;"><span>ServiceConfig<span style="color:#719e07">&lt;</span>DemoService<span style="color:#719e07">&gt;</span> service <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ServiceConfig<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span>service.setInterface(DemoService.class); |
| </span></span><span style="display:flex;"><span>service.setGroup(<span style="color:#2aa198">&#34;demo&#34;</span>); |
| </span></span><span style="display:flex;"><span>... |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>ServiceConfig<span style="color:#719e07">&lt;</span>DemoService<span style="color:#719e07">&gt;</span> service2 <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ServiceConfig<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span>service.setInterface(DemoService.class); |
| </span></span><span style="display:flex;"><span>service.setGroup(<span style="color:#2aa198">&#34;demo2&#34;</span>); |
| </span></span><span style="display:flex;"><span>... |
| </span></span></code></pre></div><p>启动 Dubbo 服务,可在注册中心看到相同服务名不同分组的服务,以 Nacos 作为注册中心为例,显示如下内容:</p> |
| <p><img src="https://dubbo.apache.org/imgs/blog/service-group-1.png" alt="image-service-group-1.png"></p> |
| <h4 id="服务消费端-api-配置">服务消费端( API 配置)</h4> |
| <p>使用 org.apache.dubbo.config.ReferenceConfig,添加 group 参数</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">// ReferenceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 请自行缓存,否则可能造成内存和连接泄漏</span> |
| </span></span><span style="display:flex;"><span>ReferenceConfig<span style="color:#719e07">&lt;</span>DemoService<span style="color:#719e07">&gt;</span> reference <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ReferenceConfig<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span>reference.setInterface(DemoService.class); |
| </span></span><span style="display:flex;"><span>reference.setGroup(<span style="color:#2aa198">&#34;demo&#34;</span>); |
| </span></span><span style="display:flex;"><span>... |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>ReferenceConfig<span style="color:#719e07">&lt;</span>DemoService<span style="color:#719e07">&gt;</span> reference2 <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ReferenceConfig<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span>reference2.setInterface(DemoService.class); |
| </span></span><span style="display:flex;"><span>reference2.setGroup(<span style="color:#2aa198">&#34;demo2&#34;</span>); |
| </span></span><span style="display:flex;"><span>... |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>ReferenceConfig<span style="color:#719e07">&lt;</span>DemoService<span style="color:#719e07">&gt;</span> reference3 <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ReferenceConfig<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span>reference3.setInterface(DemoService.class); |
| </span></span><span style="display:flex;"><span>reference3.setGroup(<span style="color:#2aa198">&#34;*&#34;</span>); |
| </span></span><span style="display:flex;"><span>... |
| </span></span></code></pre></div><p>同样启动 Dubbo 服务后,可在注册中心看到相同服务名不同分组的引用者,以 Nacos 作为注册中心为例,显示如下内容: |
| <img src="https://dubbo.apache.org/imgs/blog/service-group-2.png" alt="image-service-group-2.png"></p> |
| <blockquote> |
| <p>总是 <strong>只调</strong> 一个可用组的实现</p> |
| </blockquote></description></item><item><title>Overview: 集群容错</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/fault-tolerent-strategy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/fault-tolerent-strategy/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。</p> |
| <p><img src="https://dubbo.apache.org/imgs/user/cluster.jpg" alt="cluster"></p> |
| <p>各节点关系:</p> |
| <ul> |
| <li>这里的 <code>Invoker</code> 是 <code>Provider</code> 的一个可调用 <code>Service</code> 的抽象,<code>Invoker</code> 封装了 <code>Provider</code> 地址及 <code>Service</code> 接口信息</li> |
| <li><code>Directory</code> 代表多个 <code>Invoker</code>,可以把它看成 <code>List&lt;Invoker&gt;</code> ,但与 <code>List</code> 不同的是,它的值可能是动态变化的,比如注册中心推送变更</li> |
| <li><code>Cluster</code> 将 <code>Directory</code> 中的多个 <code>Invoker</code> 伪装成一个 <code>Invoker</code>,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个</li> |
| <li><code>Router</code> 负责从多个 <code>Invoker</code> 中按路由规则选出子集,比如读写分离,应用隔离等</li> |
| <li><code>LoadBalance</code> 负责从多个 <code>Invoker</code> 中选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选</li> |
| </ul> |
| <p>通过使用服务注册表和负载平衡,可以提高集群提供的容错能力,服务注册表用于存储有关可用服务及其位置的信息,负载平衡用于确保请求均匀分布在集群中的所有服务器上,如果一台服务器发生故障,负载将转移到其他可用服务器。</p> |
| <p>配置监视集群中服务器运行状况的运行状况检查,如果服务器未通过运行状况检查,则可以将其从集群中删除,并将负载转移到其余服务器,确保集群正常运行,并且用户可以使用应用程序。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>多个服务器部署同一集群中,运行同一应用程序,如果一台服务器出现故障,其他服务器将接管负载,确保应用程序对用户仍然可用。</p> |
| <blockquote> |
| <p>可以自行扩展集群容错策略 <a href="../../../reference-manual/spi/description/cluster/">集群扩展</a></p> |
| </blockquote> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="failover-cluster">Failover Cluster</h3> |
| <p>失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 <code>retries=&quot;2&quot;</code> 来设置重试次数(不含第一次)。</p> |
| <p>重试次数配置如下:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> retries=<span style="color:#2aa198">&#34;2&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>或</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> retries=<span style="color:#2aa198">&#34;2&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>或</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:method</span> name=<span style="color:#2aa198">&#34;findFoo&#34;</span> retries=<span style="color:#2aa198">&#34;2&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dubbo:reference&gt;</span> |
| </span></span></code></pre></div> |
| <div class="alert alert-primary" role="alert"> |
| <h4 class="alert-heading">提示</h4> |
| 该配置为缺省配置 |
| </div> |
| <h3 id="failfast-cluster">Failfast Cluster</h3> |
| <p>快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。</p> |
| <h3 id="failsafe-cluster">Failsafe Cluster</h3> |
| <p>失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。</p> |
| <h3 id="failback-cluster">Failback Cluster</h3> |
| <p>失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。</p> |
| <h3 id="forking-cluster">Forking Cluster</h3> |
| <p>并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 <code>forks=&quot;2&quot;</code> 来设置最大并行数。</p> |
| <h3 id="broadcast-cluster">Broadcast Cluster</h3> |
| <p>广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。</p> |
| <p>现在广播调用中,可以通过 broadcast.fail.percent 配置节点调用失败的比例,当达到这个比例后,BroadcastClusterInvoker |
| 将不再调用其他节点,直接抛出异常。 broadcast.fail.percent 取值在 0~100 范围内。默认情况下当全部调用失败后,才会抛出异常。 |
| broadcast.fail.percent 只是控制的当失败后是否继续调用其他节点,并不改变结果(任意一台报错则报错)。broadcast.fail.percent 参数 |
| 在 dubbo2.7.10 及以上版本生效。</p> |
| <p>Broadcast Cluster 配置 broadcast.fail.percent。</p> |
| <p>broadcast.fail.percent=20 代表了当 20% 的节点调用失败就抛出异常,不再调用其他节点。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>@reference(cluster = &#34;broadcast&#34;, parameters = {&#34;broadcast.fail.percent&#34;, &#34;20&#34;}) |
| </span></span></code></pre></div> |
| <div class="alert alert-primary" role="alert"> |
| <h4 class="alert-heading">提示</h4> |
| <code>2.1.0</code> 开始支持 |
| </div> |
| <h3 id="available-cluster">Available Cluster</h3> |
| <p>调用目前可用的实例(只调用一个),如果当前没有可用的实例,则抛出异常。通常用于不需要负载均衡的场景。</p> |
| <h3 id="mergeable-cluster">Mergeable Cluster</h3> |
| <p>将集群中的调用结果聚合起来返回结果,通常和group一起配合使用。通过分组对结果进行聚合并返回聚合后的结果,比如菜单服务,用group区分同一接口的多种实现,现在消费方需从每种group中调用一次并返回结果,对结果进行合并之后返回,这样就可以实现聚合菜单项。</p> |
| <h3 id="zoneaware-cluster">ZoneAware Cluster</h3> |
| <p>多注册中心订阅的场景,注册中心集群间的负载均衡。对于多注册中心间的选址策略有如下四种</p> |
| <ol> |
| <li>指定优先级:<code>preferred=&quot;true&quot;</code>注册中心的地址将被优先选择</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> address=<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2181&#34;</span> preferred=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><ol start="2"> |
| <li>同中心优先:检查当前请求所属的区域,优先选择具有相同区域的注册中心</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> address=<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2181&#34;</span> zone=<span style="color:#2aa198">&#34;beijing&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><ol start="3"> |
| <li>权重轮询:根据每个注册中心的权重分配流量</li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;beijing&#34;</span> address=<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2181&#34;</span> weight=<span style="color:#2aa198">&#34;100&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;shanghai&#34;</span> address=<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2182&#34;</span> weight=<span style="color:#2aa198">&#34;10&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><ol start="4"> |
| <li>缺省值:选择一个可用的注册中心</li> |
| </ol> |
| <h3 id="集群模式示例">集群模式示例</h3> |
| <p>按照以下示例在服务提供方和消费方配置集群模式</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> cluster=<span style="color:#2aa198">&#34;failsafe&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>或</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> cluster=<span style="color:#2aa198">&#34;failsafe&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div></description></item><item><title>Overview: 服务降级</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/service-downgrade/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/service-downgrade/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>推荐使用相关限流降级组件(如 <a href="https://sentinelguard.io/zh-cn/docs/open-source-framework-integrations.html">Sentinel</a>)以达到最佳体验。参考示例实践:<a href="https://dubbo.apache.org/zh-cn/overview/tasks/ecosystem/rate-limit/">微服务治理/限流降级</a></p> |
| <p>服务降级是指服务在非正常情况下进行降级应急处理。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <ul> |
| <li>某服务或接口负荷超出最大承载能力范围,需要进行降级应急处理,避免系统崩溃</li> |
| <li>调用的某非关键服务或接口暂时不可用时,返回模拟数据或空,业务还能继续可用</li> |
| <li>降级非核心业务的服务或接口,腾出系统资源,尽量保证核心业务的正常运行</li> |
| <li>某上游基础服务超时或不可用时,执行能快速响应的降级预案,避免服务整体雪崩</li> |
| </ul> |
| <h2 id="使用方式">使用方式</h2> |
| <p>以 xml 配置为例:(通过注解方式配置类似)</p> |
| <h3 id="1配置一">1.配置一</h3> |
| <p><code>mock=&quot;true&quot;</code></p> |
| <p>例:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> interface=<span style="color:#2aa198">&#34;com.xxx.service.DemoService&#34;</span> mock=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>这种方式需要在相同包下有类名 + <code>Mock</code>后缀的实现类,即<code>com.xxx.service</code>包下有<code>DemoServiceMock</code>类。</p> |
| <h3 id="2配置二">2.配置二</h3> |
| <p><code>mock=&quot;com.xxx.service.DemoServiceMock&quot;</code></p> |
| <p>例:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> interface=<span style="color:#2aa198">&#34;com.xxx.service.DemoService&#34;</span> mock=<span style="color:#2aa198">&#34;com.xxx.service.DemoServiceMock&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>这种方式指定 Mock 类的全路径。</p> |
| <h3 id="3配置三">3.配置三</h3> |
| <p><code>mock=&quot;[fail|force]return|throw xxx&quot;</code></p> |
| <ul> |
| <li>fail 或 force 关键字可选,表示调用失败或不调用强制执行 mock 方法,如果不指定关键字默认为 fail</li> |
| <li>return 表示指定返回结果,throw 表示抛出指定异常</li> |
| <li>xxx 根据接口的返回类型解析,可以指定返回值或抛出自定义的异常</li> |
| </ul> |
| <p>例:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> interface=<span style="color:#2aa198">&#34;com.xxx.service.DemoService&#34;</span> mock=<span style="color:#2aa198">&#34;return&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> interface=<span style="color:#2aa198">&#34;com.xxx.service.DemoService&#34;</span> mock=<span style="color:#2aa198">&#34;return null&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> interface=<span style="color:#2aa198">&#34;com.xxx.service.DemoService&#34;</span> mock=<span style="color:#2aa198">&#34;fail:return aaa&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> interface=<span style="color:#2aa198">&#34;com.xxx.service.DemoService&#34;</span> mock=<span style="color:#2aa198">&#34;force:return true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> interface=<span style="color:#2aa198">&#34;com.xxx.service.DemoService&#34;</span> mock=<span style="color:#2aa198">&#34;fail:throw&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> interface=<span style="color:#2aa198">&#34;com.xxx.service.DemoService&#34;</span> mock=<span style="color:#2aa198">&#34;force:throw java.lang.NullPointException&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="4配合-dubbo-admin-使用">4.配合 dubbo-admin 使用</h3> |
| <ul> |
| <li> |
| <p>应用消费端引入 <a href="https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-mock-extensions" target="_blank"><code>dubbo-mock-admin</code></a>依赖</p> |
| </li> |
| <li> |
| <p>应用消费端启动时设置 JVM 参数,<code>-Denable.dubbo.admin.mock=true</code></p> |
| </li> |
| <li> |
| <p>启动 dubbo-admin,在服务 Mock-&gt; 规则配置菜单下设置 Mock 规则</p> |
| </li> |
| </ul> |
| <p>以服务方法的维度设置规则,设置返回模拟数据,动态启用/禁用规则</p> |
| <div class="alert alert-primary" role="alert"> |
| <h4 class="alert-heading">注意事项</h4> |
| <p>Dubbo 启动时会检查配置,当 mock 属性值配置有误时会启动失败,可根据错误提示信息进行排查</p> |
| <ul> |
| <li>配置格式错误,如 <code>return+null</code> 会报错,被当做 mock 类型处理,<code>return</code> 后面可省略不写或者跟空格后再跟返回值</li> |
| <li>类型找不到错误,如自定义 mock 类、throw 自定义异常,请检查类型是否存在或是否有拼写错误</li> |
| </ul> |
| </div></description></item><item><title>Overview: 异步调用</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-call/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-call/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <h4 id="背景">背景</h4> |
| <p>从 2.7.0 开始,Dubbo 的所有异步编程接口开始以 <a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html">CompletableFuture</a> 为基础</p> |
| <p>基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小。</p> |
| <p><img src="https://dubbo.apache.org/imgs/user/future.jpg" alt="/user-guide/images/future.jpg"></p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>将用户请求内容发送到目标请求,当目标请求遇到高流量或需要长时间处理,异步调用功能将允许立即向用户返回响应,同时目标请求继续后台处理请求,当目标请求返回结果时,将内容显示给用户。</p> |
| <blockquote> |
| <p>参考用例 |
| <a href="https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-async">https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-async</a></p> |
| </blockquote> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="使用-completablefuture-签名的接口">使用 CompletableFuture 签名的接口</h3> |
| <p>需要服务提供者事先定义 CompletableFuture 签名的服务,接口定义指南如下:</p> |
| <p>Provider端异步执行将阻塞的业务从Dubbo内部线程池切换到业务自定义线程,避免Dubbo线程池的过度占用,有助于避免不同服务间的互相影响。异步执行无异于节省资源或提升RPC响应性能,因为如果业务执行需要阻塞,则始终还是要有线程来负责执行。</p> |
| <blockquote> |
| <p><strong>Provider 端异步执行和 Consumer 端异步调用是相互独立的,任意正交组合两端配置</strong></p> |
| <ul> |
| <li>Consumer同步 - Provider同步</li> |
| <li>Consumer异步 - Provider同步</li> |
| <li>Consumer同步 - Provider异步</li> |
| <li>Consumer异步 - Provider异步</li> |
| </ul> |
| </blockquote> |
| <h3 id="定义-completablefuture-签名的接口">定义 CompletableFuture 签名的接口</h3> |
| <p>服务接口定义</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">AsyncService</span> { |
| </span></span><span style="display:flex;"><span> CompletableFuture<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">sayHello</span>(String name); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>服务实现</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">AsyncServiceImpl</span> <span style="color:#268bd2">implements</span> AsyncService { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> CompletableFuture<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">sayHello</span>(String name) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> CompletableFuture.supplyAsync(() <span style="color:#719e07">-&gt;</span> { |
| </span></span><span style="display:flex;"><span> System.out.println(name); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> Thread.sleep(5000); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (InterruptedException e) { |
| </span></span><span style="display:flex;"><span> e.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;async response from provider.&#34;</span>; |
| </span></span><span style="display:flex;"><span> }); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>通过 <code>return CompletableFuture.supplyAsync() </code>,业务执行已从 Dubbo 线程切换到业务线程,避免了对 Dubbo 线程池的阻塞。</p> |
| <p>注意接口的返回类型是 <code>CompletableFuture&lt;String&gt;</code>。</p> |
| <p>XML 引用服务</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;asyncService&#34;</span> timeout=<span style="color:#2aa198">&#34;10000&#34;</span> interface=<span style="color:#2aa198">&#34;com.alibaba.dubbo.samples.async.api.AsyncService&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>调用远程服务</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">// 调用直接返回CompletableFuture</span> |
| </span></span><span style="display:flex;"><span>CompletableFuture<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> future <span style="color:#719e07">=</span> asyncService.sayHello(<span style="color:#2aa198">&#34;async call request&#34;</span>); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 增加回调</span> |
| </span></span><span style="display:flex;"><span>future.whenComplete((v, t) <span style="color:#719e07">-&gt;</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">if</span> (t <span style="color:#719e07">!=</span> <span style="color:#cb4b16">null</span>) { |
| </span></span><span style="display:flex;"><span> t.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">else</span> { |
| </span></span><span style="display:flex;"><span> System.out.println(<span style="color:#2aa198">&#34;Response: &#34;</span> <span style="color:#719e07">+</span> v); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>}); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 早于结果输出</span> |
| </span></span><span style="display:flex;"><span>System.out.println(<span style="color:#2aa198">&#34;Executed before response return.&#34;</span>); |
| </span></span></code></pre></div><h3 id="使用-asynccontext">使用 AsyncContext</h3> |
| <p>Dubbo 提供了一个类似 Servlet 3.0 的异步接口<code>AsyncContext</code>,在没有 CompletableFuture 签名接口的情况下,也可以实现 Provider 端的异步执行。</p> |
| <p>服务接口定义</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">AsyncService</span> { |
| </span></span><span style="display:flex;"><span> String <span style="color:#268bd2">sayHello</span>(String name); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>服务暴露,和普通服务完全一致</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;bean</span> id=<span style="color:#2aa198">&#34;asyncService&#34;</span> class=<span style="color:#2aa198">&#34;org.apache.dubbo.samples.governance.impl.AsyncServiceImpl&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.samples.governance.api.AsyncService&#34;</span> ref=<span style="color:#2aa198">&#34;asyncService&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>服务实现</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">AsyncServiceImpl</span> <span style="color:#268bd2">implements</span> AsyncService { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">sayHello</span>(String name) { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">final</span> AsyncContext asyncContext <span style="color:#719e07">=</span> RpcContext.startAsync(); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">new</span> Thread(() <span style="color:#719e07">-&gt;</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 如果要使用上下文,则必须要放在第一句执行</span> |
| </span></span><span style="display:flex;"><span> asyncContext.signalContextSwitch(); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> Thread.sleep(500); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (InterruptedException e) { |
| </span></span><span style="display:flex;"><span> e.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 写回响应</span> |
| </span></span><span style="display:flex;"><span> asyncContext.write(<span style="color:#2aa198">&#34;Hello &#34;</span> <span style="color:#719e07">+</span> name <span style="color:#719e07">+</span> <span style="color:#2aa198">&#34;, response from provider.&#34;</span>); |
| </span></span><span style="display:flex;"><span> }).start(); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#cb4b16">null</span>; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="使用-rpccontext-实现消费端异步调用">使用 RpcContext 实现消费端异步调用</h3> |
| <p>在 consumer.xml 中配置</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;asyncService&#34;</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.samples.governance.api.AsyncService&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:method</span> name=<span style="color:#2aa198">&#34;sayHello&#34;</span> async=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dubbo:reference&gt;</span> |
| </span></span></code></pre></div><p>调用代码</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">// 此调用会立即返回null</span> |
| </span></span><span style="display:flex;"><span>asyncService.sayHello(<span style="color:#2aa198">&#34;world&#34;</span>); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future</span> |
| </span></span><span style="display:flex;"><span>CompletableFuture<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> helloFuture <span style="color:#719e07">=</span> RpcContext.getServiceContext().getCompletableFuture(); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 为Future添加回调</span> |
| </span></span><span style="display:flex;"><span>helloFuture.whenComplete((retValue, exception) <span style="color:#719e07">-&gt;</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">if</span> (exception <span style="color:#719e07">==</span> <span style="color:#cb4b16">null</span>) { |
| </span></span><span style="display:flex;"><span> System.out.println(retValue); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">else</span> { |
| </span></span><span style="display:flex;"><span> exception.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>}); |
| </span></span></code></pre></div><p>或者,也可以这样做异步调用</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>CompletableFuture<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> future <span style="color:#719e07">=</span> RpcContext.getServiceContext().asyncCall( |
| </span></span><span style="display:flex;"><span> () <span style="color:#719e07">-&gt;</span> { |
| </span></span><span style="display:flex;"><span> asyncService.sayHello(<span style="color:#2aa198">&#34;oneway call request1&#34;</span>); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>future.get(); |
| </span></span></code></pre></div><p><strong>异步总是不等待返回</strong>,你也可以设置是否等待消息发出</p> |
| <ul> |
| <li><code>sent=&quot;true&quot;</code> 等待消息发出,消息发送失败将抛出异常。</li> |
| <li><code>sent=&quot;false&quot;</code> 不等待消息发出,将消息放入 IO 队列,即刻返回。</li> |
| </ul> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:method</span> name=<span style="color:#2aa198">&#34;findFoo&#34;</span> async=<span style="color:#2aa198">&#34;true&#34;</span> sent=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>如果你只是想异步,完全忽略返回值,可以配置 <code>return=&quot;false&quot;</code>,以减少 Future 对象的创建和管理成本</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:method</span> name=<span style="color:#2aa198">&#34;findFoo&#34;</span> async=<span style="color:#2aa198">&#34;true&#34;</span> return=<span style="color:#2aa198">&#34;false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div></description></item><item><title>Overview: 泛化调用(客户端泛化)</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-reference/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-reference/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>泛化调用是指在调用方没有服务方提供的 API(SDK)的情况下,对服务方进行调用,并且可以正常拿到调用结果。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>泛化调用主要用于实现一个通用的远程服务 Mock 框架,可通过实现 GenericService 接口处理所有服务请求。比如如下场景:</p> |
| <ol> |
| <li> |
| <p>网关服务:如果要搭建一个网关服务,那么服务网关要作为所有 RPC 服务的调用端。但是网关本身不应该依赖于服务提供方的接口 API(这样会导致每有一个新的服务发布,就需要修改网关的代码以及重新部署),所以需要泛化调用的支持。</p> |
| </li> |
| <li> |
| <p>测试平台:如果要搭建一个可以测试 RPC 调用的平台,用户输入分组名、接口、方法名等信息,就可以测试对应的 RPC 服务。那么由于同样的原因(即会导致每有一个新的服务发布,就需要修改网关的代码以及重新部署),所以平台本身不应该依赖于服务提供方的接口 API。所以需要泛化调用的支持。</p> |
| </li> |
| </ol> |
| <h2 id="使用方式">使用方式</h2> |
| <p>demo 可见 <a href="https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-generic">dubbo 项目中的示例代码</a></p> |
| <p>API 部分以此 demo 为例讲解使用方式。</p> |
| <h3 id="服务定义">服务定义</h3> |
| <h4 id="服务接口">服务接口</h4> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">HelloService</span> { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> String <span style="color:#268bd2">sayHello</span>(String name); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> CompletableFuture<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">sayHelloAsync</span>(String name); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> CompletableFuture<span style="color:#719e07">&lt;</span>Person<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">sayHelloAsyncComplex</span>(String name); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> CompletableFuture<span style="color:#719e07">&lt;</span>GenericType<span style="color:#719e07">&lt;</span>Person<span style="color:#719e07">&gt;&gt;</span> <span style="color:#268bd2">sayHelloAsyncGenericComplex</span>(String name); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h4 id="服务实现类">服务实现类</h4> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">HelloServiceImpl</span> <span style="color:#268bd2">implements</span> HelloService { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">sayHello</span>(String name) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;sayHello: &#34;</span> <span style="color:#719e07">+</span> name; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> CompletableFuture<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">sayHelloAsync</span>(String name) { |
| </span></span><span style="display:flex;"><span> CompletableFuture<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> future <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> CompletableFuture<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">new</span> Thread(() <span style="color:#719e07">-&gt;</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> Thread.sleep(5000); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (InterruptedException e) { |
| </span></span><span style="display:flex;"><span> e.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> future.complete(<span style="color:#2aa198">&#34;sayHelloAsync: &#34;</span> <span style="color:#719e07">+</span> name); |
| </span></span><span style="display:flex;"><span> }).start(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> future; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> CompletableFuture<span style="color:#719e07">&lt;</span>Person<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">sayHelloAsyncComplex</span>(String name) { |
| </span></span><span style="display:flex;"><span> Person person <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> Person(1, <span style="color:#2aa198">&#34;sayHelloAsyncComplex: &#34;</span> <span style="color:#719e07">+</span> name); |
| </span></span><span style="display:flex;"><span> CompletableFuture<span style="color:#719e07">&lt;</span>Person<span style="color:#719e07">&gt;</span> future <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> CompletableFuture<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">new</span> Thread(() <span style="color:#719e07">-&gt;</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> Thread.sleep(5000); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (InterruptedException e) { |
| </span></span><span style="display:flex;"><span> e.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> future.complete(person); |
| </span></span><span style="display:flex;"><span> }).start(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> future; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> CompletableFuture<span style="color:#719e07">&lt;</span>GenericType<span style="color:#719e07">&lt;</span>Person<span style="color:#719e07">&gt;&gt;</span> <span style="color:#268bd2">sayHelloAsyncGenericComplex</span>(String name) { |
| </span></span><span style="display:flex;"><span> Person person <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> Person(1, <span style="color:#2aa198">&#34;sayHelloAsyncGenericComplex: &#34;</span> <span style="color:#719e07">+</span> name); |
| </span></span><span style="display:flex;"><span> GenericType<span style="color:#719e07">&lt;</span>Person<span style="color:#719e07">&gt;</span> genericType <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> GenericType<span style="color:#719e07">&lt;&gt;</span>(person); |
| </span></span><span style="display:flex;"><span> CompletableFuture<span style="color:#719e07">&lt;</span>GenericType<span style="color:#719e07">&lt;</span>Person<span style="color:#719e07">&gt;&gt;</span> future <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> CompletableFuture<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">new</span> Thread(() <span style="color:#719e07">-&gt;</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> Thread.sleep(5000); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (InterruptedException e) { |
| </span></span><span style="display:flex;"><span> e.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> future.complete(genericType); |
| </span></span><span style="display:flex;"><span> }).start(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> future; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="通过api使用泛化调用">通过API使用泛化调用</h3> |
| <h4 id="服务启动方">服务启动方</h4> |
| <ol> |
| <li> |
| <p>在设置 <code>ServiceConfig</code> 时,使用<code>setGeneric(&quot;true&quot;)</code>来开启泛化调用</p> |
| </li> |
| <li> |
| <p>在设置 <code>ServiceConfig</code> 时,使用 setRef 指定实现类时,要设置一个 <code>GenericService</code> 的对象。而不是真正的服务实现类对象</p> |
| </li> |
| <li> |
| <p>其他设置与正常 Api 服务启动一致即可</p> |
| </li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> String zookeeperAddress <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;zookeeper://&#34;</span> <span style="color:#719e07">+</span> System.getProperty(<span style="color:#2aa198">&#34;zookeeper.address&#34;</span>, <span style="color:#2aa198">&#34;127.0.0.1&#34;</span>) <span style="color:#719e07">+</span> <span style="color:#2aa198">&#34;:2181&#34;</span>; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">static</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">main</span>(String<span style="color:#719e07">[]</span> args) <span style="color:#268bd2">throws</span> Exception { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">new</span> EmbeddedZooKeeper(2181, <span style="color:#cb4b16">false</span>).start(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//创建ApplicationConfig</span> |
| </span></span><span style="display:flex;"><span> ApplicationConfig applicationConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ApplicationConfig(); |
| </span></span><span style="display:flex;"><span> applicationConfig.setName(<span style="color:#2aa198">&#34;generic-impl-provider&#34;</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//创建注册中心配置</span> |
| </span></span><span style="display:flex;"><span> RegistryConfig registryConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> RegistryConfig(); |
| </span></span><span style="display:flex;"><span> registryConfig.setAddress(zookeeperAddress); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//新建服务实现类,注意要使用GenericService接收</span> |
| </span></span><span style="display:flex;"><span> GenericService helloService <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> GenericImplOfHelloService(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//创建服务相关配置</span> |
| </span></span><span style="display:flex;"><span> ServiceConfig<span style="color:#719e07">&lt;</span>GenericService<span style="color:#719e07">&gt;</span> service <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ServiceConfig<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span> service.setApplication(applicationConfig); |
| </span></span><span style="display:flex;"><span> service.setRegistry(registryConfig); |
| </span></span><span style="display:flex;"><span> service.setInterface(<span style="color:#2aa198">&#34;org.apache.dubbo.samples.generic.call.api.HelloService&#34;</span>); |
| </span></span><span style="display:flex;"><span> service.setRef(helloService); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//重点:设置为泛化调用</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//注:不再推荐使用参数为布尔值的setGeneric函数</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//应该使用referenceConfig.setGeneric(&#34;true&#34;)代替</span> |
| </span></span><span style="display:flex;"><span> service.setGeneric(<span style="color:#2aa198">&#34;true&#34;</span>); |
| </span></span><span style="display:flex;"><span> service.export(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> System.out.println(<span style="color:#2aa198">&#34;dubbo service started&#34;</span>); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">new</span> CountDownLatch(1).await(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h4 id="泛化调用方">泛化调用方</h4> |
| <p>步骤:</p> |
| <ol> |
| <li> |
| <p>在设置 <code>ReferenceConfig</code> 时,使用 <code>setGeneric(&quot;true&quot;)</code> 来开启泛化调用</p> |
| </li> |
| <li> |
| <p>配置完 <code>ReferenceConfig</code> 后,使用 <code>referenceConfig.get()</code> 获取到 <code>GenericService</code> 类的实例</p> |
| </li> |
| <li> |
| <p>使用其 <code>$invoke</code> 方法获取结果</p> |
| </li> |
| <li> |
| <p>其他设置与正常 Api 服务启动一致即可</p> |
| </li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span> <span style="color:#586e75">//定义泛化调用服务类</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> GenericService genericService; |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">static</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">main</span>(String<span style="color:#719e07">[]</span> args) <span style="color:#268bd2">throws</span> Exception { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//创建ApplicationConfig</span> |
| </span></span><span style="display:flex;"><span> ApplicationConfig applicationConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ApplicationConfig(); |
| </span></span><span style="display:flex;"><span> applicationConfig.setName(<span style="color:#2aa198">&#34;generic-call-consumer&#34;</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//创建注册中心配置</span> |
| </span></span><span style="display:flex;"><span> RegistryConfig registryConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> RegistryConfig(); |
| </span></span><span style="display:flex;"><span> registryConfig.setAddress(<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2181&#34;</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//创建服务引用配置</span> |
| </span></span><span style="display:flex;"><span> ReferenceConfig<span style="color:#719e07">&lt;</span>GenericService<span style="color:#719e07">&gt;</span> referenceConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ReferenceConfig<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//设置接口</span> |
| </span></span><span style="display:flex;"><span> referenceConfig.setInterface(<span style="color:#2aa198">&#34;org.apache.dubbo.samples.generic.call.api.HelloService&#34;</span>); |
| </span></span><span style="display:flex;"><span> applicationConfig.setRegistry(registryConfig); |
| </span></span><span style="display:flex;"><span> referenceConfig.setApplication(applicationConfig); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//重点:设置为泛化调用</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//注:不再推荐使用参数为布尔值的setGeneric函数</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//应该使用referenceConfig.setGeneric(&#34;true&#34;)代替</span> |
| </span></span><span style="display:flex;"><span> referenceConfig.setGeneric(<span style="color:#cb4b16">true</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//设置异步,不必须,根据业务而定。</span> |
| </span></span><span style="display:flex;"><span> referenceConfig.setAsync(<span style="color:#cb4b16">true</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//设置超时时间</span> |
| </span></span><span style="display:flex;"><span> referenceConfig.setTimeout(7000); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//获取服务,由于是泛化调用,所以获取的一定是GenericService类型</span> |
| </span></span><span style="display:flex;"><span> genericService <span style="color:#719e07">=</span> referenceConfig.get(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//使用GenericService类对象的$invoke方法可以代替原方法使用</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//第一个参数是需要调用的方法名</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//第二个参数是需要调用的方法的参数类型数组,为String数组,里面存入参数的全类名。</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//第三个参数是需要调用的方法的参数数组,为Object数组,里面存入需要的参数。</span> |
| </span></span><span style="display:flex;"><span> Object result <span style="color:#719e07">=</span> genericService.$invoke(<span style="color:#2aa198">&#34;sayHello&#34;</span>, <span style="color:#719e07">new</span> String<span style="color:#719e07">[]</span>{<span style="color:#2aa198">&#34;java.lang.String&#34;</span>}, <span style="color:#719e07">new</span> Object<span style="color:#719e07">[]</span>{<span style="color:#2aa198">&#34;world&#34;</span>}); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//使用CountDownLatch,如果使用同步调用则不需要这么做。</span> |
| </span></span><span style="display:flex;"><span> CountDownLatch latch <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> CountDownLatch(1); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//获取结果</span> |
| </span></span><span style="display:flex;"><span> CompletableFuture<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> future <span style="color:#719e07">=</span> RpcContext.getContext().getCompletableFuture(); |
| </span></span><span style="display:flex;"><span> future.whenComplete((value, t) <span style="color:#719e07">-&gt;</span> { |
| </span></span><span style="display:flex;"><span> System.err.println(<span style="color:#2aa198">&#34;invokeSayHello(whenComplete): &#34;</span> <span style="color:#719e07">+</span> value); |
| </span></span><span style="display:flex;"><span> latch.countDown(); |
| </span></span><span style="display:flex;"><span> }); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//打印结果</span> |
| </span></span><span style="display:flex;"><span> System.err.println(<span style="color:#2aa198">&#34;invokeSayHello(return): &#34;</span> <span style="color:#719e07">+</span> result); |
| </span></span><span style="display:flex;"><span> latch.await(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span></code></pre></div><h3 id="通过-spring-使用泛化调用">通过 Spring 使用泛化调用</h3> |
| <p>Spring 中服务暴露与服务发现有多种使用方式,如 xml,注解。这里以 xml 为例。 |
| 步骤:</p> |
| <ol> |
| <li> |
| <p>生产者端无需改动</p> |
| </li> |
| <li> |
| <p>消费者端原有的 <code>dubbo:reference</code> 标签加上 <code>generic=true</code> 的属性。</p> |
| </li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;helloService&#34;</span> generic = <span style="color:#2aa198">&#34;true&#34;</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.samples.generic.call.api.HelloService&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><ol start="3"> |
| <li> |
| <p>获取到 Bean 容器,通过 Bean 容器拿到 <code>GenericService</code> 实例。</p> |
| </li> |
| <li> |
| <p>调用 <code>$invoke</code> 方法获取结果</p> |
| </li> |
| </ol> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> GenericService genericService; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">static</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">main</span>(String<span style="color:#719e07">[]</span> args) <span style="color:#268bd2">throws</span> Exception { |
| </span></span><span style="display:flex;"><span> ClassPathXmlApplicationContext context <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ClassPathXmlApplicationContext(<span style="color:#2aa198">&#34;spring/generic-impl-consumer.xml&#34;</span>); |
| </span></span><span style="display:flex;"><span> context.start(); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//服务对应bean的名字由xml标签的id决定</span> |
| </span></span><span style="display:flex;"><span> genericService <span style="color:#719e07">=</span> context.getBean(<span style="color:#2aa198">&#34;helloService&#34;</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">//获得结果</span> |
| </span></span><span style="display:flex;"><span> Object result <span style="color:#719e07">=</span> genericService.$invoke(<span style="color:#2aa198">&#34;sayHello&#34;</span>, <span style="color:#719e07">new</span> String<span style="color:#719e07">[]</span>{<span style="color:#2aa198">&#34;java.lang.String&#34;</span>}, <span style="color:#719e07">new</span> Object<span style="color:#719e07">[]</span>{<span style="color:#2aa198">&#34;world&#34;</span>}); |
| </span></span><span style="display:flex;"><span> } |
| </span></span></code></pre></div><h3 id="protobuf-对象泛化调用">Protobuf 对象泛化调用</h3> |
| <p>一般泛化调用只能用于生成的服务参数为 POJO 的情况,而 GoogleProtobuf 的对象是基于 Builder 生成的非正常 POJO,可以通过 protobuf-json 泛化调用。</p> |
| <p>GoogleProtobuf 序列化相关的 Demo 可以参考 <a href="https://github.com/apache/dubbo-samples/tree/master/3-extensions/serialization/dubbo-samples-protobuf">protobuf-demo</a></p> |
| <h4 id="通过-spring-对-google-protobuf-对象泛化调用">通过 Spring 对 Google Protobuf 对象泛化调用</h4> |
| <p>在 Spring 中配置声明 generic = &ldquo;protobuf-json&rdquo;</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;barService&#34;</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> generic=<span style="color:#2aa198">&#34;protobuf-json&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>在 Java 代码获取 barService 并开始泛化调用:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>GenericService barService <span style="color:#719e07">=</span> (GenericService) applicationContext.getBean(<span style="color:#2aa198">&#34;barService&#34;</span>); |
| </span></span><span style="display:flex;"><span>Object result <span style="color:#719e07">=</span> barService.$invoke(<span style="color:#2aa198">&#34;sayHello&#34;</span>,<span style="color:#719e07">new</span> String<span style="color:#719e07">[]</span>{<span style="color:#2aa198">&#34;org.apache.dubbo.protobuf.GooglePbBasic$CDubboGooglePBRequestType&#34;</span>}, <span style="color:#719e07">new</span> Object<span style="color:#719e07">[]</span>{<span style="color:#2aa198">&#34;{\&#34;double\&#34;:0.0,\&#34;float\&#34;:0.0,\&#34;bytesType\&#34;:\&#34;Base64String\&#34;,\&#34;int32\&#34;:0}&#34;</span>}); |
| </span></span></code></pre></div><h4 id="通过-api-方式对-google-protobuf-对象泛化调用">通过 API 方式对 Google Protobuf 对象泛化调用</h4> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>ReferenceConfig<span style="color:#719e07">&lt;</span>GenericService<span style="color:#719e07">&gt;</span> reference <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ReferenceConfig<span style="color:#719e07">&lt;</span>GenericService<span style="color:#719e07">&gt;</span>(); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 弱类型接口名</span> |
| </span></span><span style="display:flex;"><span>reference.setInterface(GenericService.class.getName()); |
| </span></span><span style="display:flex;"><span>reference.setInterface(<span style="color:#2aa198">&#34;com.xxx.XxxService&#34;</span>); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 声明为Protobuf-json</span> |
| </span></span><span style="display:flex;"><span>reference.setGeneric(Constants.GENERIC_SERIALIZATION_PROTOBUF); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>GenericService genericService <span style="color:#719e07">=</span> reference.get(); |
| </span></span><span style="display:flex;"><span>Map<span style="color:#719e07">&lt;</span>String, Object<span style="color:#719e07">&gt;</span> person <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> HashMap<span style="color:#719e07">&lt;</span>String, Object<span style="color:#719e07">&gt;</span>(); |
| </span></span><span style="display:flex;"><span>person.put(<span style="color:#2aa198">&#34;fixed64&#34;</span>, <span style="color:#2aa198">&#34;0&#34;</span>); |
| </span></span><span style="display:flex;"><span>person.put(<span style="color:#2aa198">&#34;int64&#34;</span>, <span style="color:#2aa198">&#34;0&#34;</span>); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 参考google官方的protobuf 3 的语法,服务的每个方法中只传输一个POJO对象</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// protobuf的泛化调用只允许传递一个类型为String的json对象来代表请求参数</span> |
| </span></span><span style="display:flex;"><span>String requestString <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> Gson().toJson(person); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 返回对象是GoolgeProtobuf响应对象的json字符串。</span> |
| </span></span><span style="display:flex;"><span>Object result <span style="color:#719e07">=</span> genericService.$invoke(<span style="color:#2aa198">&#34;sayHello&#34;</span>, <span style="color:#719e07">new</span> String<span style="color:#719e07">[]</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#2aa198">&#34;com.xxx.XxxService.GooglePbBasic$CDubboGooglePBRequestType&#34;</span>}, |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">new</span> Object<span style="color:#719e07">[]</span> {requestString}); |
| </span></span></code></pre></div><h4 id="googleprotobuf-对象的处理">GoogleProtobuf 对象的处理</h4> |
| <p>GoogleProtobuf 对象是由 Protocol 契约生成,相关知识请参考 <a href="https://developers.google.com/protocol-buffers/?hl=zh-CN">ProtocolBuffers 文档</a>。假如有如下 Protobuf 契约</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-proto" data-lang="proto"><span style="display:flex;"><span>syntax <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;proto3&#34;</span>; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">package</span> com<span style="color:#719e07">.</span>xxx.XxxService.GooglePbBasic.basic; |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">message</span> <span style="color:#268bd2">CDubboGooglePBRequestType</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">double</span> <span style="color:#dc322f">double</span> <span style="color:#719e07">=</span> <span style="color:#2aa198">1</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">float</span> <span style="color:#dc322f">float</span> <span style="color:#719e07">=</span> <span style="color:#2aa198">2</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">int32</span> <span style="color:#dc322f">int32</span> <span style="color:#719e07">=</span> <span style="color:#2aa198">3</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">bool</span> <span style="color:#dc322f">bool</span> <span style="color:#719e07">=</span> <span style="color:#2aa198">13</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">string</span> <span style="color:#dc322f">string</span> <span style="color:#719e07">=</span> <span style="color:#2aa198">14</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">bytes</span> bytesType <span style="color:#719e07">=</span> <span style="color:#2aa198">15</span>; |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">message</span> <span style="color:#268bd2">CDubboGooglePBResponseType</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">string</span> msg <span style="color:#719e07">=</span> <span style="color:#2aa198">1</span>; |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">service</span> CDubboGooglePBService { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">rpc</span> sayHello (CDubboGooglePBRequestType) <span style="color:#719e07">returns</span> (CDubboGooglePBResponseType); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>则对应请求按照如下方法构造</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>Map<span style="color:#719e07">&lt;</span>String, Object<span style="color:#719e07">&gt;</span> person <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> HashMap<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span>person.put(<span style="color:#2aa198">&#34;double&#34;</span>, <span style="color:#2aa198">&#34;1.000&#34;</span>); |
| </span></span><span style="display:flex;"><span>person.put(<span style="color:#2aa198">&#34;float&#34;</span>, <span style="color:#2aa198">&#34;1.00&#34;</span>); |
| </span></span><span style="display:flex;"><span>person.put(<span style="color:#2aa198">&#34;int32&#34;</span>,<span style="color:#2aa198">&#34;1&#34;</span> ); |
| </span></span><span style="display:flex;"><span>person.put(<span style="color:#2aa198">&#34;bool&#34;</span>,<span style="color:#2aa198">&#34;false&#34;</span> ); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">//String 的对象需要经过base64编码</span> |
| </span></span><span style="display:flex;"><span>person.put(<span style="color:#2aa198">&#34;string&#34;</span>,<span style="color:#2aa198">&#34;someBaseString&#34;</span>); |
| </span></span><span style="display:flex;"><span>person.put(<span style="color:#2aa198">&#34;bytesType&#34;</span>,<span style="color:#2aa198">&#34;150&#34;</span>); |
| </span></span></code></pre></div><h4 id="googleprotobuf-服务元数据解析">GoogleProtobuf 服务元数据解析</h4> |
| <p>Google Protobuf 对象缺少标准的 JSON 格式,生成的服务元数据信息存在错误。请添加如下依赖元数据解析的依赖。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.apache.dubbo<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>dubbo-metadata-definition-protobuf<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>${dubbo.version}<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span></code></pre></div><p>从服务元数据中也可以比较容易构建泛化调用对象。</p> |
| <div class="alert alert-primary" role="alert"> |
| <h4 class="alert-heading">注意事项</h4> |
| <ol> |
| <li> |
| <p>如果参数为基本类型或者 Date,List,Map 等,则不需要转换,直接调用。</p> |
| </li> |
| <li> |
| <p>如果参数为其他 POJO,则使用 Map 代替。</p> |
| </li> |
| </ol> |
| </div> |
| <p>如:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">Student</span> { |
| </span></span><span style="display:flex;"><span> String name; |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">int</span> age; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">getName</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> name; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">setName</span>(String name) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span>.name <span style="color:#719e07">=</span> name; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">int</span> <span style="color:#268bd2">getAge</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> age; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">setAge</span>(<span style="color:#dc322f">int</span> age) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span>.age <span style="color:#719e07">=</span> age; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>在调用时应该转换为:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>Map<span style="color:#719e07">&lt;</span>String, Object<span style="color:#719e07">&gt;</span> student <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> HashMap<span style="color:#719e07">&lt;</span>String, Object<span style="color:#719e07">&gt;</span>(); |
| </span></span><span style="display:flex;"><span>student.put(<span style="color:#2aa198">&#34;name&#34;</span>, <span style="color:#2aa198">&#34;xxx&#34;</span>); |
| </span></span><span style="display:flex;"><span>student.put(<span style="color:#2aa198">&#34;age&#34;</span>, <span style="color:#2aa198">&#34;xxx&#34;</span>); |
| </span></span></code></pre></div><ol start="3"> |
| <li>对于其他序列化格式,需要特殊配置</li> |
| </ol></description></item><item><title>Overview: 流式通信</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/streaming/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/streaming/</guid><description> |
| <p>TBD</p></description></item><item><title>Overview: 线程池隔离</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/isolation-executor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/isolation-executor/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>一种新的线程池管理方式,使得提供者应用内各个服务的线程池隔离开来,互相独立,某个服务的线程池资源耗尽不会影响其他正常服务。支持线程池可配置化,由用户手动指定。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>使用线程池隔离来确保 Dubbo 用于调用远程方法的线程与微服务用于执行其任务的线程是分开的。可以通过防止线程阻塞或相互竞争来帮助提高系统的性能和稳定性。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <p>目前可以以 API、XML、Annotation 的方式进行配置</p> |
| <p><strong>配置参数</strong></p> |
| <ul> |
| <li><code>ApplicationConfig</code> 新增 <code>String executor-management-mode</code> 参数,配置值为 <code>default</code> 和 <code>isolation</code> ,默认为 <code>default</code>。 |
| <ul> |
| <li><code>executor-management-mode = default</code> 使用原有 <strong>以协议端口为粒度、服务间共享</strong> 的线程池管理方式</li> |
| <li><code>executor-management-mode = isolation</code> 使用新增的 <strong>以服务三元组为粒度、服务间隔离</strong> 的线程池管理方式</li> |
| </ul> |
| </li> |
| <li><code>ServiceConfig</code> 新增 <code>Executor executor</code> 参数,<strong>用以服务间隔离的线程池</strong>,可以由用户配置化、提供自己想要的线程池,若没有指定,则会根据协议配置(<code>ProtocolConfig</code>)信息构建默认的线程池用以服务隔离。</li> |
| </ul> |
| <blockquote> |
| <p><code>ServiceConfig</code> 新增 <code>Executor executor</code> 配置参数只有指定<code>executor-management-mode = isolation</code> 才生效。</p> |
| </blockquote> |
| <h3 id="api">API</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">test</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// provider app</span> |
| </span></span><span style="display:flex;"><span> DubboBootstrap providerBootstrap <span style="color:#719e07">=</span> DubboBootstrap.newInstance(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> ServiceConfig serviceConfig1 <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ServiceConfig(); |
| </span></span><span style="display:flex;"><span> serviceConfig1.setInterface(DemoService.class); |
| </span></span><span style="display:flex;"><span> serviceConfig1.setRef(<span style="color:#719e07">new</span> DemoServiceImpl()); |
| </span></span><span style="display:flex;"><span> serviceConfig1.setVersion(version1); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// set executor1 for serviceConfig1, max threads is 10</span> |
| </span></span><span style="display:flex;"><span> NamedThreadFactory threadFactory1 <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> NamedThreadFactory(<span style="color:#2aa198">&#34;DemoService-executor&#34;</span>); |
| </span></span><span style="display:flex;"><span> ExecutorService executor1 <span style="color:#719e07">=</span> Executors.newFixedThreadPool(10, threadFactory1); |
| </span></span><span style="display:flex;"><span> serviceConfig1.setExecutor(executor1); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> ServiceConfig serviceConfig2 <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ServiceConfig(); |
| </span></span><span style="display:flex;"><span> serviceConfig2.setInterface(HelloService.class); |
| </span></span><span style="display:flex;"><span> serviceConfig2.setRef(<span style="color:#719e07">new</span> HelloServiceImpl()); |
| </span></span><span style="display:flex;"><span> serviceConfig2.setVersion(version2); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// set executor2 for serviceConfig2, max threads is 100</span> |
| </span></span><span style="display:flex;"><span> NamedThreadFactory threadFactory2 <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> NamedThreadFactory(<span style="color:#2aa198">&#34;HelloService-executor&#34;</span>); |
| </span></span><span style="display:flex;"><span> ExecutorService executor2 <span style="color:#719e07">=</span> Executors.newFixedThreadPool(100, threadFactory2); |
| </span></span><span style="display:flex;"><span> serviceConfig2.setExecutor(executor2); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> ServiceConfig serviceConfig3 <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ServiceConfig(); |
| </span></span><span style="display:flex;"><span> serviceConfig3.setInterface(HelloService.class); |
| </span></span><span style="display:flex;"><span> serviceConfig3.setRef(<span style="color:#719e07">new</span> HelloServiceImpl()); |
| </span></span><span style="display:flex;"><span> serviceConfig3.setVersion(version3); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// Because executor is not set for serviceConfig3, the default executor of serviceConfig3 is built using</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// the threadpool parameter of the protocolConfig ( FixedThreadpool , max threads is 200)</span> |
| </span></span><span style="display:flex;"><span> serviceConfig3.setExecutor(<span style="color:#cb4b16">null</span>); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// It takes effect only if [executor-management-mode=isolation] is configured</span> |
| </span></span><span style="display:flex;"><span> ApplicationConfig applicationConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ApplicationConfig(<span style="color:#2aa198">&#34;provider-app&#34;</span>); |
| </span></span><span style="display:flex;"><span> applicationConfig.setExecutorManagementMode(<span style="color:#2aa198">&#34;isolation&#34;</span>); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> providerBootstrap |
| </span></span><span style="display:flex;"><span> .application(applicationConfig) |
| </span></span><span style="display:flex;"><span> .registry(registryConfig) |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// export with tri and dubbo protocol</span> |
| </span></span><span style="display:flex;"><span> .protocol(<span style="color:#719e07">new</span> ProtocolConfig(<span style="color:#2aa198">&#34;tri&#34;</span>, 20001)) |
| </span></span><span style="display:flex;"><span> .protocol(<span style="color:#719e07">new</span> ProtocolConfig(<span style="color:#2aa198">&#34;dubbo&#34;</span>, 20002)) |
| </span></span><span style="display:flex;"><span> .service(serviceConfig1) |
| </span></span><span style="display:flex;"><span> .service(serviceConfig2) |
| </span></span><span style="display:flex;"><span> .service(serviceConfig3); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> providerBootstrap.start(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span></code></pre></div><h3 id="xml">XML</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;beans</span> xmlns:xsi=<span style="color:#2aa198">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:dubbo=<span style="color:#2aa198">&#34;http://dubbo.apache.org/schema/dubbo&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans&#34;</span> |
| </span></span><span style="display:flex;"><span> xsi:schemaLocation=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd |
| </span></span></span><span style="display:flex;"><span><span style="color:#2aa198"> http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- NOTE: we need config executor-management-mode=&#34;isolation&#34; --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:application</span> name=<span style="color:#2aa198">&#34;demo-provider&#34;</span> executor-management-mode=<span style="color:#2aa198">&#34;isolation&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/dubbo:application&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:config-center</span> address=<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2181&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:metadata-report</span> address=<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2181&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;registry1&#34;</span> address=<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2181?registry-type=service&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:protocol</span> name=<span style="color:#2aa198">&#34;dubbo&#34;</span> port=<span style="color:#2aa198">&#34;-1&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:protocol</span> name=<span style="color:#2aa198">&#34;tri&#34;</span> port=<span style="color:#2aa198">&#34;-1&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- expose three service with dubbo and tri protocol--&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;bean</span> id=<span style="color:#2aa198">&#34;demoServiceV1&#34;</span> class=<span style="color:#2aa198">&#34;org.apache.dubbo.config.spring.impl.DemoServiceImpl&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;bean</span> id=<span style="color:#2aa198">&#34;helloServiceV2&#34;</span> class=<span style="color:#2aa198">&#34;org.apache.dubbo.config.spring.impl.HelloServiceImpl&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;bean</span> id=<span style="color:#2aa198">&#34;helloServiceV3&#34;</span> class=<span style="color:#2aa198">&#34;org.apache.dubbo.config.spring.impl.HelloServiceImpl&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- customized thread pool --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;bean</span> id=<span style="color:#2aa198">&#34;executor-demo-service&#34;</span> |
| </span></span><span style="display:flex;"><span> class=<span style="color:#2aa198">&#34;org.apache.dubbo.config.spring.isolation.spring.support.DemoServiceExecutor&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;bean</span> id=<span style="color:#2aa198">&#34;executor-hello-service&#34;</span> |
| </span></span><span style="display:flex;"><span> class=<span style="color:#2aa198">&#34;org.apache.dubbo.config.spring.isolation.spring.support.HelloServiceExecutor&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- this service use [executor=&#34;executor-demo-service&#34;] as isolated thread pool--&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:service</span> executor=<span style="color:#2aa198">&#34;executor-demo-service&#34;</span> |
| </span></span><span style="display:flex;"><span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.config.spring.api.DemoService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> group=<span style="color:#2aa198">&#34;Group1&#34;</span> |
| </span></span><span style="display:flex;"><span> timeout=<span style="color:#2aa198">&#34;3000&#34;</span> ref=<span style="color:#2aa198">&#34;demoServiceV1&#34;</span> registry=<span style="color:#2aa198">&#34;registry1&#34;</span> protocol=<span style="color:#2aa198">&#34;dubbo,tri&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- this service use [executor=&#34;executor-hello-service&#34;] as isolated thread pool--&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:service</span> executor=<span style="color:#2aa198">&#34;executor-hello-service&#34;</span> |
| </span></span><span style="display:flex;"><span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.config.spring.api.HelloService&#34;</span> version=<span style="color:#2aa198">&#34;2.0.0&#34;</span> group=<span style="color:#2aa198">&#34;Group2&#34;</span> |
| </span></span><span style="display:flex;"><span> timeout=<span style="color:#2aa198">&#34;5000&#34;</span> ref=<span style="color:#2aa198">&#34;helloServiceV2&#34;</span> registry=<span style="color:#2aa198">&#34;registry1&#34;</span> protocol=<span style="color:#2aa198">&#34;dubbo,tri&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- not set executor for this service, the default executor built using threadpool parameter of the protocolConfig --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.config.spring.api.HelloService&#34;</span> version=<span style="color:#2aa198">&#34;3.0.0&#34;</span> group=<span style="color:#2aa198">&#34;Group3&#34;</span> |
| </span></span><span style="display:flex;"><span> timeout=<span style="color:#2aa198">&#34;5000&#34;</span> ref=<span style="color:#2aa198">&#34;helloServiceV3&#34;</span> registry=<span style="color:#2aa198">&#34;registry1&#34;</span> protocol=<span style="color:#2aa198">&#34;dubbo,tri&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/beans&gt;</span> |
| </span></span></code></pre></div><h3 id="annotation">Annotation</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">@Configuration</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">@EnableDubbo</span>(scanBasePackages <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;org.apache.dubbo.config.spring.isolation.spring.annotation.provider&#34;</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">ProviderConfiguration</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Bean</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> RegistryConfig <span style="color:#268bd2">registryConfig</span>() { |
| </span></span><span style="display:flex;"><span> RegistryConfig registryConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> RegistryConfig(); |
| </span></span><span style="display:flex;"><span> registryConfig.setAddress(<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2181&#34;</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> registryConfig; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// NOTE: we need config executor-management-mode=&#34;isolation&#34;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Bean</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> ApplicationConfig <span style="color:#268bd2">applicationConfig</span>() { |
| </span></span><span style="display:flex;"><span> ApplicationConfig applicationConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ApplicationConfig(<span style="color:#2aa198">&#34;provider-app&#34;</span>); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> applicationConfig.setExecutorManagementMode(<span style="color:#2aa198">&#34;isolation&#34;</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> applicationConfig; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// expose services with dubbo protocol</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Bean</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> ProtocolConfig <span style="color:#268bd2">dubbo</span>() { |
| </span></span><span style="display:flex;"><span> ProtocolConfig protocolConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ProtocolConfig(<span style="color:#2aa198">&#34;dubbo&#34;</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> protocolConfig; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// expose services with tri protocol</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Bean</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> ProtocolConfig <span style="color:#268bd2">tri</span>() { |
| </span></span><span style="display:flex;"><span> ProtocolConfig protocolConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ProtocolConfig(<span style="color:#2aa198">&#34;tri&#34;</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> protocolConfig; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// customized thread pool</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Bean</span>(<span style="color:#2aa198">&#34;executor-demo-service&#34;</span>) |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Executor <span style="color:#268bd2">demoServiceExecutor</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#719e07">new</span> DemoServiceExecutor(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// customized thread pool</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Bean</span>(<span style="color:#2aa198">&#34;executor-hello-service&#34;</span>) |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Executor <span style="color:#268bd2">helloServiceExecutor</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#719e07">new</span> HelloServiceExecutor(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">// customized thread pool</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">DemoServiceExecutor</span> <span style="color:#268bd2">extends</span> ThreadPoolExecutor { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">DemoServiceExecutor</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">super</span>(10, 10, 60, TimeUnit.SECONDS, <span style="color:#719e07">new</span> LinkedBlockingDeque<span style="color:#719e07">&lt;&gt;</span>(), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">new</span> NamedThreadFactory(<span style="color:#2aa198">&#34;DemoServiceExecutor&#34;</span>)); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">// customized thread pool</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">HelloServiceExecutor</span> <span style="color:#268bd2">extends</span> ThreadPoolExecutor { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">HelloServiceExecutor</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">super</span>(100, 100, 60, TimeUnit.SECONDS, <span style="color:#719e07">new</span> LinkedBlockingDeque<span style="color:#719e07">&lt;&gt;</span>(), |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">new</span> NamedThreadFactory(<span style="color:#2aa198">&#34;HelloServiceExecutor&#34;</span>)); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">// &#34;executor-hello-service&#34; is beanName</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">@DubboService</span>(executor <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;executor-demo-service&#34;</span>, version <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;1.0.0&#34;</span>, group <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;Group1&#34;</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">DemoServiceImplV1</span> <span style="color:#268bd2">implements</span> DemoService { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">sayName</span>(String name) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;server name&#34;</span>; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Box <span style="color:#268bd2">getBox</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#cb4b16">null</span>; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">// not set executor for this service, the default executor built using threadpool parameter of the protocolConfig</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">@DubboService</span>(version <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;3.0.0&#34;</span>, group <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;Group3&#34;</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">HelloServiceImplV2</span> <span style="color:#268bd2">implements</span> HelloService { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> Logger logger <span style="color:#719e07">=</span> LoggerFactory.getLogger(HelloServiceImplV2.class); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">sayHello</span>(String name) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;server hello&#34;</span>; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">@DubboService</span>(executor <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;executor-hello-service&#34;</span>, version <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;2.0.0&#34;</span>, group <span style="color:#719e07">=</span> <span style="color:#2aa198">&#34;Group2&#34;</span>) |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">HelloServiceImplV3</span> <span style="color:#268bd2">implements</span> HelloService { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">static</span> <span style="color:#268bd2">final</span> Logger logger <span style="color:#719e07">=</span> LoggerFactory.getLogger(HelloServiceImplV3.class); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">sayHello</span>(String name) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;server hello&#34;</span>; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div></description></item><item><title>Overview: 调用链路传递隐式参数</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>可以通过 <code>RpcContext</code> 上的 <code>setAttachment</code> 和 <code>getAttachment</code> 在服务消费方和提供方之间进行参数的隐式传递。</p> |
| <h4 id="背景">背景</h4> |
| <p>上下文信息是 RPC 框架很重要的一个功能,使用 RpcContext 可以为单次调用指定不同配置。如分布式链路追踪场景,其实现原理就是在全链路的上下文中维护一个 traceId,Consumer 和 Provider 通过传递 traceId 来连接一次RPC调用,分别上报日志后可以在追踪系统中串联并展示完整的调用流程。这样可以更方便地发现异常,定位问题。 |
| Dubbo 中的 RpcContext 是一个 ThreadLocal 的临时状态记录器,当接收到 RPC 请求,或发起 RPC 请求时,RpcContext 的状态都会变化。比如:<strong>A 调 B,B 调 C,则 B 机器上,在 B 调 C 之前,RpcContext 记录的是 A 和 B 的信息,在 B 调 C 之后,RpcContext 记录的是 B 和 C 的信息。</strong></p> |
| <p>在 Dubbo 3 中,RpcContext 被拆分为四大模块(ServerContext、ClientAttachment、ServerAttachment 和 ServiceContext)。</p> |
| <p>它们分别承担了不同的职责:</p> |
| <ul> |
| <li>ServiceContext:在 Dubbo 内部使用,用于传递调用链路上的参数信息,如 invoker 对象等</li> |
| <li>ClientAttachment:在 Client 端使用,往 ClientAttachment 中写入的参数将被传递到 Server 端</li> |
| <li>ServerAttachment:在 Server 端使用,从 ServerAttachment 中读取的参数是从 Client 中传递过来的</li> |
| <li>ServerContext:在 Client 端和 Server 端使用,用于从 Server 端回传 Client 端使用,Server 端写入到 ServerContext 的参数在调用结束后可以在 Client 端的 ServerContext 获取到</li> |
| </ul> |
| <p><img src="https://dubbo.apache.org/imgs/v3/concepts/rpccontext.png" alt="/imgs/v3/concepts/rpccontext.png"></p> |
| <p>如上图所示,消费端发起调用的时候可以直接通过 Method Invoke 向远程的服务发起调用,同时消费端往 RpcClientAttachment 写入的数据会连同 Invoke 的参数信息写入到 Invocation 中。 |
| 消费端的 Invocation 经过序列化后通过网络传输发送给服务端,服务端解析 Invocation 生成 Method Invoke 的参数和 RpcServerAttachment,然后发起真实调用。 |
| 在服务端处理结束之后,Method Response 结果会连同 RpcServiceContext 一起生成 Result 对象。 |
| 服务端的 Result 结果对象经过序列化后通过网络传输发送回消费端,消费端解析 Result 生成 Method Response 结果和 RpcServiceContext,返回真实调用结果和上下文给消费端。</p> |
| <blockquote> |
| <p>path, group, version, dubbo, token, timeout 几个 key 是保留字段,请使用其它值。</p> |
| </blockquote> |
| <h2 id="使用场景">使用场景</h2> |
| <p>内部系统通过 Dubbo 调用时, traceId 如何透传到服务提供方。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <blockquote> |
| <p><code>setAttachment</code> 设置的 KV 对,在完成下面一次远程调用会被清空,即多次远程调用要多次设置。</p> |
| </blockquote> |
| <h3 id="在服务消费方端设置隐式参数">在服务消费方端设置隐式参数</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>RpcContext.getClientAttachment().setAttachment(<span style="color:#2aa198">&#34;index&#34;</span>, <span style="color:#2aa198">&#34;1&#34;</span>); <span style="color:#586e75">// 隐式传参,后面的远程调用都会隐式将这些参数发送到服务器端,类似cookie,用于框架集成,不建议常规业务使用</span> |
| </span></span><span style="display:flex;"><span>xxxService.xxx(); <span style="color:#586e75">// 远程调用</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// ...</span> |
| </span></span></code></pre></div><h3 id="在服务提供方端获取隐式参数">在服务提供方端获取隐式参数</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">XxxServiceImpl</span> <span style="color:#268bd2">implements</span> XxxService { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">xxx</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 获取客户端隐式传入的参数,用于框架集成,不建议常规业务使用</span> |
| </span></span><span style="display:flex;"><span> String index <span style="color:#719e07">=</span> RpcContext.getServerAttachment().getAttachment(<span style="color:#2aa198">&#34;index&#34;</span>); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="在服务提供方写入回传参数">在服务提供方写入回传参数</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">XxxServiceImpl</span> <span style="color:#268bd2">implements</span> XxxService { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">xxx</span>() { |
| </span></span><span style="display:flex;"><span> String index <span style="color:#719e07">=</span> xxx; |
| </span></span><span style="display:flex;"><span> RpcContext.getServerContext().setAttachment(<span style="color:#2aa198">&#34;result&#34;</span>, index); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="在消费端获取回传参数">在消费端获取回传参数</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>xxxService.xxx(); <span style="color:#586e75">// 远程调用</span> |
| </span></span><span style="display:flex;"><span>String result <span style="color:#719e07">=</span> RpcContext.getServerContext().getAttachment(<span style="color:#2aa198">&#34;result&#34;</span>); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// ...</span> |
| </span></span></code></pre></div><blockquote> |
| <p>参数透传问题</p> |
| </blockquote> |
| <p>在 Dubbo 2.7 中,在 A 端设置的参数,调用 B 以后,如果 B 继续调用了 C,原来在 A 中设置的参数也会被带到 C 端过去,造成参数污染的问题。 |
| Dubbo 3 对 RpcContext 进行了重构,支持可选参数透传,默认开启参数透传。</p> |
| <p>在 Dubbo 3 中提供了如下的 SPI,默认无实现,用户可以自行定义实现,<code>select</code> 的结果(可以从 RpcClientAttachment 获取当前所有参数)将作为需要透传的键值对传递到下一跳,如果返回 null 则表示不透传参数。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">@SPI</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">PenetrateAttachmentSelector</span> { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">/** |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * Select some attachments to pass to next hop. |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * These attachments can fetch from {@link RpcContext#getServerAttachment()} or user defined. |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> * @return attachment pass to next hop |
| </span></span></span><span style="display:flex;"><span><span style="color:#586e75"> */</span> |
| </span></span><span style="display:flex;"><span> Map<span style="color:#719e07">&lt;</span>String, Object<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">select</span>(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div></description></item><item><title>Overview: 动态指定 IP 调用</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/specify-ip/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/specify-ip/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>使用 Dubbo 的扩展,实现指定 IP 调用。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>发起请求的时候需要指定本次调用的服务端,如消息回调、流量隔离等。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="插件依赖">插件依赖</h3> |
| <p>适配 Dubbo 3 版本</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.apache.dubbo.extensions<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>dubbo-cluster-specify-address-dubbo3<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>1.0.0<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span></code></pre></div><p>适配 Dubbo 2 版本</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dependency&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;groupId&gt;</span>org.apache.dubbo.extensions<span style="color:#268bd2">&lt;/groupId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;artifactId&gt;</span>dubbo-cluster-specify-address-dubbo2<span style="color:#268bd2">&lt;/artifactId&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;version&gt;</span>1.0.0<span style="color:#268bd2">&lt;/version&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dependency&gt;</span> |
| </span></span></code></pre></div><h3 id="调用示例">调用示例</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>ReferenceConfig<span style="color:#719e07">&lt;</span>DemoService<span style="color:#719e07">&gt;</span> referenceConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ReferenceConfig<span style="color:#719e07">&lt;&gt;</span>(); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// ... init</span> |
| </span></span><span style="display:flex;"><span>DemoService demoService <span style="color:#719e07">=</span> referenceConfig.get(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// for invoke</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 1. find 10.10.10.10:20880 exist</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 2. if not exist, create a invoker to 10.10.10.10:20880 if `needToCreate` is true (only support in Dubbo 3.x&#39;s implementation)</span> |
| </span></span><span style="display:flex;"><span>UserSpecifiedAddressUtil.setAddress(<span style="color:#719e07">new</span> Address(<span style="color:#2aa198">&#34;10.10.10.10&#34;</span>, 20880, <span style="color:#cb4b16">true</span>)); |
| </span></span><span style="display:flex;"><span>demoService.sayHello(<span style="color:#2aa198">&#34;world&#34;</span>); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// for invoke</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 1. find 10.10.10.10:any exist</span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 2. if not exist, create a invoker to 10.10.10.10:20880 if `needToCreate` is true (only support in Dubbo 3.x&#39;s implementation)</span> |
| </span></span><span style="display:flex;"><span>UserSpecifiedAddressUtil.setAddress(<span style="color:#719e07">new</span> Address(<span style="color:#2aa198">&#34;10.10.10.10&#34;</span>, 0, <span style="color:#cb4b16">true</span>)); |
| </span></span><span style="display:flex;"><span>demoService.sayHello(<span style="color:#2aa198">&#34;world&#34;</span>); |
| </span></span></code></pre></div><h3 id="参数说明">参数说明</h3> |
| <p>指定 IP 调用的参数围绕 <code>Address</code> 对象展开。参数类型参考如下:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">package</span> org.apache.dubbo.rpc.cluster.specifyaddress; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">Address</span> <span style="color:#268bd2">implements</span> Serializable { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// ip - priority: 3</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> String ip; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// ip+port - priority: 2</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#dc322f">int</span> port; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// address - priority: 1</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> URL urlAddress; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#dc322f">boolean</span> needToCreate <span style="color:#719e07">=</span> <span style="color:#cb4b16">false</span>; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// ignore setter and getter</span> |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><ol> |
| <li><code>urlAddress</code> 为最高优先级,如果指定了目标的 URL 地址,会优先使用该地址。(不再匹配后续)</li> |
| <li>ip + port(非 0 端口) 为第二优先级,会从注册中心已经推送的地址中进行匹配。(不再匹配后续)</li> |
| <li>ip 为第三优先级,会从注册中心已经推送的地址中进行匹配。</li> |
| </ol> |
| <p>特别的,如果指定了 <code>needToCreate</code> 为 <code>true</code>,将会自动根据传入的参数构建一个 invoker。对于通过指定 ip ( + port ) 方式指定的地址, |
| 将会自动使用注册中心中第一个地址的参数为模板进行创建;如果无地址将基于 Dubbo 协议自动创建。 |
| 如需定制创建 invoker 的逻辑请实现 <code>org.apache.dubbo.rpc.cluster.specifyaddress.UserSpecifiedServiceAddressBuilder</code> SPI 接口。(此功能仅<strong>Dubbo 3 实现支持</strong>)</p> |
| <p>在构建完 <code>Address</code> 参数每次请求前通过 <code>UserSpecifiedAddressUtil</code> 工具类传给 Dubbo 框架。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">package</span> org.apache.dubbo.rpc.cluster.specifyaddress; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">UserSpecifiedAddressUtil</span> { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">static</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">setAddress</span>(Address address) { ... } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><blockquote> |
| <p><strong>必须每次都设置,而且设置后必须马上发起调用</strong>,如果出现拦截器报错(Dubbo 框架内 remove 此值是在选址过程进行的)建议设置 null 以避免 ThreadLocal 内存泄漏导致影响后续调用。</p> |
| </blockquote></description></item><item><title>Overview: 直连提供者</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/explicit-target/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/explicit-target/</guid><description> |
| <div class="pageinfo pageinfo-primary"> |
| <p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅<a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/specify-ip/">最新版本</a>。</p> |
| </div> |
| <p>在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直连方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表。</p> |
| <p><img src="https://dubbo.apache.org/imgs/user/dubbo-directly.jpg" alt="/user-guide/images/dubbo-directly.jpg"></p> |
| <h2 id="通过-xml-配置">通过 XML 配置</h2> |
| <p>如果是线上需求需要点对点,可在 <code>&lt;dubbo:reference&gt;</code> 中配置 url 指向提供者,将绕过注册中心,多个地址用分号隔开,配置如下:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;xxxService&#34;</span> interface=<span style="color:#2aa198">&#34;com.alibaba.xxx.XxxService&#34;</span> url=<span style="color:#2aa198">&#34;dubbo://localhost:20890&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div> |
| <div class="alert alert-primary" role="alert"> |
| <h4 class="alert-heading">提示</h4> |
| <code>1.0.6</code> 及以上版本支持 |
| </div> |
| <h2 id="通过--d-参数指定">通过 -D 参数指定</h2> |
| <p>在 JVM 启动参数中加入-D参数映射服务地址,如:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>java -Dcom.alibaba.xxx.XxxService<span style="color:#719e07">=</span>dubbo://localhost:20890 |
| </span></span></code></pre></div> |
| <div class="alert alert-primary" role="alert"> |
| <h4 class="alert-heading">提示</h4> |
| key 为服务名,value 为服务提供者 url,此配置优先级最高,<code>1.0.15</code> 及以上版本支持 |
| </div> |
| <h2 id="通过文件映射">通过文件映射</h2> |
| <p>如果服务比较多,也可以用文件映射,用 <code>-Ddubbo.resolve.file</code> 指定映射文件路径,此配置优先级高于 <code>&lt;dubbo:reference&gt;</code> 中的配置 [^3],如:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>java -Ddubbo.resolve.file<span style="color:#719e07">=</span>xxx.properties |
| </span></span></code></pre></div><p>然后在映射文件 <code>xxx.properties</code> 中加入配置,其中 key 为服务名,value 为服务提供者 URL:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-properties" data-lang="properties"><span style="display:flex;"><span>com.alibaba.xxx.XxxService<span style="color:#719e07">=</span><span style="color:#2aa198">dubbo://localhost:20890</span> |
| </span></span></code></pre></div> |
| <div class="alert alert-primary" role="alert"> |
| <h4 class="alert-heading">提示</h4> |
| <code>1.0.15</code> 及以上版本支持,<code>2.0</code> 以上版本自动加载 ${user.home}/dubbo-resolve.properties文件,不需要配置 |
| </div> |
| <div class="alert alert-warning" role="alert"> |
| <h4 class="alert-heading">注意</h4> |
| 为了避免复杂化线上环境,不要在线上使用这个功能,只应在测试阶段使用。 |
| </div></description></item><item><title>Overview: RPC调用上下文</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/context/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/context/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>上下文中存放的是当前调用过程中所需的环境信息。所有配置信息都将转换为 URL 的参数,参见 <a href="../../../reference-manual/config/properties/">schema 配置参考手册</a> 中的<strong>对应URL参数</strong>一列。</p> |
| <p>RpcContext 是一个 ThreadLocal 的临时状态记录器,当接收到 RPC 请求,或发起 RPC 请求时,RpcContext 的状态都会变化。比如:A 调 B,B 再调 C,则 B 机器上,在 B 调 C 之前,RpcContext 记录的是 A 调 B 的信息,在 B 调 C 之后,RpcContext 记录的是 B 调 C 的信息。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>全局链路追踪和隐藏参数。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="服务消费方">服务消费方</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">// 远程调用</span> |
| </span></span><span style="display:flex;"><span>xxxService.xxx(); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 本端是否为消费端,这里会返回true</span> |
| </span></span><span style="display:flex;"><span><span style="color:#dc322f">boolean</span> isConsumerSide <span style="color:#719e07">=</span> RpcContext.getServiceContext().isConsumerSide(); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 获取最后一次调用的提供方IP地址</span> |
| </span></span><span style="display:flex;"><span>String serverIP <span style="color:#719e07">=</span> RpcContext.getServiceContext().getRemoteHost(); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 获取当前服务配置信息,所有配置信息都将转换为URL的参数</span> |
| </span></span><span style="display:flex;"><span>String application <span style="color:#719e07">=</span> RpcContext.getServiceContext().getUrl().getParameter(<span style="color:#2aa198">&#34;application&#34;</span>); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 注意:每发起RPC调用,上下文状态会变化</span> |
| </span></span><span style="display:flex;"><span>yyyService.yyy(); |
| </span></span></code></pre></div><h3 id="服务提供方">服务提供方</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">XxxServiceImpl</span> <span style="color:#268bd2">implements</span> XxxService { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">xxx</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 本端是否为提供端,这里会返回true</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">boolean</span> isProviderSide <span style="color:#719e07">=</span> RpcContext.getServiceContext().isProviderSide(); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 获取调用方IP地址</span> |
| </span></span><span style="display:flex;"><span> String clientIP <span style="color:#719e07">=</span> RpcContext.getServiceContext().getRemoteHost(); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 获取当前服务配置信息,所有配置信息都将转换为URL的参数</span> |
| </span></span><span style="display:flex;"><span> String application <span style="color:#719e07">=</span> RpcContext.getServiceContext().getUrl().getParameter(<span style="color:#2aa198">&#34;application&#34;</span>); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 注意:每发起RPC调用,上下文状态会变化</span> |
| </span></span><span style="display:flex;"><span> yyyService.yyy(); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 此时本端变成消费端,这里会返回false</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">boolean</span> isProviderSide <span style="color:#719e07">=</span> RpcContext.getServiceContext().isProviderSide(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div></description></item><item><title>Overview: 服务接口JSON兼容性检测</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/json-compatibility-check/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/json-compatibility-check/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p><code>Dubbo</code>目前支持使用<code>Rest</code>协议进行服务调用,<code>Rest</code>协议默认会使用<code>JSON</code>作为序列化方式,但<code>JSON</code>并不支持<code>Java</code>的一些特殊用法,如<code>接口</code>和<code>抽象类</code>等。</p> |
| <p><code>Dubbo 3.3</code>版本在服务发布流程中增加了<code>服务接口JSON兼容性检测</code>功能, 可以确保服务接口传输对象是否可以被<code>JSON</code>序列化, 进一步提升<code>Rest</code>服务接口的正确性。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>使用<code>Rest</code>作为通信协议,<code>JSON</code>作为序列化方式时,对服务接口进行兼容性检查,确保服务接口传输对象可以正确地被<code>JSON</code>序列化。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <p>当使用<code>Rest</code>协议作为通信协议,<code>JSON</code>作为序列化方式时,可以在<code>xml</code>文件中通过配置<code>protocol</code>的<code>json-check-level</code>属性来配置<code>JSON兼容性检查</code>的级别。</p> |
| <p>目前有<code>3</code>种级别,每种级别的具体含义如下:</p> |
| <ul> |
| <li><code>disabled</code>:表示<code>不开启JSON兼容性检查</code>,此时不会对接口进行兼容性检查。</li> |
| <li><code>warn</code>:表示<code>开启JSON兼容性检查</code>,如果出现不兼容的情况,将会以<code>warn</code>级别的日志形式将不兼容的接口名称打印输出到终端。</li> |
| <li><code>strict</code>:表示<code>开启JSON兼容性检查</code>,如果出现不兼容的情况,将会在启动时抛出<code>IllegalStateException</code>异常,终止启动流程,同时会将不兼容的接口名称存放在异常信息中。</li> |
| </ul> |
| <blockquote> |
| <p>如果没有通过<code>json-check-level</code>指定兼容性检查级别,则默认是<code>warn</code>告警级别。</p> |
| </blockquote> |
| <h3 id="使用示例">使用示例</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#719e07">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;beans</span> xmlns:xsi=<span style="color:#2aa198">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:dubbo=<span style="color:#2aa198">&#34;http://dubbo.apache.org/schema/dubbo&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:context=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/context&#34;</span> |
| </span></span><span style="display:flex;"><span> xsi:schemaLocation=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd |
| </span></span></span><span style="display:flex;"><span><span style="color:#2aa198"> http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context |
| </span></span></span><span style="display:flex;"><span><span style="color:#2aa198"> http://www.springframework.org/schema/context/spring-context.xsd&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;context:component-scan</span> base-package=<span style="color:#2aa198">&#34;com.example.rest&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;bean</span> name=<span style="color:#2aa198">&#34;dubboConfig&#34;</span> class=<span style="color:#2aa198">&#34;com.example.rest.config.DubboConfig&#34;</span><span style="color:#268bd2">&gt;&lt;/bean&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:application</span> name=<span style="color:#2aa198">&#34;rest-provider&#34;</span> owner=<span style="color:#2aa198">&#34;programmer&#34;</span> organization=<span style="color:#2aa198">&#34;dubbo&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:registry</span> address=<span style="color:#2aa198">&#34;zookeeper://${zookeeper.address:127.0.0.1}:2180&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 将JSON兼容性检查级别设为disabled --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:protocol</span> name=<span style="color:#2aa198">&#34;rest&#34;</span> port=<span style="color:#2aa198">&#34;8880&#34;</span> threads=<span style="color:#2aa198">&#34;300&#34;</span> json-check-level=<span style="color:#2aa198">&#34;disabled&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 将JSON兼容性检查级别设为warn --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:protocol</span> name=<span style="color:#2aa198">&#34;rest&#34;</span> port=<span style="color:#2aa198">&#34;8880&#34;</span> threads=<span style="color:#2aa198">&#34;300&#34;</span> json-check-level=<span style="color:#2aa198">&#34;warn&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 将JSON兼容性检查级别设为strict --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:protocol</span> name=<span style="color:#2aa198">&#34;rest&#34;</span> port=<span style="color:#2aa198">&#34;8880&#34;</span> threads=<span style="color:#2aa198">&#34;300&#34;</span> json-check-level=<span style="color:#2aa198">&#34;strict&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/beans&gt;</span> |
| </span></span></code></pre></div></description></item><item><title>Overview: 一致性哈希选址</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>在分布式系统中跨多个节点均匀分布请求的方法,使用哈希算法创建请求的哈希并根据哈希值确定哪个节点应该处理请求,算法确保每个节点处理的请求数量大致相等。如果一个节点发生故障,其他节点可以快速接管请求,保持系统高可用性,即使一个节点出现故障,系统的数据映射到系统中有限数量节点的哈希算法,在系统中添加或删除节点时,只需更改有限数量的映射,确保数据均匀分布在系统中的所有节点上提高系统的性能。</p> |
| <p><a href="https://dubbo.apache.org/zh-cn/blog/2019/05/01/dubbo-%E4%B8%80%E8%87%B4%E6%80%A7hash%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%AE%9E%E7%8E%B0%E5%89%96%E6%9E%90/">Dubbo 一致性Hash负载均衡实现剖析</a></p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>在有多台服务端的时候根据请求参数的进行一致性哈希散列选择服务端。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <p>配置一致性哈希的方式有很多,最常见的是:</p> |
| <h3 id="注解配置">注解配置</h3> |
| <blockquote> |
| <p>@DubboReference(loadbalance = “consistenthash”)</p> |
| </blockquote> |
| <h3 id="api-配置">API 配置</h3> |
| <blockquote> |
| <p>referenceConfig.setLoadBalance(&ldquo;consistenthash&rdquo;);</p> |
| </blockquote> |
| <h3 id="properties-配置">Properties 配置</h3> |
| <blockquote> |
| <p>dubbo.reference.loadbalance=consistenthash</p> |
| </blockquote> |
| <h3 id="xml-配置">XML 配置</h3> |
| <blockquote> |
| <p>&lt;dubbo:reference loadbalance=“consistenthash” /&gt;</p> |
| </blockquote> |
| <p>默认采用第一个参数作为哈希 key,如果需要切换参数,可以指定 <code>hash.arguments</code> 属性</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>ReferenceConfig<span style="color:#719e07">&lt;</span>DemoService<span style="color:#719e07">&gt;</span> referenceConfig <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ReferenceConfig<span style="color:#719e07">&lt;</span>DemoService<span style="color:#719e07">&gt;</span>(); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// ... init</span> |
| </span></span><span style="display:flex;"><span>Map<span style="color:#719e07">&lt;</span>String, String<span style="color:#719e07">&gt;</span> parameters <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> HashMap<span style="color:#719e07">&lt;</span>String, String<span style="color:#719e07">&gt;</span>(); |
| </span></span><span style="display:flex;"><span>parameters.put(<span style="color:#2aa198">&#34;hash.arguments&#34;</span>, <span style="color:#2aa198">&#34;1&#34;</span>); |
| </span></span><span style="display:flex;"><span>parameters.put(<span style="color:#2aa198">&#34;sayHello.hash.arguments&#34;</span>, <span style="color:#2aa198">&#34;0,1&#34;</span>); |
| </span></span><span style="display:flex;"><span>referenceConfig.setParameters(parameters); |
| </span></span><span style="display:flex;"><span>referenceConfig.setLoadBalance(<span style="color:#2aa198">&#34;consistenthash&#34;</span>); |
| </span></span><span style="display:flex;"><span>referenceConfig.get(); |
| </span></span></code></pre></div></description></item><item><title>Overview: 只订阅</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/subscribe-only/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/subscribe-only/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>为方便开发测试,经常会在线下共用一个所有服务可用的注册中心,这时,如果一个正在开发中的服务提供者注册,可能会影响消费者不能正常运行。</p> |
| <p>可以让服务提供者开发方,只订阅服务(开发的服务可能依赖其它服务),而不注册正在开发的服务,通过直连测试正在开发的服务。</p> |
| <p><img src="https://dubbo.apache.org/imgs/user/subscribe-only.jpg" alt="/user-guide/images/subscribe-only.jpg"></p> |
| <h2 id="使用场景">使用场景</h2> |
| <ul> |
| <li>消费者是一个正在开发但尚未部署的新应用程序。消费者希望订阅未注册的服务,以确保在部署后能够访问所需的服务。</li> |
| <li>消费者是正在更新或修改的现有应用程序。消费者希望订阅未注册的服务以确保它能够访问更新或修改的服务。</li> |
| <li>消费者是在暂存环境中开发或测试的应用程序。消费者希望订阅未注册的服务,以确保在开发或测试时能够访问所需的服务。</li> |
| </ul> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="禁用注册配置">禁用注册配置</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> address=<span style="color:#2aa198">&#34;10.20.153.10:9090&#34;</span> register=<span style="color:#2aa198">&#34;false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p><strong>或者</strong></p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> address=<span style="color:#2aa198">&#34;10.20.153.10:9090?register=false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div></description></item><item><title>Overview: 调用触发事件通知</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/events-notify/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/events-notify/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>在调用之前、调用之后、出现异常时,会触发 <code>oninvoke</code>、<code>onreturn</code>、<code>onthrow</code> 三个事件,可以配置当事件发生时,通知哪个类的哪个方法。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>调用服务方法前我们可以记录开始时间,调用结束后统计整个调用耗费,发生异常时我们可以告警或打印错误日志或者调用服务前后记录请求日志、响应日志等。</p> |
| <blockquote> |
| <p>参考用例 |
| <a href="https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-notify">https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-notify</a></p> |
| </blockquote> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="服务提供者与消费者共享服务接口">服务提供者与消费者共享服务接口</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">interface</span> <span style="color:#268bd2">IDemoService</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Person <span style="color:#268bd2">get</span>(<span style="color:#dc322f">int</span> id); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="服务提供者实现">服务提供者实现</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">class</span> <span style="color:#268bd2">NormalDemoService</span> <span style="color:#268bd2">implements</span> IDemoService { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Person <span style="color:#268bd2">get</span>(<span style="color:#dc322f">int</span> id) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#719e07">new</span> Person(id, <span style="color:#2aa198">&#34;charles`son&#34;</span>, 4); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="服务提供者配置">服务提供者配置</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:application</span> name=<span style="color:#2aa198">&#34;rpc-callback-demo&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> address=<span style="color:#2aa198">&#34;zookeeper://127.0.0.1:2181&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;bean</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> class=<span style="color:#2aa198">&#34;org.apache.dubbo.callback.implicit.NormalDemoService&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.callback.implicit.IDemoService&#34;</span> ref=<span style="color:#2aa198">&#34;demoService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> group=<span style="color:#2aa198">&#34;cn&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="服务消费者-callback-接口">服务消费者 Callback 接口</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">interface</span> <span style="color:#268bd2">Notify</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onreturn</span>(Person msg, Integer id); |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onthrow</span>(Throwable ex, Integer id); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="服务消费者-callback-实现">服务消费者 Callback 实现</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">class</span> <span style="color:#268bd2">NotifyImpl</span> <span style="color:#268bd2">implements</span> Notify { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Map<span style="color:#719e07">&lt;</span>Integer, Person<span style="color:#719e07">&gt;</span> ret <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> HashMap<span style="color:#719e07">&lt;</span>Integer, Person<span style="color:#719e07">&gt;</span>(); |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Map<span style="color:#719e07">&lt;</span>Integer, Throwable<span style="color:#719e07">&gt;</span> errors <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> HashMap<span style="color:#719e07">&lt;</span>Integer, Throwable<span style="color:#719e07">&gt;</span>(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onreturn</span>(Person msg, Integer id) { |
| </span></span><span style="display:flex;"><span> System.out.println(<span style="color:#2aa198">&#34;onreturn:&#34;</span> <span style="color:#719e07">+</span> msg); |
| </span></span><span style="display:flex;"><span> ret.put(id, msg); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">onthrow</span>(Throwable ex, Integer id) { |
| </span></span><span style="display:flex;"><span> errors.put(id, ex); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="服务消费者-callback-配置">服务消费者 Callback 配置</h3> |
| <p>两者叠加存在以下几种组合情况:</p> |
| <ul> |
| <li>异步回调模式:<code>async=true onreturn=&quot;xxx&quot;</code></li> |
| <li>同步回调模式:<code>async=false onreturn=&quot;xxx&quot;</code></li> |
| <li>异步无回调 :<code>async=true</code></li> |
| <li>同步无回调 :<code>async=false</code></li> |
| </ul> |
| <p><code>callback</code> 与 <code>async</code> 功能正交分解,<code>async=true</code> 表示结果是否马上返回,<code>async=false</code> 默认,<code>onreturn</code> 表示是否需要回调。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;bean</span> id =<span style="color:#2aa198">&#34;demoCallback&#34;</span> class = <span style="color:#2aa198">&#34;org.apache.dubbo.callback.implicit.NotifyImpl&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.callback.implicit.IDemoService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> group=<span style="color:#2aa198">&#34;cn&#34;</span> <span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:method</span> name=<span style="color:#2aa198">&#34;get&#34;</span> async=<span style="color:#2aa198">&#34;true&#34;</span> onreturn = <span style="color:#2aa198">&#34;demoCallback.onreturn&#34;</span> onthrow=<span style="color:#2aa198">&#34;demoCallback.onthrow&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dubbo:reference&gt;</span> |
| </span></span></code></pre></div><h3 id="测试代码">测试代码</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>IDemoService demoService <span style="color:#719e07">=</span> (IDemoService) context.getBean(<span style="color:#2aa198">&#34;demoService&#34;</span>); |
| </span></span><span style="display:flex;"><span>NotifyImpl notify <span style="color:#719e07">=</span> (NotifyImpl) context.getBean(<span style="color:#2aa198">&#34;demoCallback&#34;</span>); |
| </span></span><span style="display:flex;"><span><span style="color:#dc322f">int</span> requestId <span style="color:#719e07">=</span> 2; |
| </span></span><span style="display:flex;"><span>Person ret <span style="color:#719e07">=</span> demoService.get(requestId); |
| </span></span><span style="display:flex;"><span>Assert.assertEquals(<span style="color:#cb4b16">null</span>, ret); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">//for Test:只是用来说明callback正常被调用,业务具体实现自行决定.</span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">for</span> (<span style="color:#dc322f">int</span> i <span style="color:#719e07">=</span> 0; i <span style="color:#719e07">&lt;</span> 10; i<span style="color:#719e07">++</span>) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">if</span> (<span style="color:#719e07">!</span>notify.ret.containsKey(requestId)) { |
| </span></span><span style="display:flex;"><span> Thread.sleep(200); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">else</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">break</span>; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span><span style="display:flex;"><span>Assert.assertEquals(requestId, notify.ret.get(requestId).getId()); |
| </span></span></code></pre></div></description></item><item><title>Overview: 多协议</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-protocols/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-protocols/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>与不同系统的兼容:如果你正在与一个支持特定协议的系统集成,你可以使用 Dubbo 对该协议的支持来方便通信。例如,如果您正在与使用 RMI 的遗留系统进行集成,则可以使用 Dubbo 的 RMI 协议支持与该系统进行通信。使用多种协议可以提供灵活性,并允许您为您的特定用例选择最佳选项。</p> |
| <ul> |
| <li>改进的性能:不同的协议可能具有不同的性能特征,这取决于传输的数据量和网络条件等因素。通过使用多种协议,可以根据您的性能要求选择最适合给定情况的协议。</li> |
| <li>安全性:一些协议可能提供比其他协议更好的安全特性。HTTPS 协议通过加密传输的数据来提供安全通信,这对于保护敏感数据非常有用。</li> |
| <li>易用性:某些协议在某些情况下可能更易于使用。如果正在构建 Web 应用程序并希望与远程服务集成,使用 HTTP 协议可能比使用需要更复杂设置的协议更方便。</li> |
| </ul> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="不同服务不同协议">不同服务不同协议</h3> |
| <p>不同服务在性能上适用不同协议进行传输,比如大数据用短连接协议,小数据大并发用长连接协议</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#719e07">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;beans</span> xmlns=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:xsi=<span style="color:#2aa198">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:dubbo=<span style="color:#2aa198">&#34;http://dubbo.apache.org/schema/dubbo&#34;</span> |
| </span></span><span style="display:flex;"><span> xsi:schemaLocation=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:application</span> name=<span style="color:#2aa198">&#34;world&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;registry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.141.150:9090&#34;</span> username=<span style="color:#2aa198">&#34;admin&#34;</span> password=<span style="color:#2aa198">&#34;hello1234&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 多协议配置 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:protocol</span> name=<span style="color:#2aa198">&#34;dubbo&#34;</span> port=<span style="color:#2aa198">&#34;20880&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:protocol</span> name=<span style="color:#2aa198">&#34;rmi&#34;</span> port=<span style="color:#2aa198">&#34;1099&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 使用dubbo协议暴露服务 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;com.alibaba.hello.api.HelloService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> ref=<span style="color:#2aa198">&#34;helloService&#34;</span> protocol=<span style="color:#2aa198">&#34;dubbo&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 使用rmi协议暴露服务 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;com.alibaba.hello.api.DemoService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> ref=<span style="color:#2aa198">&#34;demoService&#34;</span> protocol=<span style="color:#2aa198">&#34;rmi&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/beans&gt;</span> |
| </span></span></code></pre></div><h3 id="多协议暴露服务">多协议暴露服务</h3> |
| <p>需要与 http 客户端相互操作</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#719e07">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;beans</span> xmlns=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:xsi=<span style="color:#2aa198">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:dubbo=<span style="color:#2aa198">&#34;http://dubbo.apache.org/schema/dubbo&#34;</span> |
| </span></span><span style="display:flex;"><span> xsi:schemaLocation=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:application</span> name=<span style="color:#2aa198">&#34;world&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;registry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.141.150:9090&#34;</span> username=<span style="color:#2aa198">&#34;admin&#34;</span> password=<span style="color:#2aa198">&#34;hello1234&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 多协议配置 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:protocol</span> name=<span style="color:#2aa198">&#34;dubbo&#34;</span> port=<span style="color:#2aa198">&#34;20880&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:protocol</span> name=<span style="color:#2aa198">&#34;hessian&#34;</span> port=<span style="color:#2aa198">&#34;8080&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 使用多个协议暴露服务 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:service</span> id=<span style="color:#2aa198">&#34;helloService&#34;</span> interface=<span style="color:#2aa198">&#34;com.alibaba.hello.api.HelloService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> protocol=<span style="color:#2aa198">&#34;dubbo,hessian&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/beans&gt;</span> |
| </span></span></code></pre></div></description></item><item><title>Overview: 服务端对客户端进行回调</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/callback-parameter/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/callback-parameter/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>参数回调方式与调用本地 callback 或 listener 相同,只需要在 Spring 的配置文件中声明哪个参数是 callback 类型即可。Dubbo 将基于长连接生成反向代理,这样就可以从服务器端调用客户端逻辑。可以参考 <a href="https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-callback">dubbo 项目中的示例代码</a>。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>回调函数通知客户端执行结果,或发送通知,在方法执行时间比较长时,类似异步调用,审批工作流中回调客户端审批结果。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="服务接口示例">服务接口示例</h3> |
| <p>CallbackService.java</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">package</span> com.callback; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">CallbackService</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">addListener</span>(String key, CallbackListener listener); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>CallbackListener.java</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">package</span> com.callback; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">CallbackListener</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">changed</span>(String msg); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="服务提供者接口实现示例">服务提供者接口实现示例</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">package</span> com.callback.impl; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> java.text.SimpleDateFormat; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> java.util.Date; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> java.util.Map; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> java.util.concurrent.ConcurrentHashMap; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> com.callback.CallbackListener; |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">import</span> com.callback.CallbackService; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">CallbackServiceImpl</span> <span style="color:#268bd2">implements</span> CallbackService { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> Map<span style="color:#719e07">&lt;</span>String, CallbackListener<span style="color:#719e07">&gt;</span> listeners <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ConcurrentHashMap<span style="color:#719e07">&lt;</span>String, CallbackListener<span style="color:#719e07">&gt;</span>(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">CallbackServiceImpl</span>() { |
| </span></span><span style="display:flex;"><span> Thread t <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> Thread(<span style="color:#719e07">new</span> Runnable() { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">run</span>() { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">while</span>(<span style="color:#cb4b16">true</span>) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">for</span>(Map.Entry<span style="color:#719e07">&lt;</span>String, CallbackListener<span style="color:#719e07">&gt;</span> entry : listeners.entrySet()){ |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> entry.getValue().changed(getChanged(entry.getKey())); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (Throwable t) { |
| </span></span><span style="display:flex;"><span> listeners.remove(entry.getKey()); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> Thread.sleep(5000); <span style="color:#586e75">// 定时触发变更通知</span> |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (Throwable t) { <span style="color:#586e75">// 防御容错</span> |
| </span></span><span style="display:flex;"><span> t.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> }); |
| </span></span><span style="display:flex;"><span> t.setDaemon(<span style="color:#cb4b16">true</span>); |
| </span></span><span style="display:flex;"><span> t.start(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">addListener</span>(String key, CallbackListener listener) { |
| </span></span><span style="display:flex;"><span> listeners.put(key, listener); |
| </span></span><span style="display:flex;"><span> listener.changed(getChanged(key)); <span style="color:#586e75">// 发送变更通知</span> |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> String <span style="color:#268bd2">getChanged</span>(String key) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;Changed: &#34;</span> <span style="color:#719e07">+</span> <span style="color:#719e07">new</span> SimpleDateFormat(<span style="color:#2aa198">&#34;yyyy-MM-dd HH:mm:ss&#34;</span>).format(<span style="color:#719e07">new</span> Date()); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="服务提供者配置示例">服务提供者配置示例</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;bean</span> id=<span style="color:#2aa198">&#34;callbackService&#34;</span> class=<span style="color:#2aa198">&#34;com.callback.impl.CallbackServiceImpl&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;com.callback.CallbackService&#34;</span> ref=<span style="color:#2aa198">&#34;callbackService&#34;</span> connections=<span style="color:#2aa198">&#34;1&#34;</span> callbacks=<span style="color:#2aa198">&#34;1000&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:method</span> name=<span style="color:#2aa198">&#34;addListener&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:argument</span> index=<span style="color:#2aa198">&#34;1&#34;</span> callback=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!--也可以通过指定类型的方式--&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!--&lt;dubbo:argument type=&#34;com.demo.CallbackListener&#34; callback=&#34;true&#34; /&gt;--&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;/dubbo:method&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dubbo:service&gt;</span> |
| </span></span></code></pre></div><h3 id="服务消费者配置示例">服务消费者配置示例</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;callbackService&#34;</span> interface=<span style="color:#2aa198">&#34;com.callback.CallbackService&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="服务消费者调用示例">服务消费者调用示例</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>ClassPathXmlApplicationContext context <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ClassPathXmlApplicationContext(<span style="color:#2aa198">&#34;classpath:consumer.xml&#34;</span>); |
| </span></span><span style="display:flex;"><span>context.start(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>CallbackService callbackService <span style="color:#719e07">=</span> (CallbackService) context.getBean(<span style="color:#2aa198">&#34;callbackService&#34;</span>); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>callbackService.addListener(<span style="color:#2aa198">&#34;foo.bar&#34;</span>, <span style="color:#719e07">new</span> CallbackListener(){ |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#dc322f">void</span> <span style="color:#268bd2">changed</span>(String msg) { |
| </span></span><span style="display:flex;"><span> System.out.println(<span style="color:#2aa198">&#34;callback1:&#34;</span> <span style="color:#719e07">+</span> msg); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>}); |
| </span></span></code></pre></div></description></item><item><title>Overview: 本地伪装</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-mock/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-mock/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>在 Dubbo3 中有一种机制可以实现轻量级的服务降级,也就是本地伪装。</p> |
| <p>Mock 是 Stub 的一个子集,便于服务提供方在客户端执行容错逻辑,因经常需要在出现 RpcException (比如网络失败,超时等)时进行容错,而在出现业务异常(比如登录用户名密码错误)时不需要容错, |
| 如果用 Stub,可能就需要捕获并依赖 RpcException 类,而用 Mock 就可以不依赖 RpcException,因为它的约定就是只有出现 RpcException 时才执行。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>本地伪装常被用于服务降级。比如某验权服务,当服务提供方全部挂掉后,假如此时服务消费方发起了一次远程调用,那么本次调用将会失败并抛出一个 <code>RpcException</code> 异常。</p> |
| <p>为了避免出现这种直接抛出异常的情况出现,那么客户端就可以利用本地伪装来提供 Mock 数据返回授权失败。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="开启-mock-配置">开启 Mock 配置</h3> |
| <p>在 Spring XML 配置文件中按以下方式配置:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> mock=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>或</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> mock=<span style="color:#2aa198">&#34;com.foo.BarServiceMock&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>在工程中提供 Mock 实现 [^2]: |
| 在 interface 旁放一个 Mock 实现,它实现 BarService 接口,并有一个无参构造函数。同时,如果没有在配置文件中显式指定 Mock 类的时候,那么需要保证 Mock 类的全限定类名是 <code>原全限定类名+Mock</code> 的形式,例如 <code>com.foo.BarServiceMock</code>,否则将会 Mock 失败。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">package</span> com.foo; |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">BarServiceMock</span> <span style="color:#268bd2">implements</span> BarService { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">sayHello</span>(String name) { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 你可以伪造容错数据,此方法只在出现RpcException时被执行</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;容错数据&#34;</span>; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="使用-return-关键字-mock-返回值">使用 return 关键字 Mock 返回值</h3> |
| <p>使用 <code>return</code> 来返回一个字符串表示的对象,作为 Mock 的返回值。合法的字符串可以是:</p> |
| <ul> |
| <li><em>empty</em>:代表空,返回基本类型的默认值、集合类的空值、自定义实体类的空对象,如果返回值是一个实体类,那么此时返回的将会是一个属性都为默认值的空对象而不是 <code>null</code>。</li> |
| <li><em>null</em>:返回 <code>null</code></li> |
| <li><em>true</em>:返回 <code>true</code></li> |
| <li><em>false</em>:返回 <code>false</code></li> |
| <li><em>JSON 字符串</em>:返回反序列化 JSON 串后所得到的对象</li> |
| </ul> |
| <p>举个例子,如果服务的消费方经常需要 try-catch 捕获异常,如:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">DemoService</span> { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Offer <span style="color:#268bd2">findOffer</span>(String offerId) { |
| </span></span><span style="display:flex;"><span> Offer offer <span style="color:#719e07">=</span> <span style="color:#cb4b16">null</span>; |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> offer <span style="color:#719e07">=</span> offerService.findOffer(offerId); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (RpcException e) { |
| </span></span><span style="display:flex;"><span> logger.error(e); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> offer; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>那么请考虑改为 Mock 实现,并在 Mock 实现中 <code>return null</code>。如果只是想简单的忽略异常,在 <code>2.0.11</code> 以上版本可用:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> mock=<span style="color:#2aa198">&#34;return null&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="使用-throw-关键字-mock-抛出异常">使用 throw 关键字 Mock 抛出异常</h3> |
| <p>使用 <code>throw</code> 来返回一个 Exception 对象,作为 Mock 的返回值。</p> |
| <p>当调用出错时,抛出一个默认的 RPCException:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> mock=<span style="color:#2aa198">&#34;throw&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>当调用出错时,抛出指定的 Exception:</p> |
| <p>自定义异常必须拥有一个入参为 <code>String</code> 的构造函数,该构造函数将用于接受异常信息。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> mock=<span style="color:#2aa198">&#34;throw com.foo.MockException&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="使用-force-和-fail-关键字来配置-mock-的行为">使用 force 和 fail 关键字来配置 Mock 的行为</h3> |
| <p><code>force:</code> 代表强制使用 Mock 行为,在这种情况下不会走远程调用。</p> |
| <p><code>fail:</code> 与默认行为一致,只有当远程调用发生错误时才使用 Mock 行为。也就是说,配置的时候其实是可以不使用 <code>fail</code> 关键字的,直接使用 <code>throw</code> 或者 <code>return</code> 就可以了。</p> |
| <p><code>force:</code> 和 <code>fail:</code> 都支持与 <code>throw</code> 或者 <code>return</code> 组合使用。</p> |
| <p>强制返回指定值:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> mock=<span style="color:#2aa198">&#34;force:return fake&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>强制抛出指定异常:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> mock=<span style="color:#2aa198">&#34;force:throw com.foo.MockException&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>调用失败时返回指定值:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> mock=<span style="color:#2aa198">&#34;fail:return fake&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">&lt;!-- 等价于以下写法 --&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> mock=<span style="color:#2aa198">&#34;return fake&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>调用失败时抛出异常</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> mock=<span style="color:#2aa198">&#34;fail:throw com.foo.MockException&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">&lt;!-- 等价于以下写法 --&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> mock=<span style="color:#2aa198">&#34;throw com.foo.MockException&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="在方法级别配置-mock">在方法级别配置 Mock</h3> |
| <p>Mock 可以在方法级别上指定,假定 <code>com.foo.BarService</code> 上有好几个方法,我们可以单独为 <code>sayHello()</code> 方法指定 Mock 行为。</p> |
| <p>具体配置如下所示,在本例中,只要 <code>sayHello()</code> 被调用到时,强制返回 &ldquo;fake&rdquo;:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;demoService&#34;</span> check=<span style="color:#2aa198">&#34;false&#34;</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:parameter</span> key=<span style="color:#2aa198">&#34;sayHello.mock&#34;</span> value=<span style="color:#2aa198">&#34;force:return fake&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/dubbo:reference&gt;</span> |
| </span></span></code></pre></div></description></item><item><title>Overview: 多注册中心</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-registry/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-registry/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>Dubbo 支持同一服务向多注册中心同时注册,或者不同服务分别注册到不同的注册中心上去,甚至可以同时引用注册在不同注册中心上的同名服务。另外,注册中心是支持自定义扩展的 <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <ul> |
| <li>高可用:多个注册服务器确保即使其中一个注册服务器出现故障,服务仍然可用。</li> |
| <li>负载:同时访问大量服务,使用多个注册服务器帮助在多个服务器之间分配负载提高系统的整体性能和可扩展性。</li> |
| <li>区域:不同地理位置的服务,使用多个注册服务器来确保根据其位置注册和发现服务减少请求需要传输的距离来帮助提高系统的性能和可靠性。</li> |
| <li>安全:使用多个注册服务器。期望将一台注册服务器用于内部服务,另一台用于外部服务,以确保只有授权的客户端才能访问您的内部服务。</li> |
| </ul> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="多注册中心注册">多注册中心注册</h3> |
| <p>比如:中文站有些服务来不及在青岛部署,只在杭州部署,而青岛的其它应用需要引用此服务,就可以将服务同时注册到两个注册中心。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#719e07">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;beans</span> xmlns=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:xsi=<span style="color:#2aa198">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:dubbo=<span style="color:#2aa198">&#34;http://dubbo.apache.org/schema/dubbo&#34;</span> |
| </span></span><span style="display:flex;"><span> xsi:schemaLocation=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:application</span> name=<span style="color:#2aa198">&#34;world&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 多注册中心配置 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;hangzhouRegistry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.141.150:9090&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;qingdaoRegistry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.141.151:9010&#34;</span> default=<span style="color:#2aa198">&#34;false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 向多个注册中心注册 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;com.alibaba.hello.api.HelloService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> ref=<span style="color:#2aa198">&#34;helloService&#34;</span> registry=<span style="color:#2aa198">&#34;hangzhouRegistry,qingdaoRegistry&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/beans&gt;</span> |
| </span></span></code></pre></div><h3 id="不同服务使用不同注册中心">不同服务使用不同注册中心</h3> |
| <p>比如:CRM 有些服务是专门为国际站设计的,有些服务是专门为中文站设计的。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#719e07">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;beans</span> xmlns=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:xsi=<span style="color:#2aa198">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:dubbo=<span style="color:#2aa198">&#34;http://dubbo.apache.org/schema/dubbo&#34;</span> |
| </span></span><span style="display:flex;"><span> xsi:schemaLocation=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:application</span> name=<span style="color:#2aa198">&#34;world&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 多注册中心配置 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;chinaRegistry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.141.150:9090&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;intlRegistry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.154.177:9010&#34;</span> default=<span style="color:#2aa198">&#34;false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 向中文站注册中心注册 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;com.alibaba.hello.api.HelloService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> ref=<span style="color:#2aa198">&#34;helloService&#34;</span> registry=<span style="color:#2aa198">&#34;chinaRegistry&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 向国际站注册中心注册 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;com.alibaba.hello.api.DemoService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> ref=<span style="color:#2aa198">&#34;demoService&#34;</span> registry=<span style="color:#2aa198">&#34;intlRegistry&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/beans&gt;</span> |
| </span></span></code></pre></div><h3 id="多注册中心引用">多注册中心引用</h3> |
| <p>比如:CRM 需同时调用中文站和国际站的 PC2 服务,PC2 在中文站和国际站均有部署,接口及版本号都一样,但连的数据库不一样。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#719e07">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;beans</span> xmlns=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:xsi=<span style="color:#2aa198">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:dubbo=<span style="color:#2aa198">&#34;http://dubbo.apache.org/schema/dubbo&#34;</span> |
| </span></span><span style="display:flex;"><span> xsi:schemaLocation=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:application</span> name=<span style="color:#2aa198">&#34;world&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 多注册中心配置 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;chinaRegistry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.141.150:9090&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;intlRegistry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.154.177:9010&#34;</span> default=<span style="color:#2aa198">&#34;false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 引用中文站服务 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;chinaHelloService&#34;</span> interface=<span style="color:#2aa198">&#34;com.alibaba.hello.api.HelloService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> registry=<span style="color:#2aa198">&#34;chinaRegistry&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 引用国际站服务 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;intlHelloService&#34;</span> interface=<span style="color:#2aa198">&#34;com.alibaba.hello.api.HelloService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> registry=<span style="color:#2aa198">&#34;intlRegistry&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/beans&gt;</span> |
| </span></span></code></pre></div><p>如果只是测试环境临时需要连接两个不同注册中心,使用竖号分隔多个不同注册中心地址:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#719e07">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;beans</span> xmlns=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:xsi=<span style="color:#2aa198">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span> |
| </span></span><span style="display:flex;"><span> xmlns:dubbo=<span style="color:#2aa198">&#34;http://dubbo.apache.org/schema/dubbo&#34;</span> |
| </span></span><span style="display:flex;"><span> xsi:schemaLocation=<span style="color:#2aa198">&#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd&#34;</span><span style="color:#268bd2">&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:application</span> name=<span style="color:#2aa198">&#34;world&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 多注册中心配置,竖号分隔表示同时连接多个不同注册中心,同一注册中心的多个集群地址用逗号分隔 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:registry</span> address=<span style="color:#2aa198">&#34;10.20.141.150:9090|10.20.154.177:9010&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">&lt;!-- 引用服务 --&gt;</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;helloService&#34;</span> interface=<span style="color:#2aa198">&#34;com.alibaba.hello.api.HelloService&#34;</span> version=<span style="color:#2aa198">&#34;1.0.0&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;/beans&gt;</span> |
| </span></span></code></pre></div><div class="footnotes" role="doc-endnotes"> |
| <hr> |
| <ol> |
| <li id="fn:1"> |
| <p>可以自行扩展注册中心,参见:<a href="../../../reference-manual/spi/description/registry">注册中心扩展</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> |
| </li> |
| </ol> |
| </div></description></item><item><title>Overview: 本地存根</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-stub/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-stub/</guid><description> |
| <h2 id="特性说明">特性说明:</h2> |
| <p>远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑。</p> |
| <p><img src="https://dubbo.apache.org/imgs/user/stub.jpg" alt="/user-guide/images/stub.jpg"></p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="spring-配置文件配置">spring 配置文件配置</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:consumer</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> stub=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>或</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:consumer</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> stub=<span style="color:#2aa198">&#34;com.foo.BarServiceStub&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="提供-stub-的实现-2">提供 Stub 的实现 <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">package</span> com.foo; |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">BarServiceStub</span> <span style="color:#268bd2">implements</span> BarService { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">private</span> <span style="color:#268bd2">final</span> BarService barService; |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 构造函数传入真正的远程代理对象</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> <span style="color:#268bd2">BarServiceStub</span>(BarService barService){ |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">this</span>.barService <span style="color:#719e07">=</span> barService; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">sayHello</span>(String name) { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> barService.sayHello(name); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (Exception e) { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 你可以容错,可以做任何AOP拦截事项</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;容错数据&#34;</span>; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><div class="footnotes" role="doc-endnotes"> |
| <hr> |
| <ol> |
| <li id="fn:1"> |
| <p>Stub 必须有可传入 Proxy 的构造函数。&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> |
| </li> |
| <li id="fn:2"> |
| <p>在 interface 旁边放一个 Stub 实现,它实现 BarService 接口,并有一个传入远程 BarService 实例的构造函数。&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> |
| </li> |
| </ol> |
| </div></description></item><item><title>Overview: 回声测试</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/echo-service/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/echo-service/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,能够测试整个调用是否通畅,可用于监控。执行回声测试,客户端发送一个包含特定值(如字符串)的请求。服务器应使用相同的值进行响应,从而验证请求是否已成功接收和处理。如果响应与请求不匹配,则表示服务运行不正常,应进一步调查。要求 Dubbo 服务器正在运行,并且服务器和客户端之间具有网络连接。在客户端,必须配置 Dubbo 客户端以连接到服务器,客户端将向服务器发送请求,然后服务器应返回与请求相同的响应。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>测试验证是否可以调用服务以及响应是否正确,对于在尝试在生产环境中使用服务之前验证服务特别有用。 |
| echo 测试是验证 Dubbo 服务基本功能的一种简单有效的方法,在将服务部署到生产环境之前执行此测试非常重要,以确保服务按预期工作。</p> |
| <blockquote> |
| <p>参考用例 |
| <a href="https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-echo">https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-echo</a></p> |
| </blockquote> |
| <h2 id="使用方式">使用方式</h2> |
| <p>所有服务自动实现 <code>EchoService</code> 接口,只需将任意服务引用强制转型为 <code>EchoService</code>,即可使用。</p> |
| <h3 id="spring-配置">Spring 配置</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> id=<span style="color:#2aa198">&#34;memberService&#34;</span> interface=<span style="color:#2aa198">&#34;com.xxx.MemberService&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="代码示例">代码示例</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#586e75">// 远程服务引用</span> |
| </span></span><span style="display:flex;"><span>MemberService memberService <span style="color:#719e07">=</span> ctx.getBean(<span style="color:#2aa198">&#34;memberService&#34;</span>); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span>EchoService echoService <span style="color:#719e07">=</span> (EchoService) memberService; <span style="color:#586e75">// 强制转型为EchoService</span> |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 回声测试可用性</span> |
| </span></span><span style="display:flex;"><span>String status <span style="color:#719e07">=</span> echoService.$echo(<span style="color:#2aa198">&#34;OK&#34;</span>); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#719e07">assert</span>(status.equals(<span style="color:#2aa198">&#34;OK&#34;</span>)); |
| </span></span></code></pre></div></description></item><item><title>Overview: 调用信息记录</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/accesslog/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/accesslog/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>在 dubbo3 日志分为日志适配和访问日志,如果想记录每一次请求信息,可开启访问日志,类似于 apache 的访问日志。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>基于审计需要等类似 nginx accesslog 输出等。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="log4j-日志">log4j 日志</h3> |
| <p>将访问日志输出到当前应用的 log4j 日志</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:protocol</span> accesslog=<span style="color:#2aa198">&#34;true&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="指定文件">指定文件</h3> |
| <p>将访问日志输出到指定文件</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:protocol</span> accesslog=<span style="color:#2aa198">&#34;http://10.20.160.198/wiki/display/dubbo/foo/bar.log&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><blockquote> |
| <p>此日志量比较大,请注意磁盘容量。</p> |
| </blockquote></description></item><item><title>Overview: 实现泛化实现(服务端泛化)</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-service/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-service/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>泛接口实现方式主要用于服务器端没有 API 接口及模型类元的情况,参数及返回值中的所有 POJO 均用 Map 表示,通常用于框架集成,比如:实现一个通用的远程服务 Mock 框架,可通过实现 GenericService 接口处理所有服务请求。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>注册服务: 服务提供者在服务注册表中注册服务,例如 Zookeeper,服务注册表存储有关服务的信息,例如其接口、实现类和地址。</p> |
| <p>部署服务: 服务提供商将服务部署在服务器并使其对消费者可用。</p> |
| <p>调用服务: 使用者使用服务注册表生成的代理调用服务,代理将请求转发给服务提供商,服务提供商执行服务并将响应发送回消费者。</p> |
| <p>监视服务:提供者和使用者可以使用 Dubbo 框架监视服务,允许他们查看服务的执行情况,并在必要时进行调整。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <p>在 Java 代码中实现 <code>GenericService</code> 接口</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#719e07">package</span> com.foo; |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">MyGenericService</span> <span style="color:#268bd2">implements</span> GenericService { |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> Object <span style="color:#268bd2">$invoke</span>(String methodName, String<span style="color:#719e07">[]</span> parameterTypes, Object<span style="color:#719e07">[]</span> args) <span style="color:#268bd2">throws</span> GenericException { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">if</span> (<span style="color:#2aa198">&#34;sayHello&#34;</span>.equals(methodName)) { |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;Welcome &#34;</span> <span style="color:#719e07">+</span> args<span style="color:#719e07">[</span>0<span style="color:#719e07">]</span>; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><h3 id="通过-spring-暴露泛化实现">通过 Spring 暴露泛化实现</h3> |
| <p>在 Spring 配置申明服务的实现</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;bean</span> id=<span style="color:#2aa198">&#34;genericService&#34;</span> class=<span style="color:#2aa198">&#34;com.foo.MyGenericService&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;com.foo.BarService&#34;</span> ref=<span style="color:#2aa198">&#34;genericService&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="通过-api-方式暴露泛化实现">通过 API 方式暴露泛化实现</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>... |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 用org.apache.dubbo.rpc.service.GenericService可以替代所有接口实现 </span> |
| </span></span><span style="display:flex;"><span>GenericService xxxService <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> XxxGenericService(); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存 </span> |
| </span></span><span style="display:flex;"><span>ServiceConfig<span style="color:#719e07">&lt;</span>GenericService<span style="color:#719e07">&gt;</span> service <span style="color:#719e07">=</span> <span style="color:#719e07">new</span> ServiceConfig<span style="color:#719e07">&lt;</span>GenericService<span style="color:#719e07">&gt;</span>(); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 弱类型接口名 </span> |
| </span></span><span style="display:flex;"><span>service.setInterface(<span style="color:#2aa198">&#34;com.xxx.XxxService&#34;</span>); |
| </span></span><span style="display:flex;"><span>service.setVersion(<span style="color:#2aa198">&#34;1.0.0&#34;</span>); |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 指向一个通用服务实现 </span> |
| </span></span><span style="display:flex;"><span>service.setRef(xxxService); |
| </span></span><span style="display:flex;"><span> |
| </span></span><span style="display:flex;"><span><span style="color:#586e75">// 暴露及注册服务 </span> |
| </span></span><span style="display:flex;"><span>service.export(); |
| </span></span></code></pre></div></description></item><item><title>Overview: 异步执行</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-execute-on-provider/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-execute-on-provider/</guid><description> |
| <div class="pageinfo pageinfo-primary"> |
| <p>此文档已经不再维护。您当前查看的是快照版本。如果想要查看最新版本的文档,请参阅<a href="https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/">最新版本</a>。</p> |
| </div> |
| <p>Provider端异步执行将阻塞的业务从Dubbo内部线程池切换到业务自定义线程,避免Dubbo线程池的过度占用,有助于避免不同服务间的互相影响。异步执行无异于节省资源或提升RPC响应性能,因为如果业务执行需要阻塞,则始终还是要有线程来负责执行。</p> |
| <div class="alert alert-warning" role="alert"> |
| <h4 class="alert-heading">注意</h4> |
| <p>Provider 端异步执行和 Consumer 端异步调用是相互独立的,你可以任意正交组合两端配置</p> |
| <ul> |
| <li>Consumer同步 - Provider同步</li> |
| <li>Consumer异步 - Provider同步</li> |
| <li>Consumer同步 - Provider异步</li> |
| <li>Consumer异步 - Provider异步</li> |
| </ul> |
| </div> |
| <h2 id="定义-completablefuture-签名的接口">定义 CompletableFuture 签名的接口</h2> |
| <p>服务接口定义:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">AsyncService</span> { |
| </span></span><span style="display:flex;"><span> CompletableFuture<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">sayHello</span>(String name); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>服务实现:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">AsyncServiceImpl</span> <span style="color:#268bd2">implements</span> AsyncService { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">@Override</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> CompletableFuture<span style="color:#719e07">&lt;</span>String<span style="color:#719e07">&gt;</span> <span style="color:#268bd2">sayHello</span>(String name) { |
| </span></span><span style="display:flex;"><span> RpcContext savedContext <span style="color:#719e07">=</span> RpcContext.getContext(); |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 建议为supplyAsync提供自定义线程池,避免使用JDK公用线程池</span> |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> CompletableFuture.supplyAsync(() <span style="color:#719e07">-&gt;</span> { |
| </span></span><span style="display:flex;"><span> System.out.println(savedContext.getAttachment(<span style="color:#2aa198">&#34;consumer-key1&#34;</span>)); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> Thread.sleep(5000); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (InterruptedException e) { |
| </span></span><span style="display:flex;"><span> e.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#2aa198">&#34;async response from provider.&#34;</span>; |
| </span></span><span style="display:flex;"><span> }); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>通过 <code>return CompletableFuture.supplyAsync() </code>,业务执行已从 Dubbo 线程切换到业务线程,避免了对 Dubbo 线程池的阻塞。</p> |
| <h2 id="使用asynccontext">使用AsyncContext</h2> |
| <p>Dubbo 提供了一个类似 Servlet 3.0 的异步接口<code>AsyncContext</code>,在没有 CompletableFuture 签名接口的情况下,也可以实现 Provider 端的异步执行。</p> |
| <p>服务接口定义:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">interface</span> <span style="color:#268bd2">AsyncService</span> { |
| </span></span><span style="display:flex;"><span> String <span style="color:#268bd2">sayHello</span>(String name); |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div><p>服务暴露,和普通服务完全一致:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;bean</span> id=<span style="color:#2aa198">&#34;asyncService&#34;</span> class=<span style="color:#2aa198">&#34;org.apache.dubbo.samples.governance.impl.AsyncServiceImpl&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> interface=<span style="color:#2aa198">&#34;org.apache.dubbo.samples.governance.api.AsyncService&#34;</span> ref=<span style="color:#2aa198">&#34;asyncService&#34;</span><span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>服务实现:</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#268bd2">public</span> <span style="color:#268bd2">class</span> <span style="color:#268bd2">AsyncServiceImpl</span> <span style="color:#268bd2">implements</span> AsyncService { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">public</span> String <span style="color:#268bd2">sayHello</span>(String name) { |
| </span></span><span style="display:flex;"><span> <span style="color:#268bd2">final</span> AsyncContext asyncContext <span style="color:#719e07">=</span> RpcContext.startAsync(); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">new</span> Thread(() <span style="color:#719e07">-&gt;</span> { |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 如果要使用上下文,则必须要放在第一句执行</span> |
| </span></span><span style="display:flex;"><span> asyncContext.signalContextSwitch(); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">try</span> { |
| </span></span><span style="display:flex;"><span> Thread.sleep(500); |
| </span></span><span style="display:flex;"><span> } <span style="color:#719e07">catch</span> (InterruptedException e) { |
| </span></span><span style="display:flex;"><span> e.printStackTrace(); |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span> <span style="color:#586e75">// 写回响应</span> |
| </span></span><span style="display:flex;"><span> asyncContext.write(<span style="color:#2aa198">&#34;Hello &#34;</span> <span style="color:#719e07">+</span> name <span style="color:#719e07">+</span> <span style="color:#2aa198">&#34;, response from provider.&#34;</span>); |
| </span></span><span style="display:flex;"><span> }).start(); |
| </span></span><span style="display:flex;"><span> <span style="color:#719e07">return</span> <span style="color:#cb4b16">null</span>; |
| </span></span><span style="display:flex;"><span> } |
| </span></span><span style="display:flex;"><span>} |
| </span></span></code></pre></div></description></item><item><title>Overview: 本地调用</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-call/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-call/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>本地调用使用了 injvm 协议,是一个伪协议,它不开启端口,不发起远程调用,只在 JVM 内直接关联,但执行 Dubbo 的 Filter 链。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>当我们需要调用远程服务时,远程服务并没有开发完成,使用 injvm 协议在本地实现类似服务,调用此服务时可以调用我们本地的实现服务。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="定义-injvm-协议">定义 injvm 协议</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:protocol</span> name=<span style="color:#2aa198">&#34;injvm&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="设置默认协议">设置默认协议</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:provider</span> protocol=<span style="color:#2aa198">&#34;injvm&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="设置服务协议">设置服务协议</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> protocol=<span style="color:#2aa198">&#34;injvm&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="优先使用-injvm">优先使用 injvm</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:consumer</span> injvm=<span style="color:#2aa198">&#34;true&#34;</span> ...<span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:provider</span> injvm=<span style="color:#2aa198">&#34;true&#34;</span> ...<span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p><strong>或</strong></p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> injvm=<span style="color:#2aa198">&#34;true&#34;</span> ...<span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> injvm=<span style="color:#2aa198">&#34;true&#34;</span> ...<span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div> |
| <div class="alert alert-warning" role="alert"> |
| <h4 class="alert-heading">注意</h4> |
| <strong>Dubbo 从 <code>2.2.0</code> 每个服务默认都会在本地暴露,无需进行任何配置即可进行本地引用,如果不希望服务进行远程暴露,只需要在 provider 将 protocol 设置成 injvm 即可。</strong> |
| </div> |
| <h3 id="自动暴露">自动暴露</h3> |
| <p>从 <code>2.2.0</code> 开始,每个服务默认都会在本地暴露。在引用服务的时候,默认优先引用本地服务。如果希望引用远程服务可以使用一下配置强制引用远程服务。</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:reference</span> ... scope=<span style="color:#2aa198">&#34;remote&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="动态配置调用行为">动态配置调用行为</h3> |
| <p>从<code>3.2</code>开始,Dubbo提供api可以让用户在使用中动态地去配置单一次调用时为本地调用或者远程调用,当没配置的时候将默认优先引用本地服务</p> |
| <p><strong>配置单一次调用为远程调用</strong></p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>RpcContext.getServiceContext().setLocalInvoke(<span style="color:#cb4b16">false</span>); |
| </span></span></code></pre></div><p><strong>配置单一次调用为本地调用</strong></p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>RpcContext.getServiceContext().setLocalInvoker(<span style="color:#cb4b16">true</span>); |
| </span></span></code></pre></div></description></item><item><title>Overview: 延迟暴露</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/delay-publish/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/delay-publish/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>如果你的服务需要预热时间,比如初始化缓存,等待相关资源就位等,可以使用 delay 进行延迟暴露。我们在 Dubbo 2.6.5 版本中对服务延迟暴露逻辑进行了细微的调整,将需要延迟暴露(delay &gt; 0)服务的倒计时动作推迟到了 Spring 初始化完成后进行。你在使用 Dubbo 的过程中,并不会感知到此变化,因此请放心使用。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>当服务完全配置并准备好向外界暴露时才会触发服务的暴露,保证服务在准备就绪时暴露,提高了服务系统可靠性。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="dubbo-265-之前版本">Dubbo 2.6.5 之前版本</h3> |
| <p>延迟到 Spring 初始化完成后,再暴露服务<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> delay=<span style="color:#2aa198">&#34;-1&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p>延迟 5 秒暴露服务</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> delay=<span style="color:#2aa198">&#34;5000&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="dubbo-265-及以后版本">Dubbo 2.6.5 及以后版本</h3> |
| <p>所有服务都将在 Spring 初始化完成后进行暴露,如果你不需要延迟暴露服务,无需配置 delay。</p> |
| <p>延迟 5 秒暴露服务</p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:service</span> delay=<span style="color:#2aa198">&#34;5000&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><h3 id="spring-2x-初始化死锁问题">Spring 2.x 初始化死锁问题</h3> |
| <h3 id="触发条件">触发条件</h3> |
| <p>在 Spring 解析到 <code>&lt;dubbo:service /&gt;</code> 时,就已经向外暴露了服务,而 Spring 还在接着初始化其它 Bean。如果这时有请求进来,并且服务的实现类里有调用 <code>applicationContext.getBean()</code> 的用法。</p> |
| <ol> |
| <li> |
| <p>请求线程的 applicationContext.getBean() 调用,先同步 singletonObjects 判断 Bean 是否存在,不存在就同步 beanDefinitionMap 进行初始化,并再次同步 singletonObjects 写入 Bean 实例缓存。</p> |
| <p><img src="https://dubbo.apache.org/imgs/user/lock-get-bean.jpg" alt="deadlock"></p> |
| </li> |
| <li> |
| <p>而 Spring 初始化线程,因不需要判断 Bean 的存在,直接同步 beanDefinitionMap 进行初始化,并同步 singletonObjects 写入 Bean 实例缓存。</p> |
| <p><img src="https://dubbo.apache.org/imgs/user/lock-init-context.jpg" alt="/user-guide/images/lock-init-context.jpg"></p> |
| <p>这样就导致 getBean 线程,先锁 singletonObjects,再锁 beanDefinitionMap,再次锁 singletonObjects。<br> |
| 而 Spring 初始化线程,先锁 beanDefinitionMap,再锁 singletonObjects。反向锁导致线程死锁,不能提供服务,启动不了。</p> |
| </li> |
| </ol> |
| <h3 id="规避办法">规避办法</h3> |
| <ol> |
| <li>强烈建议不要在服务的实现类中有 applicationContext.getBean() 的调用,全部采用 IoC 注入的方式使用 Spring的Bean。</li> |
| <li>如果实在要调 getBean(),可以将 Dubbo 的配置放在 Spring 的最后加载。</li> |
| <li>如果不想依赖配置顺序,可以使用 <code>&lt;dubbo:provider delay=”-1” /&gt;</code>,使 Dubbo 在 Spring 容器初始化完后,再暴露服务。</li> |
| <li>如果大量使用 getBean(),相当于已经把 Spring 退化为工厂模式在用,可以将 Dubbo 的服务隔离单独的 Spring 容器。</li> |
| </ol> |
| <div class="footnotes" role="doc-endnotes"> |
| <hr> |
| <ol> |
| <li id="fn:1"> |
| <p>基于 Spring 的 ContextRefreshedEvent 事件触发暴露&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p> |
| </li> |
| </ol> |
| </div></description></item><item><title>Overview: 只注册</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/registry-only/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/registry-only/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>如果有两个镜像环境,两个注册中心,有一个服务只在其中一个注册中心有部署,另一个注册中心还没来得及部署,而两个注册中心的其它应用都需要依赖此服务。这个时候,可以让服务提供者方只注册服务到另一注册中心,而不从另一注册中心订阅服务。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>服务互不依赖的情况或者当服务提供者端发生变化时,服务提供者不需要接收通知时。</p> |
| <p>该机制通常用于提供程序相对静态且不太可能更改的场景或者提供程序和使用者互不依赖的场景。</p> |
| <h2 id="使用方式">使用方式</h2> |
| <h3 id="禁用订阅配置">禁用订阅配置</h3> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;hzRegistry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.153.10:9090&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;qdRegistry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.141.150:9090&#34;</span> subscribe=<span style="color:#2aa198">&#34;false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div><p><strong>或者</strong></p> |
| <div class="highlight"><pre tabindex="0" style="color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;hzRegistry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.153.10:9090&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span><span style="display:flex;"><span><span style="color:#268bd2">&lt;dubbo:registry</span> id=<span style="color:#2aa198">&#34;qdRegistry&#34;</span> address=<span style="color:#2aa198">&#34;10.20.141.150:9090?subscribe=false&#34;</span> <span style="color:#268bd2">/&gt;</span> |
| </span></span></code></pre></div></description></item><item><title>Overview: 分布式事务支持</title><link>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/distributed-transaction/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/distributed-transaction/</guid><description> |
| <h2 id="特性说明">特性说明</h2> |
| <p>分布式事务基于 JTA/XA 规范实现。</p> |
| <h2 id="使用场景">使用场景</h2> |
| <p>支付交易:支付交易中的分布式交易支持,如在线支付、银行转账等,确保在完成多个服务调用后支付成功。</p> |
| <p>库存管理:支持库存管理中的分布式事务场景,确保用户购买产品时,库存得到相应更新成功和交易成功。</p> |
| <p>订单处理:支持订单处理中的分布式事务场景,确保当用户下订单时,在完成多个服务调用后成功下订单。</p> |
| <p>数据同步:支持数据同步中的分布式事务场景,确保在完成多个服务调用后,不同服务之间的数据同步成功。</p> |
| <h2 id="实现方式">实现方式</h2> |
| <p><strong>两阶段提交</strong></p> |
| <p><img src="https://dubbo.apache.org/imgs/user/jta-xa.jpg" alt="/user-guide/images/jta-xa.jpg"></p> |
| <blockquote> |
| <p>在 Dubbo 中,可以采用 <a href="https://dubbo.apache.org/zh-cn/blog/2019/01/17/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8seata%E4%BF%9D%E8%AF%81dubbo%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%97%B4%E7%9A%84%E4%B8%80%E8%87%B4%E6%80%A7/">seata</a> 来完成对分布式事务的支持。</p> |
| </blockquote></description></item></channel></rss> |