You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by cr...@apache.org on 2021/10/02 00:24:09 UTC

[dubbo] branch 3.0 updated: Verify remote reference for remote url (#8973)

This is an automated email from the ASF dual-hosted git repository.

crazyhzm pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.0 by this push:
     new 403a989  Verify remote reference for remote url (#8973)
403a989 is described below

commit 403a98943be006c4c9366bd61e1dd1789ee8ff84
Author: huazhongming <cr...@gmail.com>
AuthorDate: Sat Oct 2 08:23:52 2021 +0800

    Verify remote reference for remote url (#8973)
    
    * Verify remote reference for remote url
    
    * destroy DubboBootstrap
    
    * fix typo
---
 .../dubbo/rpc/cluster/support/ClusterUtils.java    |  16 +-
 .../filter/DefaultFilterChainBuilderTest.java      |  33 ++++
 .../rpc/cluster/support/ClusterUtilsTest.java      | 189 ++++++++++-----------
 .../support/TagProviderURLMergeProcessor.java      |  29 ++--
 .../DefaultProviderURLMergeProcessorTest.java}     | 123 +++++++-------
 ...che.dubbo.rpc.cluster.ProviderURLMergeProcessor |   1 +
 .../org/apache/dubbo/config/ReferenceConfig.java   |   1 -
 .../org/apache/dubbo/config/ServiceConfig.java     |   1 -
 .../org/apache/dubbo/config/MethodConfigTest.java  |  53 +++---
 .../apache/dubbo/config/ReferenceConfigTest.java   |  44 +++++
 .../dubbo/rpc/protocol/CountInvokerListener.java   |   1 +
 .../rpc/protocol/ProtocolListenerWrapperTest.java  |  43 ++++-
 12 files changed, 325 insertions(+), 209 deletions(-)

diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
index 845020e..eca3993 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
@@ -42,28 +42,28 @@ public class ClusterUtils implements ScopeModelAware {
     public URL mergeUrl(URL remoteUrl, Map<String, String> localMap) {
 
         String ump = localMap.get(URL_MERGE_PROCESSOR_KEY);
-        ProviderURLMergeProcessor providerURLMergeProcessor;
+        ProviderURLMergeProcessor providerUrlMergeProcessor;
 
         if (StringUtils.isNotEmpty(ump)) {
-            providerURLMergeProcessor = applicationModel.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension(ump);
+            providerUrlMergeProcessor = applicationModel.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension(ump);
         } else {
-            providerURLMergeProcessor = applicationModel.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension("default");
+            providerUrlMergeProcessor = applicationModel.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension("default");
         }
 
-        return providerURLMergeProcessor.mergeUrl(remoteUrl, localMap);
+        return providerUrlMergeProcessor.mergeUrl(remoteUrl, localMap);
     }
 
     public Map<String, String> mergeLocalParams(Map<String, String> localMap) {
         String ump = localMap.get(URL_MERGE_PROCESSOR_KEY);
-        ProviderURLMergeProcessor providerURLMergeProcessor;
+        ProviderURLMergeProcessor providerUrlMergeProcessor;
 
         if (StringUtils.isNotEmpty(ump)) {
-            providerURLMergeProcessor = applicationModel.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension(ump);
+            providerUrlMergeProcessor = applicationModel.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension(ump);
         } else {
-            providerURLMergeProcessor = applicationModel.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension("default");
+            providerUrlMergeProcessor = applicationModel.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension("default");
         }
 
-        return providerURLMergeProcessor.mergeLocalParams(localMap);
+        return providerUrlMergeProcessor.mergeLocalParams(localMap);
 
     }
 
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DefaultFilterChainBuilderTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DefaultFilterChainBuilderTest.java
index 655f6d9..1bf0b93 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DefaultFilterChainBuilderTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DefaultFilterChainBuilderTest.java
@@ -63,4 +63,37 @@ public class DefaultFilterChainBuilderTest {
         Assertions.assertTrue(((FilterChainBuilder.FilterChainNode<?, ?, ?>) invokerAfterBuild).filter instanceof LogFilter);
 
     }
+
+    @Test
+    public void testBuildInvokerChainForRemoteReference() {
+        DefaultFilterChainBuilder defaultFilterChainBuilder = new DefaultFilterChainBuilder();
+
+        // verify that no filter is built by default
+        URL urlWithoutFilter = URL.valueOf("dubbo://127.0.0.1:20880/DemoService")
+            .addParameter(INTERFACE_KEY, DemoService.class.getName());
+        AbstractInvoker<DemoService> invokerWithoutFilter = new AbstractInvoker<DemoService>(DemoService.class, urlWithoutFilter) {
+            @Override
+            protected Result doInvoke(Invocation invocation) throws Throwable {
+                return null;
+            }
+        };
+
+        Invoker<?> invokerAfterBuild = defaultFilterChainBuilder.buildInvokerChain(invokerWithoutFilter, REFERENCE_FILTER_KEY, CONSUMER);
+        Assertions.assertTrue(invokerAfterBuild instanceof AbstractInvoker);
+
+        // verify that if LogFilter is configured, LogFilter should exist in the filter chain
+        URL urlWithFilter = URL.valueOf("dubbo://127.0.0.1:20880/DemoService")
+            .addParameter(INTERFACE_KEY, DemoService.class.getName())
+            .addParameter(REFERENCE_FILTER_KEY, "log");
+        AbstractInvoker<DemoService> invokerWithFilter = new AbstractInvoker<DemoService>(DemoService.class, urlWithFilter) {
+            @Override
+            protected Result doInvoke(Invocation invocation) throws Throwable {
+                return null;
+            }
+        };
+        invokerAfterBuild = defaultFilterChainBuilder.buildInvokerChain(invokerWithFilter, REFERENCE_FILTER_KEY, CONSUMER);
+        Assertions.assertTrue(invokerAfterBuild instanceof FilterChainBuilder.FilterChainNode);
+        Assertions.assertTrue(((FilterChainBuilder.FilterChainNode<?, ?, ?>) invokerAfterBuild).filter instanceof LogFilter);
+
+    }
 }
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
index 7cf23b3..c32707d 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
@@ -23,28 +23,26 @@ import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import java.util.Map;
+
 import static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
 import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
 import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.URL_MERGE_PROCESSOR_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
 
+
 public class ClusterUtilsTest {
 
     private ClusterUtils clusterUtils;
@@ -59,37 +57,38 @@ public class ClusterUtilsTest {
     public void testMergeUrl() throws Exception {
         URL providerURL = URL.valueOf("dubbo://localhost:55555");
         providerURL = providerURL.setPath("path")
-                .setUsername("username")
-                .setPassword("password");
+            .setUsername("username")
+            .setPassword("password");
 
         providerURL = URLBuilder.from(providerURL)
-                .addParameter(GROUP_KEY, "dubbo")
-                .addParameter(VERSION_KEY, "1.2.3")
-                .addParameter(DUBBO_VERSION_KEY, "2.3.7")
-                .addParameter(THREADPOOL_KEY, "fixed")
-                .addParameter(THREADS_KEY, Integer.MAX_VALUE)
-                .addParameter(THREAD_NAME_KEY, "test")
-                .addParameter(CORE_THREADS_KEY, Integer.MAX_VALUE)
-                .addParameter(QUEUES_KEY, Integer.MAX_VALUE)
-                .addParameter(ALIVE_KEY, Integer.MAX_VALUE)
-                .addParameter(DEFAULT_KEY_PREFIX + THREADS_KEY, Integer.MAX_VALUE)
-                .addParameter(DEFAULT_KEY_PREFIX + THREADPOOL_KEY, "fixed")
-                .addParameter(DEFAULT_KEY_PREFIX + CORE_THREADS_KEY, Integer.MAX_VALUE)
-                .addParameter(DEFAULT_KEY_PREFIX + QUEUES_KEY, Integer.MAX_VALUE)
-                .addParameter(DEFAULT_KEY_PREFIX + ALIVE_KEY, Integer.MAX_VALUE)
-                .addParameter(DEFAULT_KEY_PREFIX + THREAD_NAME_KEY, "test")
-                .addParameter(APPLICATION_KEY, "provider")
-                .addParameter(REFERENCE_FILTER_KEY, "filter1,filter2")
-                .addParameter(TAG_KEY,"TTT")
-                .build();
-
+            .addParameter(GROUP_KEY, "dubbo")
+            .addParameter(VERSION_KEY, "1.2.3")
+            .addParameter(DUBBO_VERSION_KEY, "2.3.7")
+            .addParameter(THREADPOOL_KEY, "fixed")
+            .addParameter(THREADS_KEY, Integer.MAX_VALUE)
+            .addParameter(THREAD_NAME_KEY, "test")
+            .addParameter(CORE_THREADS_KEY, Integer.MAX_VALUE)
+            .addParameter(QUEUES_KEY, Integer.MAX_VALUE)
+            .addParameter(ALIVE_KEY, Integer.MAX_VALUE)
+            .addParameter(DEFAULT_KEY_PREFIX + THREADS_KEY, Integer.MAX_VALUE)
+            .addParameter(DEFAULT_KEY_PREFIX + THREADPOOL_KEY, "fixed")
+            .addParameter(DEFAULT_KEY_PREFIX + CORE_THREADS_KEY, Integer.MAX_VALUE)
+            .addParameter(DEFAULT_KEY_PREFIX + QUEUES_KEY, Integer.MAX_VALUE)
+            .addParameter(DEFAULT_KEY_PREFIX + ALIVE_KEY, Integer.MAX_VALUE)
+            .addParameter(DEFAULT_KEY_PREFIX + THREAD_NAME_KEY, "test")
+            .addParameter(APPLICATION_KEY, "provider")
+            .addParameter(REFERENCE_FILTER_KEY, "filter1,filter2")
+            .addParameter(TAG_KEY, "TTT")
+            .build();
+
+        // Verify default ProviderURLMergeProcessor
         URL consumerURL = new URLBuilder(DUBBO_PROTOCOL, "localhost", 55555)
-                .addParameter(PID_KEY, "1234")
-                .addParameter(THREADPOOL_KEY, "foo")
-                .addParameter(APPLICATION_KEY, "consumer")
-                .addParameter(REFERENCE_FILTER_KEY, "filter3")
-                .addParameter(TAG_KEY,"UUU")
-                .build();
+            .addParameter(PID_KEY, "1234")
+            .addParameter(THREADPOOL_KEY, "foo")
+            .addParameter(APPLICATION_KEY, "consumer")
+            .addParameter(REFERENCE_FILTER_KEY, "filter3")
+            .addParameter(TAG_KEY, "UUU")
+            .build();
 
         URL url = clusterUtils.mergeUrl(providerURL, consumerURL.getParameters());
 
@@ -110,71 +109,67 @@ public class ClusterUtilsTest {
         Assertions.assertFalse(url.hasParameter(THREAD_NAME_KEY));
         Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + THREAD_NAME_KEY));
 
-        Assertions.assertEquals(url.getPath(), "path");
-        Assertions.assertEquals(url.getUsername(), "username");
-        Assertions.assertEquals(url.getPassword(), "password");
-        Assertions.assertEquals(url.getParameter(PID_KEY), "1234");
-        Assertions.assertEquals(url.getParameter(THREADPOOL_KEY), "foo");
-        Assertions.assertEquals(url.getApplication(), "consumer");
-        Assertions.assertEquals(url.getRemoteApplication(), "provider");
-        Assertions.assertEquals(url.getParameter(REFERENCE_FILTER_KEY), "filter1,filter2,filter3");
-
-        Assertions.assertEquals(url.getParameter(TAG_KEY), "TTT");
+        Assertions.assertEquals("path", url.getPath());
+        Assertions.assertEquals("username", url.getUsername());
+        Assertions.assertEquals("password", url.getPassword());
+        Assertions.assertEquals("1234", url.getParameter(PID_KEY));
+        Assertions.assertEquals("foo", url.getParameter(THREADPOOL_KEY));
+        Assertions.assertEquals("consumer", url.getApplication());
+        Assertions.assertEquals("provider", url.getRemoteApplication());
+        Assertions.assertEquals("filter1,filter2,filter3", url.getParameter(REFERENCE_FILTER_KEY));
+
+        Assertions.assertEquals("TTT", url.getParameter(TAG_KEY));
+
+        // Verify custom ProviderURLMergeProcessor
+        URL consumerUrlForTag = new URLBuilder(DUBBO_PROTOCOL, "localhost", 55555)
+            .addParameter(PID_KEY, "1234")
+            .addParameter(THREADPOOL_KEY, "foo")
+            .addParameter(APPLICATION_KEY, "consumer")
+            .addParameter(REFERENCE_FILTER_KEY, "filter3")
+            .addParameter(TAG_KEY, "UUU")
+            .addParameter(URL_MERGE_PROCESSOR_KEY, "tag")
+            .build();
+
+        URL urlForTag = clusterUtils.mergeUrl(providerURL, consumerUrlForTag.getParameters());
+        Assertions.assertEquals("UUU", urlForTag.getParameter(TAG_KEY));
     }
 
     @Test
-    public void testUseProviderParams() {
-        // present in both local and remote, but uses remote value.
-        URL localURL = URL.valueOf("dubbo://localhost:20880/DemoService?version=local&group=local&dubbo=local&release=local" +
-                "&methods=local&tag=local&timestamp=local");
-        URL remoteURL = URL.valueOf("dubbo://localhost:20880/DemoService?version=remote&group=remote&dubbo=remote&release=remote" +
-                "&methods=remote&tag=remote&timestamp=remote");
-        URL mergedUrl = clusterUtils.mergeUrl(remoteURL, localURL.getParameters());
-
-        Assertions.assertEquals(remoteURL.getVersion(), mergedUrl.getVersion());
-        Assertions.assertEquals(remoteURL.getGroup(), mergedUrl.getGroup());
-        Assertions.assertEquals(remoteURL.getParameter(DUBBO_VERSION_KEY), mergedUrl.getParameter(DUBBO_VERSION_KEY));
-        Assertions.assertEquals(remoteURL.getParameter(RELEASE_KEY), mergedUrl.getParameter(RELEASE_KEY));
-        Assertions.assertEquals(remoteURL.getParameter(METHODS_KEY), mergedUrl.getParameter(METHODS_KEY));
-        Assertions.assertEquals(remoteURL.getParameter(TIMESTAMP_KEY), mergedUrl.getParameter(TIMESTAMP_KEY));
-        Assertions.assertEquals(remoteURL.getParameter(TAG_KEY), mergedUrl.getParameter(TAG_KEY));
-
-        // present in local url but not in remote url, parameters of remote url is empty
-        localURL = URL.valueOf("dubbo://localhost:20880/DemoService?version=local&group=local&dubbo=local&release=local" +
-                "&methods=local&tag=local&timestamp=local");
-        remoteURL = URL.valueOf("dubbo://localhost:20880/DemoService");
-        mergedUrl = clusterUtils.mergeUrl(remoteURL, localURL.getParameters());
-
-        Assertions.assertEquals(mergedUrl.getVersion(),localURL.getVersion());
-        Assertions.assertEquals(mergedUrl.getGroup(),localURL.getGroup());
-        Assertions.assertNull(mergedUrl.getParameter(DUBBO_VERSION_KEY));
-        Assertions.assertNull(mergedUrl.getParameter(RELEASE_KEY));
-        Assertions.assertNull(mergedUrl.getParameter(METHODS_KEY));
-        Assertions.assertNull(mergedUrl.getParameter(TIMESTAMP_KEY));
-        Assertions.assertNull(mergedUrl.getParameter(TAG_KEY));
-
-        // present in local url but not in remote url
-        localURL = URL.valueOf("dubbo://localhost:20880/DemoService?version=local&group=local&dubbo=local&release=local" +
-                "&methods=local&tag=local&timestamp=local");
-        remoteURL = URL.valueOf("dubbo://localhost:20880/DemoService?key=value");
-        mergedUrl = clusterUtils.mergeUrl(remoteURL, localURL.getParameters());
-
-        Assertions.assertEquals(mergedUrl.getVersion(),localURL.getVersion());
-        Assertions.assertEquals(mergedUrl.getGroup(),localURL.getGroup());
-        Assertions.assertNull(mergedUrl.getParameter(DUBBO_VERSION_KEY));
-        Assertions.assertNull(mergedUrl.getParameter(RELEASE_KEY));
-        Assertions.assertNull(mergedUrl.getParameter(METHODS_KEY));
-        Assertions.assertNull(mergedUrl.getParameter(TIMESTAMP_KEY));
-        Assertions.assertNull(mergedUrl.getParameter(TAG_KEY));
-
-        // present in both local and remote, uses local url params
-        localURL = URL.valueOf("dubbo://localhost:20880/DemoService?loadbalance=local&timeout=1000&cluster=local");
-        remoteURL = URL.valueOf("dubbo://localhost:20880/DemoService?loadbalance=remote&timeout=2000&cluster=remote");
-        mergedUrl = clusterUtils.mergeUrl(remoteURL, localURL.getParameters());
-
-        Assertions.assertEquals(localURL.getParameter(CLUSTER_KEY), mergedUrl.getParameter(CLUSTER_KEY));
-        Assertions.assertEquals(localURL.getParameter(TIMEOUT_KEY), mergedUrl.getParameter(TIMEOUT_KEY));
-        Assertions.assertEquals(localURL.getParameter(LOADBALANCE_KEY), mergedUrl.getParameter(LOADBALANCE_KEY));
-    }
+    public void testMergeLocalParams() {
 
+        // Verify default ProviderURLMergeProcessor
+        URL consumerURL = new URLBuilder(DUBBO_PROTOCOL, "localhost", 55555)
+            .addParameter(PID_KEY, "1234")
+            .addParameter(THREADPOOL_KEY, "foo")
+            .addParameter(APPLICATION_KEY, "consumer")
+            .addParameter(REFERENCE_FILTER_KEY, "filter3")
+            .addParameter(TAG_KEY, "UUU")
+            .build();
+
+        Map<String,String> params = clusterUtils.mergeLocalParams(consumerURL.getParameters());
+
+        Assertions.assertEquals("1234", params.get(PID_KEY));
+        Assertions.assertEquals("foo", params.get(THREADPOOL_KEY));
+        Assertions.assertEquals("consumer", params.get(APPLICATION_KEY));
+        Assertions.assertEquals("filter3", params.get(REFERENCE_FILTER_KEY));
+        Assertions.assertEquals("UUU", params.get(TAG_KEY));
+
+        // Verify custom ProviderURLMergeProcessor
+        URL consumerUrlForTag = new URLBuilder(DUBBO_PROTOCOL, "localhost", 55555)
+            .addParameter(PID_KEY, "1234")
+            .addParameter(THREADPOOL_KEY, "foo")
+            .addParameter(APPLICATION_KEY, "consumer")
+            .addParameter(REFERENCE_FILTER_KEY, "filter3")
+            .addParameter(TAG_KEY, "UUU")
+            .addParameter(URL_MERGE_PROCESSOR_KEY, "tag")
+            .build();
+
+        Map<String,String> paramsForTag = clusterUtils.mergeLocalParams(consumerUrlForTag.getParameters());
+
+        Assertions.assertEquals("1234", paramsForTag.get(PID_KEY));
+        Assertions.assertEquals("foo", paramsForTag.get(THREADPOOL_KEY));
+        Assertions.assertEquals("consumer", paramsForTag.get(APPLICATION_KEY));
+        Assertions.assertEquals("filter3", paramsForTag.get(REFERENCE_FILTER_KEY));
+        Assertions.assertNull(paramsForTag.get(TAG_KEY));
+    }
 }
diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/protocol/CountInvokerListener.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/TagProviderURLMergeProcessor.java
similarity index 52%
copy from dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/protocol/CountInvokerListener.java
copy to dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/TagProviderURLMergeProcessor.java
index 4883380..02d8ed6 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/protocol/CountInvokerListener.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/TagProviderURLMergeProcessor.java
@@ -14,30 +14,29 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.rpc.protocol;
+package org.apache.dubbo.rpc.cluster.support;
 
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.InvokerListener;
-import org.apache.dubbo.rpc.RpcException;
 
-import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor;
 
+import java.util.Map;
 
-public class CountInvokerListener implements InvokerListener {
+import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
 
-    private final static AtomicInteger counter = new AtomicInteger(0);
+public class TagProviderURLMergeProcessor implements ProviderURLMergeProcessor {
 
     @Override
-    public void referred(Invoker<?> invoker) throws RpcException {
-        counter.incrementAndGet();
+    public URL mergeUrl(URL remoteUrl, Map<String, String> localParametersMap) {
+        String tag = localParametersMap.get(TAG_KEY);
+        remoteUrl = remoteUrl.removeParameter(TAG_KEY);
+        remoteUrl = remoteUrl.addParameter(TAG_KEY, tag);
+        return remoteUrl;
     }
 
     @Override
-    public void destroyed(Invoker<?> invoker) {
-
-    }
-
-    public static int getCounter() {
-        return counter.get();
+    public Map<String, String> mergeLocalParams(Map<String, String> localMap) {
+        localMap.remove(TAG_KEY);
+        return ProviderURLMergeProcessor.super.mergeLocalParams(localMap);
     }
 }
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/merger/DefaultProviderURLMergeProcessorTest.java
similarity index 66%
copy from dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
copy to dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/merger/DefaultProviderURLMergeProcessorTest.java
index 7cf23b3..8a5f43b 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/merger/DefaultProviderURLMergeProcessorTest.java
@@ -14,84 +14,84 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.rpc.cluster.support;
+package org.apache.dubbo.rpc.cluster.support.merger;
+
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.URLBuilder;
-import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
 import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
 import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
 
-public class ClusterUtilsTest {
+public class DefaultProviderURLMergeProcessorTest {
 
-    private ClusterUtils clusterUtils;
+    private ProviderURLMergeProcessor providerURLMergeProcessor;
 
     @BeforeEach
     public void setup() {
-        clusterUtils = new ClusterUtils();
-        clusterUtils.setApplicationModel(ApplicationModel.defaultModel());
+        providerURLMergeProcessor = new DefaultProviderURLMergeProcessor();
     }
 
     @Test
     public void testMergeUrl() throws Exception {
         URL providerURL = URL.valueOf("dubbo://localhost:55555");
         providerURL = providerURL.setPath("path")
-                .setUsername("username")
-                .setPassword("password");
+            .setUsername("username")
+            .setPassword("password");
 
         providerURL = URLBuilder.from(providerURL)
-                .addParameter(GROUP_KEY, "dubbo")
-                .addParameter(VERSION_KEY, "1.2.3")
-                .addParameter(DUBBO_VERSION_KEY, "2.3.7")
-                .addParameter(THREADPOOL_KEY, "fixed")
-                .addParameter(THREADS_KEY, Integer.MAX_VALUE)
-                .addParameter(THREAD_NAME_KEY, "test")
-                .addParameter(CORE_THREADS_KEY, Integer.MAX_VALUE)
-                .addParameter(QUEUES_KEY, Integer.MAX_VALUE)
-                .addParameter(ALIVE_KEY, Integer.MAX_VALUE)
-                .addParameter(DEFAULT_KEY_PREFIX + THREADS_KEY, Integer.MAX_VALUE)
-                .addParameter(DEFAULT_KEY_PREFIX + THREADPOOL_KEY, "fixed")
-                .addParameter(DEFAULT_KEY_PREFIX + CORE_THREADS_KEY, Integer.MAX_VALUE)
-                .addParameter(DEFAULT_KEY_PREFIX + QUEUES_KEY, Integer.MAX_VALUE)
-                .addParameter(DEFAULT_KEY_PREFIX + ALIVE_KEY, Integer.MAX_VALUE)
-                .addParameter(DEFAULT_KEY_PREFIX + THREAD_NAME_KEY, "test")
-                .addParameter(APPLICATION_KEY, "provider")
-                .addParameter(REFERENCE_FILTER_KEY, "filter1,filter2")
-                .addParameter(TAG_KEY,"TTT")
-                .build();
+            .addParameter(GROUP_KEY, "dubbo")
+            .addParameter(VERSION_KEY, "1.2.3")
+            .addParameter(DUBBO_VERSION_KEY, "2.3.7")
+            .addParameter(THREADPOOL_KEY, "fixed")
+            .addParameter(THREADS_KEY, Integer.MAX_VALUE)
+            .addParameter(THREAD_NAME_KEY, "test")
+            .addParameter(CORE_THREADS_KEY, Integer.MAX_VALUE)
+            .addParameter(QUEUES_KEY, Integer.MAX_VALUE)
+            .addParameter(ALIVE_KEY, Integer.MAX_VALUE)
+            .addParameter(DEFAULT_KEY_PREFIX + THREADS_KEY, Integer.MAX_VALUE)
+            .addParameter(DEFAULT_KEY_PREFIX + THREADPOOL_KEY, "fixed")
+            .addParameter(DEFAULT_KEY_PREFIX + CORE_THREADS_KEY, Integer.MAX_VALUE)
+            .addParameter(DEFAULT_KEY_PREFIX + QUEUES_KEY, Integer.MAX_VALUE)
+            .addParameter(DEFAULT_KEY_PREFIX + ALIVE_KEY, Integer.MAX_VALUE)
+            .addParameter(DEFAULT_KEY_PREFIX + THREAD_NAME_KEY, "test")
+            .addParameter(APPLICATION_KEY, "provider")
+            .addParameter(REFERENCE_FILTER_KEY, "filter1,filter2")
+            .addParameter(TAG_KEY, "TTT")
+            .build();
 
         URL consumerURL = new URLBuilder(DUBBO_PROTOCOL, "localhost", 55555)
-                .addParameter(PID_KEY, "1234")
-                .addParameter(THREADPOOL_KEY, "foo")
-                .addParameter(APPLICATION_KEY, "consumer")
-                .addParameter(REFERENCE_FILTER_KEY, "filter3")
-                .addParameter(TAG_KEY,"UUU")
-                .build();
+            .addParameter(PID_KEY, "1234")
+            .addParameter(THREADPOOL_KEY, "foo")
+            .addParameter(APPLICATION_KEY, "consumer")
+            .addParameter(REFERENCE_FILTER_KEY, "filter3")
+            .addParameter(TAG_KEY, "UUU")
+            .build();
 
-        URL url = clusterUtils.mergeUrl(providerURL, consumerURL.getParameters());
+        URL url = providerURLMergeProcessor.mergeUrl(providerURL, consumerURL.getParameters());
 
         Assertions.assertFalse(url.hasParameter(THREADS_KEY));
         Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + THREADS_KEY));
@@ -110,26 +110,26 @@ public class ClusterUtilsTest {
         Assertions.assertFalse(url.hasParameter(THREAD_NAME_KEY));
         Assertions.assertFalse(url.hasParameter(DEFAULT_KEY_PREFIX + THREAD_NAME_KEY));
 
-        Assertions.assertEquals(url.getPath(), "path");
-        Assertions.assertEquals(url.getUsername(), "username");
-        Assertions.assertEquals(url.getPassword(), "password");
-        Assertions.assertEquals(url.getParameter(PID_KEY), "1234");
-        Assertions.assertEquals(url.getParameter(THREADPOOL_KEY), "foo");
-        Assertions.assertEquals(url.getApplication(), "consumer");
-        Assertions.assertEquals(url.getRemoteApplication(), "provider");
-        Assertions.assertEquals(url.getParameter(REFERENCE_FILTER_KEY), "filter1,filter2,filter3");
+        Assertions.assertEquals("path", url.getPath());
+        Assertions.assertEquals("username", url.getUsername());
+        Assertions.assertEquals("password", url.getPassword());
+        Assertions.assertEquals("1234", url.getParameter(PID_KEY));
+        Assertions.assertEquals("foo", url.getParameter(THREADPOOL_KEY));
+        Assertions.assertEquals("consumer", url.getApplication());
+        Assertions.assertEquals("provider", url.getRemoteApplication());
+        Assertions.assertEquals("filter1,filter2,filter3", url.getParameter(REFERENCE_FILTER_KEY));
 
-        Assertions.assertEquals(url.getParameter(TAG_KEY), "TTT");
+        Assertions.assertEquals("TTT", url.getParameter(TAG_KEY));
     }
 
     @Test
     public void testUseProviderParams() {
         // present in both local and remote, but uses remote value.
         URL localURL = URL.valueOf("dubbo://localhost:20880/DemoService?version=local&group=local&dubbo=local&release=local" +
-                "&methods=local&tag=local&timestamp=local");
+            "&methods=local&tag=local&timestamp=local");
         URL remoteURL = URL.valueOf("dubbo://localhost:20880/DemoService?version=remote&group=remote&dubbo=remote&release=remote" +
-                "&methods=remote&tag=remote&timestamp=remote");
-        URL mergedUrl = clusterUtils.mergeUrl(remoteURL, localURL.getParameters());
+            "&methods=remote&tag=remote&timestamp=remote");
+        URL mergedUrl = providerURLMergeProcessor.mergeUrl(remoteURL, localURL.getParameters());
 
         Assertions.assertEquals(remoteURL.getVersion(), mergedUrl.getVersion());
         Assertions.assertEquals(remoteURL.getGroup(), mergedUrl.getGroup());
@@ -141,12 +141,12 @@ public class ClusterUtilsTest {
 
         // present in local url but not in remote url, parameters of remote url is empty
         localURL = URL.valueOf("dubbo://localhost:20880/DemoService?version=local&group=local&dubbo=local&release=local" +
-                "&methods=local&tag=local&timestamp=local");
+            "&methods=local&tag=local&timestamp=local");
         remoteURL = URL.valueOf("dubbo://localhost:20880/DemoService");
-        mergedUrl = clusterUtils.mergeUrl(remoteURL, localURL.getParameters());
+        mergedUrl = providerURLMergeProcessor.mergeUrl(remoteURL, localURL.getParameters());
 
-        Assertions.assertEquals(mergedUrl.getVersion(),localURL.getVersion());
-        Assertions.assertEquals(mergedUrl.getGroup(),localURL.getGroup());
+        Assertions.assertEquals(localURL.getVersion(), mergedUrl.getVersion());
+        Assertions.assertEquals(localURL.getGroup(), mergedUrl.getGroup());
         Assertions.assertNull(mergedUrl.getParameter(DUBBO_VERSION_KEY));
         Assertions.assertNull(mergedUrl.getParameter(RELEASE_KEY));
         Assertions.assertNull(mergedUrl.getParameter(METHODS_KEY));
@@ -155,12 +155,12 @@ public class ClusterUtilsTest {
 
         // present in local url but not in remote url
         localURL = URL.valueOf("dubbo://localhost:20880/DemoService?version=local&group=local&dubbo=local&release=local" +
-                "&methods=local&tag=local&timestamp=local");
+            "&methods=local&tag=local&timestamp=local");
         remoteURL = URL.valueOf("dubbo://localhost:20880/DemoService?key=value");
-        mergedUrl = clusterUtils.mergeUrl(remoteURL, localURL.getParameters());
+        mergedUrl = providerURLMergeProcessor.mergeUrl(remoteURL, localURL.getParameters());
 
-        Assertions.assertEquals(mergedUrl.getVersion(),localURL.getVersion());
-        Assertions.assertEquals(mergedUrl.getGroup(),localURL.getGroup());
+        Assertions.assertEquals(localURL.getVersion(), mergedUrl.getVersion());
+        Assertions.assertEquals(localURL.getGroup(), mergedUrl.getGroup());
         Assertions.assertNull(mergedUrl.getParameter(DUBBO_VERSION_KEY));
         Assertions.assertNull(mergedUrl.getParameter(RELEASE_KEY));
         Assertions.assertNull(mergedUrl.getParameter(METHODS_KEY));
@@ -170,11 +170,10 @@ public class ClusterUtilsTest {
         // present in both local and remote, uses local url params
         localURL = URL.valueOf("dubbo://localhost:20880/DemoService?loadbalance=local&timeout=1000&cluster=local");
         remoteURL = URL.valueOf("dubbo://localhost:20880/DemoService?loadbalance=remote&timeout=2000&cluster=remote");
-        mergedUrl = clusterUtils.mergeUrl(remoteURL, localURL.getParameters());
+        mergedUrl = providerURLMergeProcessor.mergeUrl(remoteURL, localURL.getParameters());
 
         Assertions.assertEquals(localURL.getParameter(CLUSTER_KEY), mergedUrl.getParameter(CLUSTER_KEY));
         Assertions.assertEquals(localURL.getParameter(TIMEOUT_KEY), mergedUrl.getParameter(TIMEOUT_KEY));
         Assertions.assertEquals(localURL.getParameter(LOADBALANCE_KEY), mergedUrl.getParameter(LOADBALANCE_KEY));
     }
-
 }
diff --git a/dubbo-cluster/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor b/dubbo-cluster/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor
new file mode 100644
index 0000000..8bf1a88
--- /dev/null
+++ b/dubbo-cluster/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor
@@ -0,0 +1 @@
+tag=org.apache.dubbo.rpc.cluster.support.TagProviderURLMergeProcessor
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index 43ab5f5..5c8639d 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
@@ -551,7 +551,6 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
             } catch (ClassNotFoundException e) {
                 throw new IllegalStateException(e.getMessage(), e);
             }
-            //checkInterfaceAndMethods(interfaceClass, getMethods());
         }
 
         checkStubAndLocal(interfaceClass);
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
index 2c9168b..be1d486 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
@@ -323,7 +323,6 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
             } catch (ClassNotFoundException e) {
                 throw new IllegalStateException(e.getMessage(), e);
             }
-            //checkInterfaceAndMethods(interfaceClass, getMethods());
             checkRef();
             generic = Boolean.FALSE.toString();
         }
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MethodConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MethodConfigTest.java
index 23c7a60..3bd2495 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MethodConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MethodConfigTest.java
@@ -97,12 +97,12 @@ public class MethodConfigTest {
         MethodConfig methodConfig = methodConfigs.get(0);
 
         assertThat(METHOD_NAME, equalTo(methodConfig.getName()));
-        assertThat(TIMEOUT, equalTo(methodConfig.getTimeout().intValue()));
-        assertThat(RETRIES, equalTo(methodConfig.getRetries().intValue()));
+        assertThat(TIMEOUT, equalTo(methodConfig.getTimeout()));
+        assertThat(RETRIES, equalTo(methodConfig.getRetries()));
         assertThat(LOADBALANCE, equalTo(methodConfig.getLoadbalance()));
         assertThat(ASYNC, equalTo(methodConfig.isAsync()));
-        assertThat(ACTIVES, equalTo(methodConfig.getActives().intValue()));
-        assertThat(EXECUTES, equalTo(methodConfig.getExecutes().intValue()));
+        assertThat(ACTIVES, equalTo(methodConfig.getActives()));
+        assertThat(EXECUTES, equalTo(methodConfig.getExecutes()));
         assertThat(DEPERECATED, equalTo(methodConfig.getDeprecated()));
         assertThat(STICKY, equalTo(methodConfig.getSticky()));
         assertThat(ONINVOKE, equalTo(methodConfig.getOninvoke()));
@@ -113,7 +113,7 @@ public class MethodConfigTest {
         assertThat(ONRETURN_METHOD, equalTo(methodConfig.getOnreturnMethod()));
         assertThat(CACHE, equalTo(methodConfig.getCache()));
         assertThat(VALIDATION, equalTo(methodConfig.getValidation()));
-        assertThat(ARGUMENTS_INDEX, equalTo(methodConfig.getArguments().get(0).getIndex().intValue()));
+        assertThat(ARGUMENTS_INDEX, equalTo(methodConfig.getArguments().get(0).getIndex()));
         assertThat(ARGUMENTS_CALLBACK, equalTo(methodConfig.getArguments().get(0).isCallback()));
         assertThat(ARGUMENTS_TYPE, equalTo(methodConfig.getArguments().get(0).getType()));
     }
@@ -123,7 +123,7 @@ public class MethodConfigTest {
         MethodConfig method = new MethodConfig();
         method.setName("hello");
         assertThat(method.getName(), equalTo("hello"));
-        Map<String, String> parameters = new HashMap<String, String>();
+        Map<String, String> parameters = new HashMap<>();
         MethodConfig.appendParameters(parameters, method);
         assertThat(parameters, not(hasKey("name")));
     }
@@ -180,7 +180,7 @@ public class MethodConfigTest {
     }
 
     //@Test
-    public void testOnreturn() throws Exception {
+    public void testOnReturn() throws Exception {
         MethodConfig method = new MethodConfig();
         method.setOnreturn("on-return-object");
         assertThat(method.getOnreturn(), equalTo("on-return-object"));
@@ -193,7 +193,7 @@ public class MethodConfigTest {
     }
 
     @Test
-    public void testOnreturnMethod() throws Exception {
+    public void testOnReturnMethod() throws Exception {
         MethodConfig method = new MethodConfig();
         method.setOnreturnMethod("on-return-method");
         assertThat(method.getOnreturnMethod(), equalTo("on-return-method"));
@@ -206,7 +206,7 @@ public class MethodConfigTest {
     }
 
     //@Test
-    public void testOnthrow() throws Exception {
+    public void testOnThrow() throws Exception {
         MethodConfig method = new MethodConfig();
         method.setOnthrow("on-throw-object");
         assertThat(method.getOnthrow(), equalTo((Object) "on-throw-object"));
@@ -219,7 +219,7 @@ public class MethodConfigTest {
     }
 
     @Test
-    public void testOnthrowMethod() throws Exception {
+    public void testOnThrowMethod() throws Exception {
         MethodConfig method = new MethodConfig();
         method.setOnthrowMethod("on-throw-method");
         assertThat(method.getOnthrowMethod(), equalTo("on-throw-method"));
@@ -232,7 +232,7 @@ public class MethodConfigTest {
     }
 
     //@Test
-    public void testOninvoke() throws Exception {
+    public void testOnInvoke() throws Exception {
         MethodConfig method = new MethodConfig();
         method.setOninvoke("on-invoke-object");
         assertThat(method.getOninvoke(), equalTo((Object) "on-invoke-object"));
@@ -245,7 +245,7 @@ public class MethodConfigTest {
     }
 
     @Test
-    public void testOninvokeMethod() throws Exception {
+    public void testOnInvokeMethod() throws Exception {
         MethodConfig method = new MethodConfig();
         method.setOninvokeMethod("on-invoke-method");
         assertThat(method.getOninvokeMethod(), equalTo("on-invoke-method"));
@@ -273,7 +273,7 @@ public class MethodConfigTest {
         SysProps.setProperty("dubbo.reference."+ interfaceName +".sayName.parameters", "[{a:1},{b:2}]");
         SysProps.setProperty("dubbo.reference."+ interfaceName +".init", "false");
 
-        ReferenceConfig referenceConfig = new ReferenceConfig();
+        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();
         referenceConfig.setInterface(interfaceName);
         MethodConfig methodConfig = new MethodConfig();
         methodConfig.setName("sayName");
@@ -305,7 +305,7 @@ public class MethodConfigTest {
         SysProps.setProperty("dubbo.reference."+ interfaceName +".sayName.parameters", "[{a:1},{b:2}]");
         SysProps.setProperty("dubbo.reference."+ interfaceName +".init", "false");
 
-        ReferenceConfig referenceConfig = new ReferenceConfig();
+        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();
         referenceConfig.setInterface(interfaceName);
 
         DubboBootstrap.getInstance()
@@ -338,13 +338,13 @@ public class MethodConfigTest {
         SysProps.setProperty("dubbo.service."+ interfaceName +".group", "demo");
         SysProps.setProperty("dubbo.registry.address", "N/A");
 
-        ServiceConfig serviceConfig = new ServiceConfig();
+        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();
         serviceConfig.setInterface(interfaceName);
         serviceConfig.setRef(new DemoServiceImpl());
         MethodConfig methodConfig = new MethodConfig();
         methodConfig.setName("sayName");
         methodConfig.setTimeout(1000);
-        serviceConfig.setMethods(Arrays.asList(methodConfig));
+        serviceConfig.setMethods(Collections.singletonList(methodConfig));
 
         DubboBootstrap.getInstance()
             .application("demo-app")
@@ -360,6 +360,8 @@ public class MethodConfigTest {
         Assertions.assertEquals(params, methodConfig.getParameters());
         Assertions.assertEquals("demo", serviceConfig.getGroup());
 
+        DubboBootstrap.getInstance().destroy();
+
     }
 
     @Test
@@ -374,11 +376,11 @@ public class MethodConfigTest {
         SysProps.setProperty("dubbo.service."+ interfaceName +".echo", "non-method-config");
         SysProps.setProperty("dubbo.registry.address", "N/A");
 
-        ServiceConfig serviceConfig = new ServiceConfig();
+        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();
         serviceConfig.setInterface(interfaceName);
         serviceConfig.setRef(new DemoServiceImpl());
 
-        Assertions.assertEquals(null, serviceConfig.getMethods());
+        Assertions.assertNull(serviceConfig.getMethods());
 
         DubboBootstrap.getInstance()
             .application("demo-app")
@@ -403,7 +405,7 @@ public class MethodConfigTest {
         Assertions.assertEquals(true, methodConfig.getSticky());
         Assertions.assertEquals(0, argumentConfig.getIndex());
         Assertions.assertEquals(true, argumentConfig.isCallback());
-
+        DubboBootstrap.getInstance().destroy();
     }
 
     @Test
@@ -414,13 +416,13 @@ public class MethodConfigTest {
         SysProps.setProperty("dubbo.service."+ interfaceName +".group", "demo");
         SysProps.setProperty("dubbo.registry.address", "N/A");
 
-        ServiceConfig serviceConfig = new ServiceConfig();
+        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();
         serviceConfig.setInterface(interfaceName);
         serviceConfig.setRef(new DemoServiceImpl());
         MethodConfig methodConfig = new MethodConfig();
         methodConfig.setName("sayHello");
         methodConfig.setTimeout(1000);
-        serviceConfig.setMethods(Arrays.asList(methodConfig));
+        serviceConfig.setMethods(Collections.singletonList(methodConfig));
 
         try {
             DubboBootstrap.getInstance()
@@ -433,6 +435,8 @@ public class MethodConfigTest {
             Throwable cause = e.getCause();
             Assertions.assertEquals(IllegalStateException.class, cause.getClass());
             Assertions.assertTrue(cause.getMessage().contains("not found method"), cause.toString());
+        }finally {
+            DubboBootstrap.getInstance().destroy();
         }
     }
 
@@ -445,22 +449,23 @@ public class MethodConfigTest {
         SysProps.setProperty("dubbo.registry.address", "N/A");
         SysProps.setProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_INVALID_METHOD_CONFIG, "true");
 
-        ServiceConfig serviceConfig = new ServiceConfig();
+        ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();
         serviceConfig.setInterface(interfaceName);
         serviceConfig.setRef(new DemoServiceImpl());
         MethodConfig methodConfig = new MethodConfig();
         methodConfig.setName("sayHello");
         methodConfig.setTimeout(1000);
-        serviceConfig.setMethods(Arrays.asList(methodConfig));
+        serviceConfig.setMethods(Collections.singletonList(methodConfig));
 
         DubboBootstrap.getInstance()
             .application("demo-app")
             .service(serviceConfig)
             .initialize();
 
-        // expect sayHello method config will be ignore, and sayName method config will be create.
+        // expect sayHello method config will be ignored, and sayName method config will be created.
         Assertions.assertEquals(1, serviceConfig.getMethods().size());
         Assertions.assertEquals("sayName", serviceConfig.getMethods().get(0).getName());
+        DubboBootstrap.getInstance().destroy();
     }
 
     @Test
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
index ab21b6b..e3fd806 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
@@ -121,6 +121,7 @@ import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
 import static org.apache.dubbo.rpc.Constants.SCOPE_KEY;
 import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
 import static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;
+import static org.apache.dubbo.rpc.cluster.Constants.PEER_KEY;
 
 public class ReferenceConfigTest {
     private static String zkUrl1;
@@ -550,6 +551,48 @@ public class ReferenceConfigTest {
         dubboBootstrap.destroy();
     }
 
+
+    /**
+     * Verify that the remote url is directly configured for remote reference
+     */
+    @Test
+    public void testCreateInvokerWithRemoteUrlForRemoteRefer() {
+
+        ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();
+        referenceConfig.setGeneric(Boolean.FALSE.toString());
+        referenceConfig.setProtocol("dubbo");
+        referenceConfig.setInit(true);
+        referenceConfig.setLazy(false);
+        referenceConfig.setInjvm(false);
+
+        DubboBootstrap dubboBootstrap = DubboBootstrap.newInstance(FrameworkModel.defaultModel());
+
+        ApplicationConfig applicationConfig = new ApplicationConfig();
+        applicationConfig.setName("application1");
+        Map<String, String> parameters = new HashMap<>();
+        parameters.put("key1", "value1");
+        parameters.put("key2", "value2");
+        applicationConfig.setParameters(parameters);
+
+        referenceConfig.refreshed.set(true);
+        referenceConfig.setInterface(DemoService.class);
+        referenceConfig.getInterfaceClass();
+        referenceConfig.setCheck(false);
+
+        referenceConfig.setUrl("dubbo://127.0.0.1:20880");
+
+        dubboBootstrap
+            .application(applicationConfig)
+            .reference(referenceConfig)
+            .initialize();
+
+        referenceConfig.init();
+        Assertions.assertTrue(referenceConfig.getInvoker() instanceof MockClusterInvoker);
+        Assertions.assertEquals(Boolean.TRUE, referenceConfig.getInvoker().getUrl().getAttribute(PEER_KEY));
+        dubboBootstrap.destroy();
+
+    }
+
     /**
      * Verify that the registry url is directly configured for remote reference
      */
@@ -1081,6 +1124,7 @@ public class ReferenceConfigTest {
     private class InnerTest {
 
     }
+
     private static class TestClassLoader extends ClassLoader {
         private String basePath;
 
diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/protocol/CountInvokerListener.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/protocol/CountInvokerListener.java
index 4883380..420bbf7 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/protocol/CountInvokerListener.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/protocol/CountInvokerListener.java
@@ -29,6 +29,7 @@ public class CountInvokerListener implements InvokerListener {
 
     @Override
     public void referred(Invoker<?> invoker) throws RpcException {
+        counter.set(0);
         counter.incrementAndGet();
     }
 
diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/protocol/ProtocolListenerWrapperTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/protocol/ProtocolListenerWrapperTest.java
index 5f0bbe4..d174181 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/protocol/ProtocolListenerWrapperTest.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/protocol/ProtocolListenerWrapperTest.java
@@ -34,7 +34,6 @@ import static org.mockito.Mockito.when;
 
 public class ProtocolListenerWrapperTest {
 
-
     @Test
     public void testLoadingListenerForLocalReference() {
         // verify that no listener is loaded by default
@@ -77,5 +76,47 @@ public class ProtocolListenerWrapperTest {
         Assertions.assertEquals(1, CountInvokerListener.getCounter());
     }
 
+    @Test
+    public void testLoadingListenerForRemoteReference() {
+        // verify that no listener is loaded by default
+        URL urlWithoutListener = URL.valueOf("dubbo://127.0.0.1:20880/DemoService")
+            .addParameter(INTERFACE_KEY, DemoService.class.getName());
+        AbstractInvoker<DemoService> invokerWithoutListener = new AbstractInvoker<DemoService>(DemoService.class, urlWithoutListener) {
+            @Override
+            protected Result doInvoke(Invocation invocation) throws Throwable {
+                return null;
+            }
+        };
+
+        Protocol protocolWithoutListener = mock(Protocol.class);
+        when(protocolWithoutListener.refer(DemoService.class, urlWithoutListener)).thenReturn(invokerWithoutListener);
+
+        ProtocolListenerWrapper protocolListenerWrapperWithoutListener = new ProtocolListenerWrapper(protocolWithoutListener);
+
+        Invoker<?> invoker = protocolListenerWrapperWithoutListener.refer(DemoService.class, urlWithoutListener);
+        Assertions.assertTrue(invoker instanceof ListenerInvokerWrapper);
+        Assertions.assertEquals(0, ((ListenerInvokerWrapper<?>) invoker).getListeners().size());
+
+        // verify that if the invoker.listener is configured, then load the specified listener
+        URL urlWithListener = URL.valueOf("dubbo://127.0.0.1:20880/DemoService")
+            .addParameter(INTERFACE_KEY, DemoService.class.getName())
+            .addParameter(INVOKER_LISTENER_KEY, "count");
+        AbstractInvoker<DemoService> invokerWithListener = new AbstractInvoker<DemoService>(DemoService.class, urlWithListener) {
+            @Override
+            protected Result doInvoke(Invocation invocation) throws Throwable {
+                return null;
+            }
+        };
+
+        Protocol protocol = mock(Protocol.class);
+        when(protocol.refer(DemoService.class, urlWithListener)).thenReturn(invokerWithListener);
+
+        ProtocolListenerWrapper protocolListenerWrapper = new ProtocolListenerWrapper(protocol);
+
+        invoker = protocolListenerWrapper.refer(DemoService.class, urlWithListener);
+        Assertions.assertTrue(invoker instanceof ListenerInvokerWrapper);
+        Assertions.assertEquals(1, CountInvokerListener.getCounter());
+    }
+
 
 }