You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2021/08/06 04:49:20 UTC

[dubbo] branch 3.0 updated: test: Add testcases for checking Injvm protocol in multiple registry center (#8418)

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

albumenj 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 75443e1  test: Add testcases for checking Injvm protocol in multiple registry center (#8418)
75443e1 is described below

commit 75443e1c8e842c2ce700e7dd4d01a16921edd278
Author: Xiong, Pin <pi...@foxmail.com>
AuthorDate: Thu Aug 5 23:49:09 2021 -0500

    test: Add testcases for checking Injvm protocol in multiple registry center (#8418)
    
    1. Refactor the previous source code for checking Injvm protocol in single registry center
    2. Verify the exported services through the custom ServiceListener in multiple registry center
    3. Verify the exported exporters through the custom ExporterListener in multiple registry center
    4. Verify the filter chain through the custom Filter in multiple registry center
---
 ...=> AbstractRegistryCenterExporterListener.java} |  24 ++-
 ... => AbstractRegistryCenterServiceListener.java} |  13 +-
 .../multiple/MultipleZooKeeperServer.java          | 225 +++++++++++++++++++++
 ...ultipleRegistryCenterInjvmExporterListener.java |  33 +++
 .../injvm/MultipleRegistryCenterInjvmFilter.java}  |  12 +-
 ...ultipleRegistryCenterInjvmIntegrationTest.java} |  82 ++++----
 .../injvm/MultipleRegistryCenterInjvmService.java  |  26 +++
 .../MultipleRegistryCenterInjvmServiceImpl.java    |  30 +++
 ...MultipleRegistryCenterInjvmServiceListener.java |  34 ++++
 .../dubbo/integration/multiple/package-info.java   |  22 ++
 ...RegistryCenterDubboProtocolIntegrationTest.java |  37 ++--
 ...ingleRegistryCenterExportedServiceListener.java |  34 ++++
 .../SingleRegistryCenterInjvmExporterListener.java |  33 +++
 ...r.java => SingleRegistryCenterInjvmFilter.java} |   2 +-
 .../SingleRegistryCenterInjvmIntegrationTest.java  |  34 ++--
 .../SingleRegistryCenterInjvmServiceListener.java  |  34 ++++
 .../single/listener/ExportedServiceListener.java   |  61 ------
 .../org.apache.dubbo.config.ServiceListener        |   5 +-
 .../services/org.apache.dubbo.rpc.ExporterListener |   3 +-
 .../META-INF/services/org.apache.dubbo.rpc.Filter  |   3 +-
 20 files changed, 575 insertions(+), 172 deletions(-)

diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/listener/InjvmExporterListener.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/AbstractRegistryCenterExporterListener.java
similarity index 87%
rename from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/listener/InjvmExporterListener.java
rename to dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/AbstractRegistryCenterExporterListener.java
index 6f3ace1..c23e400 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/listener/InjvmExporterListener.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/AbstractRegistryCenterExporterListener.java
@@ -14,11 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.integration.single.listener;
+package org.apache.dubbo.integration;
 
-import org.apache.dubbo.common.constants.CommonConstants;
-import org.apache.dubbo.common.extension.Activate;
-import org.apache.dubbo.integration.single.injvm.SingleRegistryCenterInjvmService;
 import org.apache.dubbo.rpc.Exporter;
 import org.apache.dubbo.rpc.ExporterListener;
 import org.apache.dubbo.rpc.Filter;
@@ -27,10 +24,16 @@ import org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder;
 import org.apache.dubbo.rpc.listener.ListenerExporterWrapper;
 
 import java.lang.reflect.Field;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
 
-@Activate(group = CommonConstants.PROVIDER, order = 1000)
-public class InjvmExporterListener implements ExporterListener {
+/**
+ * The abstraction of {@link ExporterListener} is to record exported exporters, which should be extended by different sub-classes.
+ */
+public abstract class AbstractRegistryCenterExporterListener implements ExporterListener {
 
     /**
      * Exported exporters.
@@ -43,6 +46,11 @@ public class InjvmExporterListener implements ExporterListener {
     private Set<Filter> filters = new HashSet<>();
 
     /**
+     * Returns the interface of exported service.
+     */
+    protected abstract Class<?> getInterface();
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -50,7 +58,7 @@ public class InjvmExporterListener implements ExporterListener {
         ListenerExporterWrapper listenerExporterWrapper = (ListenerExporterWrapper) exporter;
         FilterChainBuilder.FilterChainNode filterChainNode = (FilterChainBuilder.FilterChainNode) listenerExporterWrapper.getInvoker();
         if (filterChainNode == null ||
-            filterChainNode.getInterface() != SingleRegistryCenterInjvmService.class) {
+            filterChainNode.getInterface() != getInterface()) {
             return;
         }
         exportedExporters.add(exporter);
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/listener/InjvmServiceListener.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/AbstractRegistryCenterServiceListener.java
similarity index 81%
rename from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/listener/InjvmServiceListener.java
rename to dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/AbstractRegistryCenterServiceListener.java
index 0764b78..438e228 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/listener/InjvmServiceListener.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/AbstractRegistryCenterServiceListener.java
@@ -14,30 +14,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.integration.single.listener;
+package org.apache.dubbo.integration;
 
 import org.apache.dubbo.config.ServiceConfig;
 import org.apache.dubbo.config.ServiceListener;
-import org.apache.dubbo.integration.single.injvm.SingleRegistryCenterInjvmService;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 /**
- * This implementation of {@link ServiceListener} is to record exported services with injvm protocol.
+ * This implementation of {@link ServiceListener} is to record exported services, which should be extended by different sub-classes.
  */
-public class InjvmServiceListener implements ServiceListener {
+public abstract class AbstractRegistryCenterServiceListener implements ServiceListener {
 
     private List<ServiceConfig> exportedServices = new ArrayList<>(2);
 
     /**
+     * Return the interface name of exported service.
+     */
+    protected abstract Class<?> getInterface();
+    /**
      * {@inheritDoc}
      */
     @Override
     public void exported(ServiceConfig sc) {
         //All exported services will be added
-        if (sc.getInterfaceClass() == SingleRegistryCenterInjvmService.class) {
+        if (sc.getInterfaceClass() == getInterface()) {
             exportedServices.add(sc);
         }
     }
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/MultipleZooKeeperServer.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/MultipleZooKeeperServer.java
new file mode 100644
index 0000000..8780b70
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/MultipleZooKeeperServer.java
@@ -0,0 +1,225 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.integration.multiple;
+
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.zookeeper.server.ServerConfig;
+import org.apache.zookeeper.server.ZooKeeperServerMain;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.Properties;
+import java.util.UUID;
+
+/**
+ * The zookeeper server is just for testing.
+ * Also there is only one static instance, which can be created.
+ * <p>
+ * Note: It can only be used if the following conditions are satisfied
+ * <p>1. Integration testcase instead of unit testcase
+ * <p>2. You can use only one zookeeper instance per Package, because the zookeeper is a static global instance.
+ */
+public class MultipleZooKeeperServer {
+
+    private static final Logger logger = LoggerFactory.getLogger(MultipleZooKeeperServer.class);
+
+    /**
+     * Define a static zookeeper instance.
+     */
+    private static volatile InnerZooKeeper INSTANCE_ONE;
+
+    /**
+     * Define a static zookeeper instance.
+     */
+    private static volatile InnerZooKeeper INSTANCE_TWO;
+
+    /**
+     * Start the zookeeper instances.
+     */
+    public static void start() {
+        if (INSTANCE_ONE == null) {
+            INSTANCE_ONE = new InnerZooKeeper("multiple-zookeeper-server-one-for-test",
+                NetUtils.getAvailablePort());
+            INSTANCE_ONE.start();
+        }
+        if (INSTANCE_TWO == null) {
+            INSTANCE_TWO = new InnerZooKeeper("multiple-zookeeper-server-two-for-test",
+                NetUtils.getAvailablePort());
+            INSTANCE_TWO.start();
+        }
+    }
+
+    /**
+     * Returns the zookeeper-one server's port.
+     */
+    public static int getPortOne() {
+        return INSTANCE_ONE.getClientPort();
+    }
+
+    /**
+     * Returns the zookeeper-two server's port.
+     */
+    public static int getPortTwo() {
+        return INSTANCE_TWO.getClientPort();
+    }
+
+    /**
+     * Checks if all zookeeper servers are running.
+     */
+    public static boolean isRunning() {
+        return INSTANCE_ONE.isRunning() && INSTANCE_TWO.isRunning();
+    }
+
+    /**
+     * Shutdown all zookeeper instances.
+     */
+    public static void shutdown() {
+        if (INSTANCE_ONE != null) {
+            INSTANCE_ONE.shutdown();
+            INSTANCE_ONE = null;
+        }
+
+        if (INSTANCE_TWO != null) {
+            INSTANCE_TWO.shutdown();
+            INSTANCE_TWO = null;
+        }
+    }
+
+    /**
+     * from: https://github.com/spring-projects/spring-xd/blob/v1.3.1.RELEASE/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/zookeeper/ZooKeeperUtils.java
+     * <p>
+     * Helper class to start an embedded instance of standalone (non clustered) ZooKeeper.
+     * <p>
+     * NOTE: at least an external standalone server (if not an ensemble) are recommended, even for
+     */
+    private static class InnerZooKeeper {
+
+        /**
+         * ZooKeeper client port. This will be determined dynamically upon startup.
+         */
+        private final int clientPort;
+
+        /**
+         * ZooKeeper name.
+         */
+        private final String zookeeperName;
+
+        /**
+         * Thread for running the ZooKeeper server.
+         */
+        private volatile Thread zkServerThread;
+
+        /**
+         * ZooKeeper server.
+         */
+        private volatile ZooKeeperServerMain zkServer;
+
+        /**
+         * Construct an EmbeddedZooKeeper with the provided port.
+         *
+         * @param zookeeperName zookeeper name
+         * @param clientPort port for ZooKeeper server to bind to
+         */
+        public InnerZooKeeper(String zookeeperName, int clientPort) {
+            this.zookeeperName = zookeeperName;
+            this.clientPort = clientPort;
+        }
+
+        /**
+         * Returns the port that clients should use to connect to this embedded server.
+         *
+         * @return dynamically determined client port
+         */
+        public int getClientPort() {
+            return this.clientPort;
+        }
+
+        /**
+         * Checks if the zookeeper server is running.
+         */
+        public boolean isRunning() {
+            return (zkServerThread != null);
+        }
+
+        /**
+         * Start the ZooKeeper server in a background thread.
+         * <p>
+         * any exceptions thrown during startup or execution.
+         */
+        private synchronized void start() {
+            if (zkServerThread == null) {
+                zkServerThread = new Thread(() -> {
+                    try {
+                        Properties properties = new Properties();
+                        File file = new File(System.getProperty("java.io.tmpdir")
+                            + File.separator + UUID.randomUUID());
+                        file.deleteOnExit();
+                        properties.setProperty("dataDir", file.getAbsolutePath());
+                        properties.setProperty("clientPort", String.valueOf(clientPort));
+
+                        QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig();
+                        quorumPeerConfig.parseProperties(properties);
+
+                        zkServer = new ZooKeeperServerMain();
+                        ServerConfig configuration = new ServerConfig();
+                        configuration.readFrom(quorumPeerConfig);
+
+                        zkServer.runFromConfig(configuration);
+                    } catch (Exception e) {
+                        logger.error("Exception running embedded ZooKeeper", e);
+                    }
+                }, zookeeperName);
+                zkServerThread.setDaemon(true);
+                zkServerThread.start();
+            }
+        }
+
+        /**
+         * Shutdown the ZooKeeper server.
+         */
+        private synchronized void shutdown() {
+            if (zkServerThread != null) {
+                // The shutdown method is protected...thus this hack to invoke it.
+                // This will log an exception on shutdown; see
+                // https://issues.apache.org/jira/browse/ZOOKEEPER-1873 for details.
+                try {
+                    Method shutdown = ZooKeeperServerMain.class.getDeclaredMethod("shutdown");
+                    shutdown.setAccessible(true);
+                    shutdown.invoke(zkServer);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+
+                // It is expected that the thread will exit after
+                // the server is shutdown; this will block until
+                // the shutdown is complete.
+                try {
+                    zkServerThread.join(5000);
+                    zkServerThread = null;
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    logger.warn("Interrupted while waiting for embedded ZooKeeper to exit");
+                    // abandoning zk thread
+                    zkServerThread = null;
+                }
+            }
+        }
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmExporterListener.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmExporterListener.java
new file mode 100644
index 0000000..1820a12
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmExporterListener.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.integration.multiple.injvm;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.integration.AbstractRegistryCenterExporterListener;
+
+@Activate(group = CommonConstants.PROVIDER, order = 1000)
+public class MultipleRegistryCenterInjvmExporterListener extends AbstractRegistryCenterExporterListener {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Class<?> getInterface() {
+        return MultipleRegistryCenterInjvmService.class;
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/InjvmFilter.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmFilter.java
similarity index 85%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/InjvmFilter.java
copy to dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmFilter.java
index cb45038..658924d 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/InjvmFilter.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmFilter.java
@@ -14,18 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.integration.single.injvm;
+package org.apache.dubbo.integration.multiple.injvm;
 
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.common.extension.Activate;
-import org.apache.dubbo.rpc.Filter;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.*;
 
-@Activate(group = CommonConstants.PROVIDER, order = 10000)
-public class InjvmFilter implements Filter,Filter.Listener {
+@Activate(group = CommonConstants.PROVIDER, order = 10200)
+public class MultipleRegistryCenterInjvmFilter implements Filter,Filter.Listener{
 
     /**
      * The filter is called or not
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmIntegrationTest.java
similarity index 67%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java
copy to dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmIntegrationTest.java
index 052f9dd..815c759 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmIntegrationTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.integration.single.injvm;
+package org.apache.dubbo.integration.multiple.injvm;
 
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.config.ServiceConfig;
@@ -25,15 +25,13 @@ import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.integration.IntegrationTest;
-import org.apache.dubbo.integration.single.SingleZooKeeperServer;
-import org.apache.dubbo.integration.single.listener.InjvmExporterListener;
-import org.apache.dubbo.integration.single.listener.InjvmServiceListener;
+import org.apache.dubbo.integration.multiple.MultipleZooKeeperServer;
+import org.apache.dubbo.integration.single.injvm.SingleRegistryCenterInjvmService;
 import org.apache.dubbo.rpc.ExporterListener;
 import org.apache.dubbo.rpc.Filter;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,59 +42,59 @@ import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
 /**
  * The testcases are only for checking the process of exporting provider using injvm protocol.
  */
-public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest {
+public class MultipleRegistryCenterInjvmIntegrationTest implements IntegrationTest {
 
-    private static final Logger logger = LoggerFactory.getLogger(SingleRegistryCenterInjvmIntegrationTest.class);
+    private static final Logger logger = LoggerFactory.getLogger(MultipleRegistryCenterInjvmIntegrationTest.class);
 
     /**
      * Define the provider application name.
      */
-    private static String PROVIDER_APPLICATION_NAME = "single-registry-center-provider-for-injvm-protocol";
+    private static String PROVIDER_APPLICATION_NAME = "multiple-registry-center-provider-for-injvm-protocol";
 
     /**
      * The name for getting the specified instance, which is loaded using SPI.
      */
-    private static String SPI_NAME = "singleConfigCenterInjvm";
+    private static String SPI_NAME = "multipleConfigCenterInjvm";
+
     /**
      * Define the {@link ServiceConfig} instance.
      */
-    private ServiceConfig<SingleRegistryCenterInjvmService> serviceConfig;
+    private ServiceConfig<MultipleRegistryCenterInjvmService> serviceConfig;
 
     /**
      * The listener to record exported services
      */
-    private InjvmServiceListener serviceListener;
+    private MultipleRegistryCenterInjvmServiceListener serviceListener;
 
     /**
      * The listener to record exported exporters.
      */
-    private InjvmExporterListener exporterListener;
+    private MultipleRegistryCenterInjvmExporterListener exporterListener;
 
     /**
      * The filter for checking filter chain.
      */
-    private InjvmFilter filter;
+    private MultipleRegistryCenterInjvmFilter filter;
 
     @BeforeEach
     public void setUp() throws Exception {
         logger.info(getClass().getSimpleName() + " testcase is beginning...");
         DubboBootstrap.reset();
-        //start zookeeper only once
-        logger.info(SingleZooKeeperServer.getZookeeperServerName() + " is beginning to start...");
-        SingleZooKeeperServer.start();
-        logger.info(SingleZooKeeperServer.getZookeeperServerName() + " has started.");
+        //start all zookeeper services only once
+        MultipleZooKeeperServer.start();
 
         // initialize service config
-        serviceConfig = new ServiceConfig<SingleRegistryCenterInjvmService>();
-        serviceConfig.setInterface(SingleRegistryCenterInjvmService.class);
-        serviceConfig.setRef(new SingleRegistryCenterInjvmServiceImpl());
+        serviceConfig = new ServiceConfig<>();
+        serviceConfig.setInterface(MultipleRegistryCenterInjvmService.class);
+        serviceConfig.setRef(new MultipleRegistryCenterInjvmServiceImpl());
         serviceConfig.setAsync(false);
         serviceConfig.setScope(SCOPE_LOCAL);
 
         // initailize bootstrap
         DubboBootstrap.getInstance()
             .application(new ApplicationConfig(PROVIDER_APPLICATION_NAME))
-            .registry(new RegistryConfig("N/A"))
+            .registry(new RegistryConfig("zookeeper://127.0.0.1:" + MultipleZooKeeperServer.getPortOne()))
+            .registry(new RegistryConfig("zookeeper://127.0.0.1:" + MultipleZooKeeperServer.getPortTwo()))
             .protocol(new ProtocolConfig("injvm"))
             .service(serviceConfig);
     }
@@ -113,9 +111,9 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
      */
     private void beforeExport() {
         // ---------------initialize--------------- //
-        serviceListener = (InjvmServiceListener) ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension(SPI_NAME);
-        exporterListener = (InjvmExporterListener) ExtensionLoader.getExtensionLoader(ExporterListener.class).getExtension(SPI_NAME);
-        filter = (InjvmFilter) ExtensionLoader.getExtensionLoader(Filter.class).getExtension(SPI_NAME);
+        serviceListener = (MultipleRegistryCenterInjvmServiceListener) ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension(SPI_NAME);
+        exporterListener = (MultipleRegistryCenterInjvmExporterListener) ExtensionLoader.getExtensionLoader(ExporterListener.class).getExtension(SPI_NAME);
+        filter = (MultipleRegistryCenterInjvmFilter) ExtensionLoader.getExtensionLoader(Filter.class).getExtension(SPI_NAME);
 
         // ---------------checkpoints--------------- //
         // There is nothing in ServiceListener
@@ -129,7 +127,6 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
     /**
      * {@inheritDoc}
      */
-    @Test
     @Override
     public void integrate() {
         beforeExport();
@@ -139,7 +136,7 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
         referenceConfig.setInterface(SingleRegistryCenterInjvmService.class);
         referenceConfig.setBootstrap(DubboBootstrap.getInstance());
         referenceConfig.setScope(SCOPE_LOCAL);
-        referenceConfig.get().hello("Dubbo");
+        referenceConfig.get().hello("Dubbo in multiple registry center");
         afterInvoke();
     }
 
@@ -147,41 +144,42 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
      * There are some checkpoints need to check after exported as follow:
      * <ul>
      *     <li>The exported service is only one or not</li>
-     *     <li>The exported service is SingleRegistryCenterInjvmService or not</li>
-     *     <li>The SingleRegistryCenterInjvmService is exported or not</li>
+     *     <li>The exported service is MultipleRegistryCenterInjvmService or not</li>
+     *     <li>The MultipleRegistryCenterInjvmService is exported or not</li>
      *     <li>The exported exporter is only one or not</li>
-     *     <li>The exported exporter contains InjvmFilter or not</li>
+     *     <li>The exported exporter contains MultipleRegistryCenterInjvmFilter or not</li>
      * </ul>
      */
     private void afterExport() {
         // The exported service is only one
         Assertions.assertEquals(serviceListener.getExportedServices().size(),1);
-        // The exported service is SingleRegistryCenterInjvmService
+        // The exported service is MultipleRegistryCenterInjvmService
         Assertions.assertEquals(serviceListener.getExportedServices().get(0).getInterfaceClass(),
-            SingleRegistryCenterInjvmService.class);
-        // The SingleRegistryCenterInjvmService is exported
+            MultipleRegistryCenterInjvmService.class);
+        // The MultipleRegistryCenterInjvmService is exported
         Assertions.assertTrue(serviceListener.getExportedServices().get(0).isExported());
         // The exported exporter is only one
         Assertions.assertEquals(exporterListener.getExportedExporters().size(),1);
-        // The exported exporter contains InjvmFilter
+        // The exported exporter contains MultipleRegistryCenterInjvmFilter
         Assertions.assertTrue(exporterListener.getFilters().contains(filter));
     }
 
     /**
      * There are some checkpoints need to check after invoked as follow:
      * <ul>
-     *     <li>The InjvmFilter has called or not</li>
-     *     <li>The InjvmFilter exists error after invoked</li>
-     *     <li>The InjvmFilter's response is right or not</li>
+     *     <li>The MultipleRegistryCenterInjvmFilter has called or not</li>
+     *     <li>The MultipleRegistryCenterInjvmFilter exists error after invoked</li>
+     *     <li>The MultipleRegistryCenterInjvmFilter's response is right or not</li>
      * </ul>
      */
     private void afterInvoke(){
-        // The InjvmFilter has called
+        // The MultipleRegistryCenterInjvmFilter has called
         Assertions.assertTrue(filter.hasCalled());
-        // The InjvmFilter doesn't exist error
+        // The MultipleRegistryCenterInjvmFilter doesn't exist error
         Assertions.assertFalse(filter.hasError());
-        // Check the InjvmFilter's response
-        Assertions.assertEquals("Hello Dubbo",filter.getResponse());
+        // Check the MultipleRegistryCenterInjvmFilter's response
+        Assertions.assertEquals("Hello Dubbo in multiple registry center",
+            filter.getResponse());
     }
 
     @AfterEach
@@ -194,8 +192,6 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
         serviceListener = null;
         logger.info(getClass().getSimpleName() + " testcase is ending...");
         // destroy zookeeper only once
-        logger.info(SingleZooKeeperServer.getZookeeperServerName() + " is beginning to shutdown...");
-        SingleZooKeeperServer.shutdown();
-        logger.info(SingleZooKeeperServer.getZookeeperServerName() + " has shutdown.");
+        MultipleZooKeeperServer.shutdown();
     }
 }
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmService.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmService.java
new file mode 100644
index 0000000..fba0451
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmService.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.integration.multiple.injvm;
+/**
+ * This interface is used to check if the exported injvm protocol works well or not.
+ */
+public interface MultipleRegistryCenterInjvmService {
+    /**
+     * The simple method for testing.
+     */
+    String hello(String name);
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmServiceImpl.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmServiceImpl.java
new file mode 100644
index 0000000..f04a5ea
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmServiceImpl.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.integration.multiple.injvm;
+
+/**
+ * The simple implementation for {@link MultipleRegistryCenterInjvmService}
+ */
+public class MultipleRegistryCenterInjvmServiceImpl implements MultipleRegistryCenterInjvmService {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String hello(String name) {
+        return null;
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmServiceListener.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmServiceListener.java
new file mode 100644
index 0000000..766fa18
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmServiceListener.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.integration.multiple.injvm;
+
+import org.apache.dubbo.config.ServiceListener;
+import org.apache.dubbo.integration.AbstractRegistryCenterServiceListener;
+
+/**
+ * This implementation of {@link ServiceListener} is to record exported services with injvm protocol in multiple registry center.
+ */
+public class MultipleRegistryCenterInjvmServiceListener extends AbstractRegistryCenterServiceListener {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Class<?> getInterface() {
+        return MultipleRegistryCenterInjvmService.class;
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/package-info.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/package-info.java
new file mode 100644
index 0000000..c186c7d
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * There are two scenario in integration testcases.<p>
+ * The one is single registry center, the other is multiple registry centers.<p>
+ * The purpose of all of testcases in this package is to test for multiple registry center.
+ */
+package org.apache.dubbo.integration.multiple;
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java
index 079b040..fa62302 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java
@@ -27,9 +27,7 @@ import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.ServiceListener;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.integration.IntegrationTest;
-import org.apache.dubbo.integration.single.listener.ExportedServiceListener;
 import org.apache.dubbo.metadata.MetadataInfo;
-import org.apache.dubbo.metadata.MetadataService;
 import org.apache.dubbo.metadata.WritableMetadataService;
 import org.apache.dubbo.registry.ListenerRegistryWrapper;
 import org.apache.dubbo.registry.Registry;
@@ -96,9 +94,9 @@ public class SingleRegistryCenterDubboProtocolIntegrationTest implements Integra
     private SingleRegistryCenterIntegrationService singleRegistryCenterIntegrationService;
 
     /**
-     * Define the {@link ExportedServiceListener} instance to obtain the exported services.
+     * Define the {@link SingleRegistryCenterExportedServiceListener} instance to obtain the exported services.
      */
-    private ExportedServiceListener exportedServiceListener;
+    private SingleRegistryCenterExportedServiceListener singleRegistryCenterExportedServiceListener;
 
     @BeforeEach
     public void setUp() throws Exception {
@@ -162,7 +160,7 @@ public class SingleRegistryCenterDubboProtocolIntegrationTest implements Integra
         // DubboBootstrap is shutdown or not
         Assertions.assertFalse(DubboBootstrap.getInstance().isShutdown());
         // The ServiceListener is loaded by SPI or not
-        Assertions.assertNull(exportedServiceListener);
+        Assertions.assertNull(singleRegistryCenterExportedServiceListener);
     }
 
     /**
@@ -263,26 +261,17 @@ public class SingleRegistryCenterDubboProtocolIntegrationTest implements Integra
         // The matchKey of MetadataInfo's service is right or not
         Assertions.assertEquals(serviceInfo.getMatchKey(), key);
         // The exported services are right or not
-        // 1. The exported service must contain SingleRegistryCenterIntegrationService and MetadataService
+        // 1. The exported service must contain SingleRegistryCenterIntegrationService
         // 2. The exported service's interface must be SingleRegistryCenterIntegrationService.class
-        // 3. All exported service must be exported
-        exportedServiceListener = (ExportedServiceListener) ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension("exported");
-        Assertions.assertNotNull(exportedServiceListener);
-        Assertions.assertEquals(exportedServiceListener.getExportedServices().size(), 2);
-        ServiceConfig singleRegistryCenterServiceConfig = null;
-        ServiceConfig metadataServiceServiceConfig = null;
-        for (ServiceConfig exportedServiceConfig: exportedServiceListener.getExportedServices()) {
-            if(exportedServiceConfig.getInterfaceClass() == SingleRegistryCenterIntegrationService.class){
-                singleRegistryCenterServiceConfig = exportedServiceConfig;
-            }
-            if(exportedServiceConfig.getInterfaceClass() == MetadataService.class){
-                metadataServiceServiceConfig = exportedServiceConfig;
-            }
-        }
+        // 3. All exported services must be exported
+        singleRegistryCenterExportedServiceListener = (SingleRegistryCenterExportedServiceListener) ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension("exported");
+        Assertions.assertNotNull(singleRegistryCenterExportedServiceListener);
+        Assertions.assertEquals(singleRegistryCenterExportedServiceListener.getExportedServices().size(), 1);
+        Assertions.assertEquals(SingleRegistryCenterIntegrationService.class,
+            singleRegistryCenterExportedServiceListener.getExportedServices().get(0).getInterfaceClass());
+        ServiceConfig singleRegistryCenterServiceConfig = singleRegistryCenterExportedServiceListener.getExportedServices().get(0);
         Assertions.assertNotNull(singleRegistryCenterServiceConfig);
-        Assertions.assertNotNull(metadataServiceServiceConfig);
         Assertions.assertTrue(singleRegistryCenterServiceConfig.isExported());
-        Assertions.assertTrue(metadataServiceServiceConfig.isExported());
     }
 
     /**
@@ -395,8 +384,8 @@ public class SingleRegistryCenterDubboProtocolIntegrationTest implements Integra
         serviceConfig = null;
         referenceConfig = null;
         // The exported service has been unexported
-        Assertions.assertTrue(exportedServiceListener.getExportedServices().isEmpty());
-        exportedServiceListener = null;
+        Assertions.assertTrue(singleRegistryCenterExportedServiceListener.getExportedServices().isEmpty());
+        singleRegistryCenterExportedServiceListener = null;
         logger.info(getClass().getSimpleName() + " testcase is ending...");
         // destroy zookeeper only once
         logger.info(SingleZooKeeperServer.getZookeeperServerName() + " is beginning to shutdown...");
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/SingleRegistryCenterExportedServiceListener.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/SingleRegistryCenterExportedServiceListener.java
new file mode 100644
index 0000000..37a733a
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/SingleRegistryCenterExportedServiceListener.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.integration.single;
+
+import org.apache.dubbo.config.ServiceListener;
+import org.apache.dubbo.integration.AbstractRegistryCenterServiceListener;
+
+/**
+ * This implementation of {@link ServiceListener} is to record exported services in single registry center.
+ */
+public class SingleRegistryCenterExportedServiceListener extends AbstractRegistryCenterServiceListener {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Class<?> getInterface() {
+        return SingleRegistryCenterIntegrationService.class;
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmExporterListener.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmExporterListener.java
new file mode 100644
index 0000000..4edec5f
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmExporterListener.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.integration.single.injvm;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.integration.AbstractRegistryCenterExporterListener;
+
+@Activate(group = CommonConstants.PROVIDER, order = 1000)
+public class SingleRegistryCenterInjvmExporterListener extends AbstractRegistryCenterExporterListener {
+
+    /**
+     * Returns the interface of exported service.
+     */
+    @Override
+    protected Class<?> getInterface() {
+        return SingleRegistryCenterInjvmService.class;
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/InjvmFilter.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmFilter.java
similarity index 96%
rename from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/InjvmFilter.java
rename to dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmFilter.java
index cb45038..a27a7b9 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/InjvmFilter.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmFilter.java
@@ -25,7 +25,7 @@ import org.apache.dubbo.rpc.RpcException;
 import org.apache.dubbo.rpc.Result;
 
 @Activate(group = CommonConstants.PROVIDER, order = 10000)
-public class InjvmFilter implements Filter,Filter.Listener {
+public class SingleRegistryCenterInjvmFilter implements Filter,Filter.Listener {
 
     /**
      * The filter is called or not
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java
index 052f9dd..429da7b 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java
@@ -26,8 +26,6 @@ import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.integration.IntegrationTest;
 import org.apache.dubbo.integration.single.SingleZooKeeperServer;
-import org.apache.dubbo.integration.single.listener.InjvmExporterListener;
-import org.apache.dubbo.integration.single.listener.InjvmServiceListener;
 import org.apache.dubbo.rpc.ExporterListener;
 import org.apache.dubbo.rpc.Filter;
 import org.junit.jupiter.api.AfterEach;
@@ -65,17 +63,17 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
     /**
      * The listener to record exported services
      */
-    private InjvmServiceListener serviceListener;
+    private SingleRegistryCenterInjvmServiceListener serviceListener;
 
     /**
      * The listener to record exported exporters.
      */
-    private InjvmExporterListener exporterListener;
+    private SingleRegistryCenterInjvmExporterListener exporterListener;
 
     /**
      * The filter for checking filter chain.
      */
-    private InjvmFilter filter;
+    private SingleRegistryCenterInjvmFilter filter;
 
     @BeforeEach
     public void setUp() throws Exception {
@@ -87,7 +85,7 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
         logger.info(SingleZooKeeperServer.getZookeeperServerName() + " has started.");
 
         // initialize service config
-        serviceConfig = new ServiceConfig<SingleRegistryCenterInjvmService>();
+        serviceConfig = new ServiceConfig<>();
         serviceConfig.setInterface(SingleRegistryCenterInjvmService.class);
         serviceConfig.setRef(new SingleRegistryCenterInjvmServiceImpl());
         serviceConfig.setAsync(false);
@@ -96,7 +94,7 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
         // initailize bootstrap
         DubboBootstrap.getInstance()
             .application(new ApplicationConfig(PROVIDER_APPLICATION_NAME))
-            .registry(new RegistryConfig("N/A"))
+            .registry(new RegistryConfig("zookeeper://127.0.0.1:" + SingleZooKeeperServer.getPort()))
             .protocol(new ProtocolConfig("injvm"))
             .service(serviceConfig);
     }
@@ -113,9 +111,9 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
      */
     private void beforeExport() {
         // ---------------initialize--------------- //
-        serviceListener = (InjvmServiceListener) ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension(SPI_NAME);
-        exporterListener = (InjvmExporterListener) ExtensionLoader.getExtensionLoader(ExporterListener.class).getExtension(SPI_NAME);
-        filter = (InjvmFilter) ExtensionLoader.getExtensionLoader(Filter.class).getExtension(SPI_NAME);
+        serviceListener = (SingleRegistryCenterInjvmServiceListener) ExtensionLoader.getExtensionLoader(ServiceListener.class).getExtension(SPI_NAME);
+        exporterListener = (SingleRegistryCenterInjvmExporterListener) ExtensionLoader.getExtensionLoader(ExporterListener.class).getExtension(SPI_NAME);
+        filter = (SingleRegistryCenterInjvmFilter) ExtensionLoader.getExtensionLoader(Filter.class).getExtension(SPI_NAME);
 
         // ---------------checkpoints--------------- //
         // There is nothing in ServiceListener
@@ -150,7 +148,7 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
      *     <li>The exported service is SingleRegistryCenterInjvmService or not</li>
      *     <li>The SingleRegistryCenterInjvmService is exported or not</li>
      *     <li>The exported exporter is only one or not</li>
-     *     <li>The exported exporter contains InjvmFilter or not</li>
+     *     <li>The exported exporter contains SingleRegistryCenterInjvmFilter or not</li>
      * </ul>
      */
     private void afterExport() {
@@ -163,24 +161,24 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
         Assertions.assertTrue(serviceListener.getExportedServices().get(0).isExported());
         // The exported exporter is only one
         Assertions.assertEquals(exporterListener.getExportedExporters().size(),1);
-        // The exported exporter contains InjvmFilter
+        // The exported exporter contains SingleRegistryCenterInjvmFilter
         Assertions.assertTrue(exporterListener.getFilters().contains(filter));
     }
 
     /**
      * There are some checkpoints need to check after invoked as follow:
      * <ul>
-     *     <li>The InjvmFilter has called or not</li>
-     *     <li>The InjvmFilter exists error after invoked</li>
-     *     <li>The InjvmFilter's response is right or not</li>
+     *     <li>The SingleRegistryCenterInjvmFilter has called or not</li>
+     *     <li>The SingleRegistryCenterInjvmFilter exists error after invoked</li>
+     *     <li>The SingleRegistryCenterInjvmFilter's response is right or not</li>
      * </ul>
      */
     private void afterInvoke(){
-        // The InjvmFilter has called
+        // The SingleRegistryCenterInjvmFilter has called
         Assertions.assertTrue(filter.hasCalled());
-        // The InjvmFilter doesn't exist error
+        // The SingleRegistryCenterInjvmFilter doesn't exist error
         Assertions.assertFalse(filter.hasError());
-        // Check the InjvmFilter's response
+        // Check the SingleRegistryCenterInjvmFilter's response
         Assertions.assertEquals("Hello Dubbo",filter.getResponse());
     }
 
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmServiceListener.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmServiceListener.java
new file mode 100644
index 0000000..b1ff898
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmServiceListener.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.integration.single.injvm;
+
+import org.apache.dubbo.config.ServiceListener;
+import org.apache.dubbo.integration.AbstractRegistryCenterServiceListener;
+
+/**
+ * This implementation of {@link ServiceListener} is to record exported services with injvm protocol in single registry center.
+ */
+public class SingleRegistryCenterInjvmServiceListener extends AbstractRegistryCenterServiceListener {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Class<?> getInterface() {
+        return SingleRegistryCenterInjvmService.class;
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/listener/ExportedServiceListener.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/listener/ExportedServiceListener.java
deleted file mode 100644
index a8bf95b..0000000
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/listener/ExportedServiceListener.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.integration.single.listener;
-
-import org.apache.dubbo.config.ServiceConfig;
-import org.apache.dubbo.config.ServiceListener;
-import org.apache.dubbo.integration.single.SingleRegistryCenterIntegrationService;
-import org.apache.dubbo.metadata.MetadataService;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.ArrayList;
-
-/**
- * This implementation of {@link ServiceListener} is to record exported services
- */
-public class ExportedServiceListener implements ServiceListener {
-
-    private List<ServiceConfig> exportedServices = new ArrayList<>(2);
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void exported(ServiceConfig sc) {
-        //All exported services will be added
-        if(sc.getInterfaceClass()== MetadataService.class ||
-        sc.getInterfaceClass() == SingleRegistryCenterIntegrationService.class){
-            exportedServices.add(sc);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void unexported(ServiceConfig sc) {
-        //remove the exported services.
-        exportedServices.remove(sc);
-    }
-
-    /**
-     * Return all exported services.
-     */
-    public List<ServiceConfig> getExportedServices(){
-        return Collections.unmodifiableList(exportedServices);
-    }
-}
diff --git a/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.config.ServiceListener b/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.config.ServiceListener
index aac2dca..b7e2dab 100644
--- a/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.config.ServiceListener
+++ b/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.config.ServiceListener
@@ -1,3 +1,4 @@
 mock=org.apache.dubbo.config.mock.MockServiceListener
-exported=org.apache.dubbo.integration.single.listener.ExportedServiceListener
-singleConfigCenterInjvm=org.apache.dubbo.integration.single.listener.InjvmServiceListener
+exported=org.apache.dubbo.integration.single.SingleRegistryCenterExportedServiceListener
+singleConfigCenterInjvm=org.apache.dubbo.integration.single.injvm.SingleRegistryCenterInjvmServiceListener
+multipleConfigCenterInjvm=org.apache.dubbo.integration.multiple.injvm.MultipleRegistryCenterInjvmServiceListener
diff --git a/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.ExporterListener b/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.ExporterListener
index 1b9f72d..51f85f7 100644
--- a/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.ExporterListener
+++ b/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.ExporterListener
@@ -16,4 +16,5 @@
 #
 
 mockexporterlistener=org.apache.dubbo.config.mock.MockExporterListener
-singleConfigCenterInjvm=org.apache.dubbo.integration.single.listener.InjvmExporterListener
+singleConfigCenterInjvm=org.apache.dubbo.integration.single.injvm.SingleRegistryCenterInjvmExporterListener
+multipleConfigCenterInjvm=org.apache.dubbo.integration.multiple.injvm.MultipleRegistryCenterInjvmExporterListener
diff --git a/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.Filter b/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.Filter
index ea35520..9bf8f99 100644
--- a/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.Filter
+++ b/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.rpc.Filter
@@ -1,2 +1,3 @@
 mockfilter=org.apache.dubbo.config.mock.MockFilter
-singleConfigCenterInjvm=org.apache.dubbo.integration.single.injvm.InjvmFilter
+singleConfigCenterInjvm=org.apache.dubbo.integration.single.injvm.SingleRegistryCenterInjvmFilter
+multipleConfigCenterInjvm=org.apache.dubbo.integration.multiple.injvm.MultipleRegistryCenterInjvmFilter