<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> I have searched the issues of this repository and believe that this is not a duplicate.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked="">  I have checked the FAQ of this repository and believe that this is not a duplicate.</li>
</ul>
<p dir="auto">Environment<br>
Dubbo version: 2.7.2<br>
Operating System version: Mac OS<br>
Java version: 1.8<br>
Steps to reproduce this issue</p>
<p dir="auto">Infos:</p>
<table role="table">
<thead>
<tr>
<th>IP</th>
<th>SIDE</th>
<th>ENV</th>
<th>STATIC TAG</th>
<th>DYNAMIC TAG</th>
</tr>
</thead>
<tbody>
<tr>
<td>192.168.1.5</td>
<td>Consumer</td>
<td>DEV</td>
<td>DEV</td>
<td>hello</td>
</tr>
<tr>
<td>192.168.1.6</td>
<td>Provider</td>
<td>QA</td>
<td>QA</td>
<td></td>
</tr>
<tr>
<td>192.168.1.7</td>
<td>Provider</td>
<td>STABLE</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p dir="auto">When I config TagRouter like this (in Dubbo admin):</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="---
force: false
runtime: true
enabled: true
priority: 1
key: hello-service
tags:
  - name: hello
    addresses: [&quot;192.168.1.8&quot;,&quot;192.168.1.9&quot;]
..."><pre class="notranslate"><code class="notranslate">---
force: false
runtime: true
enabled: true
priority: 1
key: hello-service
tags:
  - name: hello
    addresses: ["192.168.1.8","192.168.1.9"]
...
</code></pre></div>
<p dir="auto">when without match dynamic tag and static tag<br>
Hope Result:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="192.168.1.5(DEV) =&gt;  192.168.1.7(STABLE)"><pre class="notranslate"><code class="notranslate">192.168.1.5(DEV) =&gt;  192.168.1.7(STABLE)
</code></pre></div>
<p dir="auto">Actual Result:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="192.168.1.5(DEV) =&gt; [NO PROVIDER]"><pre class="notranslate"><code class="notranslate">192.168.1.5(DEV) =&gt; [NO PROVIDER]
</code></pre></div>
<p dir="auto">原因:</p>
<p dir="auto">消费方初始化refer时，在ReferenceConfig中会将consumer的配置参数放入一个map(具体参考ReferenceConfig类中第303行<code class="notranslate">appendParameters(map, consumer)</code>)，然后在创建代理的时候会合并消费方和提供方的配置参数(参考ReferenceConfig类中第371行<code class="notranslate">urls.add(ClusterUtils.mergeUrl(url, map));</code>)，之后在ClusterUtils中尽管会保留提供方的配置，参数，但是在消费方设置了dubbo.tag参数，而提供方未设置dubbo.tag的情况下，导致加了消费方默认的dubbo.tag;</p>
<p dir="auto">然后在进行标签路由时，由于设置了动态标签路由，但是又没有匹配的提供方实例，最后会获取动态标签中不存在，且动态标签为空的实例（参考TagRouter类中第125~127行，如下）</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content=" // FAILOVER: return all Providers without any tags.
            else {
                List&lt;Invoker&lt;T&gt;&gt; tmp = filterInvoker(invokers, invoker -&gt; addressNotMatches(invoker.getUrl(),
                        tagRouterRuleCopy.getAddresses()));
                return filterInvoker(tmp, invoker -&gt; StringUtils.isEmpty(invoker.getUrl().getParameter(Constants.TAG_KEY)));
            }"><pre class="notranslate"><code class="notranslate"> // FAILOVER: return all Providers without any tags.
            else {
                List&lt;Invoker&lt;T&gt;&gt; tmp = filterInvoker(invokers, invoker -&gt; addressNotMatches(invoker.getUrl(),
                        tagRouterRuleCopy.getAddresses()));
                return filterInvoker(tmp, invoker -&gt; StringUtils.isEmpty(invoker.getUrl().getParameter(Constants.TAG_KEY)));
            }
</code></pre></div>
<p dir="auto">但是由于之前在refer的时候合并了参数，这边尽管Stable下的实例192.168.1.7的ProviderConfig URL中不带Dubbo TAG，这里还是会获取到消费方的默认标签DEV。</p>
<p dir="auto">解决:<br>
修改判断条件：</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="return filterInvoker(tmp, invoker -&gt; StringUtils.isEmpty(url.getParameter(Constants.TAG_KEY)? StringUtils.isEmpty(invoker.getUrl().getParameter(Constants.TAG_KEY)) : invoker.getUrl().getParameter(Constants.TAG_KEY).equals(url.getParameter(Constants.TAG_KEY)) );"><pre class="notranslate"><code class="notranslate">return filterInvoker(tmp, invoker -&gt; StringUtils.isEmpty(url.getParameter(Constants.TAG_KEY)? StringUtils.isEmpty(invoker.getUrl().getParameter(Constants.TAG_KEY)) : invoker.getUrl().getParameter(Constants.TAG_KEY).equals(url.getParameter(Constants.TAG_KEY)) );
</code></pre></div>
<p dir="auto">另外，发现标签路由的常量跟官方文档中不一致，实际上是:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="org.apache.dubbo.rpc.cluster.TAG_KEY
org.apache.dubbo.rpc.FORCE_USE_TAG"><pre class="notranslate"><code class="notranslate">org.apache.dubbo.rpc.cluster.TAG_KEY
org.apache.dubbo.rpc.FORCE_USE_TAG
</code></pre></div>
<p dir="auto">能够统一修正为:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="org.apache.dubbo.rpc.cluster.TAG_KEY
org.apache.dubbo.rpc.cluster.FORCE_KEY"><pre class="notranslate"><code class="notranslate">org.apache.dubbo.rpc.cluster.TAG_KEY
org.apache.dubbo.rpc.cluster.FORCE_KEY
</code></pre></div>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I have searched the <a href="https://github.com/apache/dubbo/issues">issues</a> of this repository and believe that this is not a duplicate.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I have checked the <a href="https://github.com/apache/dubbo/blob/master/FAQ.md">FAQ</a> of this repository and believe that this is not a duplicate.</li>
</ul>
<h3 dir="auto">Environment</h3>
<ul dir="auto">
<li>Dubbo version: 2.7.6</li>
<li>Operating System version: mac  10.15</li>
<li>Java version: 1.8.0.231</li>
</ul>
<h3 dir="auto">Steps to reproduce this issue</h3>
<ol dir="auto">
<li>spring boot应用中自定义ExportListener SPI扩展，记为X</li>
<li>在dubbo:service中设置listener为XXX</li>
<li>启动spring boot应用</li>
</ol>
<p dir="auto">Pls. provide [GitHub address] to reproduce this issue.</p>
<h3 dir="auto">Expected Result</h3>
<p dir="auto">What do you expected from the above steps？<br>
应用正常启动</p>
<h3 dir="auto">Actual Result</h3>
<p dir="auto">What actually happens?<br>
异常堆栈如下，我跟踪了一下代码执行，问题出在org.apache.dubbo.config.utils.ConfigValidationUtils#validateServiceConfig方法中，先校验了一次ExporterListener.class的扩展点，而后在validateAbstractInterfaceConfig(config)中，针对同一个ServiceConfig校验了一次 InvokerListener.class的扩展。这个地方我感觉有问题，因为我是针对dubbo:service设置的ExporterListener，而InvokerListener因为是针对dubbo:reference的，为何针对dubbo:service也去校验InvokerListener扩展呢？</p>
<p dir="auto">java.lang.IllegalStateException: No such extension XXX for listener/org.apache.dubbo.rpc.InvokerListener<br>
at org.apache.dubbo.config.utils.ConfigValidationUtils.checkMultiExtension(ConfigValidationUtils.java:531)<br>
at org.apache.dubbo.config.utils.ConfigValidationUtils.validateAbstractInterfaceConfig(ConfigValidationUtils.java:299)<br>
at org.apache.dubbo.config.utils.ConfigValidationUtils.validateServiceConfig(ConfigValidationUtils.java:316)<br>
at org.apache.dubbo.config.ServiceConfig.checkAndUpdateSubConfigs(ServiceConfig.java:283)<br>
at org.apache.dubbo.config.ServiceConfig.export(ServiceConfig.java:193)<br>
at org.apache.dubbo.config.bootstrap.DubboBootstrap.lambda$exportServices$15(DubboBootstrap.java:917)<br>
at java.util.HashMap$Values.forEach(HashMap.java:981)<br>
at org.apache.dubbo.config.bootstrap.DubboBootstrap.exportServices(DubboBootstrap.java:905)<br>
at org.apache.dubbo.config.bootstrap.DubboBootstrap.start(DubboBootstrap.java:745)<br>
at org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener.onContextRefreshedEvent(DubboBootstrapApplicationListener.java:59)<br>
at org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener.onApplicationContextEvent(DubboBootstrapApplicationListener.java:52)<br>
at org.apache.dubbo.config.spring.context.OneTimeExecutionApplicationContextEventListener.onApplicationEvent(OneTimeExecutionApplicationContextEventListener.java:40)<br>
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)<br>
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)<br>
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)<br>
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:403)<br>
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:360)<br>
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:897)<br>
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162)<br>
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553)<br>
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)<br>
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)<br>
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)<br>
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)<br>
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)<br>
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)<br>
at cn.edu.bupt.Starter.main(Starter.java:18)</p>
<p dir="auto">If there is an exception, please attach the exception trace:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Just put your stack trace here!"><pre class="notranslate"><code class="notranslate">Just put your stack trace here!
</code></pre></div>