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/15 14:33:02 UTC
[dubbo] branch 3.0 updated: test: verify service-discovery-registry
protocol in multiple registry center (#8493)
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 d89aa89 test: verify service-discovery-registry protocol in multiple registry center (#8493)
d89aa89 is described below
commit d89aa89ba0711cd8fa5a8b760a7c78de371bb51b
Author: Xiong, Pin <pi...@foxmail.com>
AuthorDate: Sun Aug 15 09:32:42 2021 -0500
test: verify service-discovery-registry protocol in multiple registry center (#8493)
1. Check ServiceDiscoveryRegistry
2. Check InMemoryWritableMetadataService
3. Define a SPI for RegistryServiceListener
---
.../integration/multiple/AbstractStorage.java | 82 ++++++++
.../apache/dubbo/integration/multiple/Storage.java | 58 ++++++
...terServiceDiscoveryRegistryIntegrationTest.java | 220 +++++++++++++++++++++
...ceDiscoveryRegistryRegistryServiceListener.java | 103 ++++++++++
...istryCenterServiceDiscoveryRegistryService.java | 26 +++
...yCenterServiceDiscoveryRegistryServiceImpl.java | 29 +++
.../ServiceDiscoveryRegistryInfoWrapper.java | 82 ++++++++
.../ServiceDiscoveryRegistryStorage.java | 26 +++
...RegistryCenterDubboProtocolIntegrationTest.java | 3 -
...g.apache.dubbo.registry.RegistryServiceListener | 18 ++
10 files changed, 644 insertions(+), 3 deletions(-)
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/AbstractStorage.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/AbstractStorage.java
new file mode 100644
index 0000000..7a0b938
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/AbstractStorage.java
@@ -0,0 +1,82 @@
+/*
+ * 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 java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This abstraction class to implement the basic methods for {@link Storage}.
+ *
+ * @param <T> The type to store
+ */
+public abstract class AbstractStorage<T> implements Storage<T> {
+
+ private Map<String, T> storage = new ConcurrentHashMap<>();
+
+
+ /**
+ * Generate the key for storage
+ *
+ * @param host the host in the register center.
+ * @param port the port in the register center.
+ * @return the generated key with the given host and port.
+ */
+ private String generateKey(String host, int port) {
+ return String.format("%s:%d", host, port);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public T get(String host, int port) {
+ return storage.get(generateKey(host, port));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void put(String host, int port, T value) {
+ storage.put(generateKey(host, port), value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean contains(String host, int port) {
+ return storage.containsKey(generateKey(host, port));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int size() {
+ return storage.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clear() {
+ storage.clear();
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/Storage.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/Storage.java
new file mode 100644
index 0000000..064289c
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/Storage.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+/**
+ * This interface to store the given type instance in multiple registry center.
+ * @param <T> The type to store
+ */
+public interface Storage <T>{
+
+ /**
+ * Gets the stored instance with the given host and port.
+ * @param host the host in the register center.
+ * @param port the port in the register center.
+ * @return the stored instance.
+ */
+ T get(String host, int port);
+
+ /**
+ * Sets the stored instance with the given host and port as key.
+ * @param host the host in the register center.
+ * @param port the port in the register center.
+ * @param value the instance to store.
+ */
+ void put(String host, int port, T value);
+
+ /**
+ * Checks if the instance exists with the given host and port.
+ * @param host the host in the register center.
+ * @param port the port in the register center.
+ * @return {@code true} if the instance exists with the given host and port, otherwise {@code false}
+ */
+ boolean contains(String host, int port);
+
+ /**
+ * Returns the size of all stored values.
+ */
+ int size();
+
+ /**
+ * Clear all data.
+ */
+ void clear();
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest.java
new file mode 100644
index 0000000..b493812
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest.java
@@ -0,0 +1,220 @@
+/*
+ * 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.servicediscoveryregistry;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.config.*;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.integration.IntegrationTest;
+import org.apache.dubbo.integration.multiple.injvm.*;
+import org.apache.dubbo.registry.RegistryServiceListener;
+import org.apache.dubbo.registry.client.metadata.store.InMemoryWritableMetadataService;
+import org.apache.dubbo.registrycenter.DefaultMultipleRegistryCenter;
+import org.apache.dubbo.registrycenter.MultipleRegistryCenter;
+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;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
+
+/**
+ * The testcases are only for checking the process of exporting provider using service-discovery-registry protocol.
+ */
+public class MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest implements IntegrationTest {
+
+ private static final Logger logger = LoggerFactory.getLogger(MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest.class);
+
+ /**
+ * Define the provider application name.
+ */
+ public static String PROVIDER_APPLICATION_NAME = "multiple-registry-center-provider-for-service-discovery-registry-protocol";
+
+ /**
+ * The name for getting the specified instance, which is loaded using SPI.
+ */
+ private static String SPI_NAME = "multipleConfigCenterServiceDiscoveryRegistry";
+
+ /**
+ * Define the protocol's name.
+ */
+ private static String PROTOCOL_NAME = CommonConstants.DUBBO;
+ /**
+ * Define the protocol's port.
+ */
+ private static int PROTOCOL_PORT = 20880;
+
+ /**
+ * Define the {@link ServiceConfig} instance.
+ */
+ private ServiceConfig<MultipleRegistryCenterServiceDiscoveryRegistryService> serviceConfig;
+
+ /**
+ * Default a registry center.
+ */
+ private MultipleRegistryCenter registryCenter;
+
+ /**
+ * Define a {@link RegistryServiceListener} instance.
+ */
+ private MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener registryServiceListener;
+
+ /**
+ * The localhost.
+ */
+ private static String HOST = "127.0.0.1";
+
+ /**
+ * The port of register center.
+ */
+ private Set<Integer> ports = new HashSet<>(2);
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ logger.info(getClass().getSimpleName() + " testcase is beginning...");
+ DubboBootstrap.reset();
+ //start all zookeeper services only once
+ registryCenter = new DefaultMultipleRegistryCenter();
+ registryCenter.startup();
+ // initialize service config
+ serviceConfig = new ServiceConfig<>();
+ serviceConfig.setInterface(MultipleRegistryCenterServiceDiscoveryRegistryService.class);
+ serviceConfig.setRef(new MultipleRegistryCenterServiceDiscoveryRegistryServiceImpl());
+ serviceConfig.setAsync(false);
+
+ // initailize bootstrap
+ for (RegistryConfig registryConfig : registryCenter.getRegistryConfigs()) {
+ DubboBootstrap.getInstance().registry(registryConfig);
+ ports.add(registryConfig.getPort());
+ }
+ DubboBootstrap.getInstance()
+ .application(new ApplicationConfig(PROVIDER_APPLICATION_NAME))
+ .protocol(new ProtocolConfig(PROTOCOL_NAME, PROTOCOL_PORT))
+ .service(serviceConfig);
+ // ---------------initialize--------------- //
+ registryServiceListener = (MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener) ExtensionLoader
+ .getExtensionLoader(RegistryServiceListener.class).getExtension(SPI_NAME);
+ // RegistryServiceListener is not null
+ Assertions.assertNotNull(registryServiceListener);
+ registryServiceListener.getStorage().clear();
+
+ }
+
+ /**
+ * Define a {@link RegistryServiceListener} for helping check.<p>
+ * There are some checkpoints need to verify as follow:
+ * <ul>
+ * <li>ServiceConfig is exported or not</li>
+ * <li>ServiceDiscoveryRegistryStorage is empty or not</li>
+ * </ul>
+ */
+ private void beforeExport() {
+ // ---------------checkpoints--------------- //
+ // ServiceConfig isn't exported
+ Assertions.assertFalse(serviceConfig.isExported());
+
+ // ServiceDiscoveryRegistryStorage is empty
+ Assertions.assertEquals(registryServiceListener.getStorage().size(),0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Test
+ @Override
+ public void integrate() {
+ beforeExport();
+ DubboBootstrap.getInstance().start();
+ afterExport();
+ ReferenceConfig<MultipleRegistryCenterServiceDiscoveryRegistryService> referenceConfig = new ReferenceConfig<>();
+ referenceConfig.setInterface(MultipleRegistryCenterServiceDiscoveryRegistryService.class);
+ referenceConfig.setBootstrap(DubboBootstrap.getInstance());
+ referenceConfig.get().hello("Dubbo in multiple registry center");
+ afterInvoke();
+ }
+
+ /**
+ * There are some checkpoints need to check after exported as follow:
+ * <ul>
+ * <li>ServiceDiscoveryRegistry is right or not</li>
+ * <li>All register center has been registered and subscribed</li>
+ * </ul>
+ */
+ private void afterExport() {
+ // ServiceDiscoveryRegistry is not null
+ Assertions.assertEquals(registryServiceListener.getStorage().size(),2);
+ // All register center has been registered and subscribed
+ for (int port: ports){
+ Assertions.assertTrue(registryServiceListener.getStorage().contains(HOST,port));
+ ServiceDiscoveryRegistryInfoWrapper serviceDiscoveryRegistryInfoWrapper = registryServiceListener.getStorage().get(HOST,port);
+ // check if it's registered
+ Assertions.assertTrue(serviceDiscoveryRegistryInfoWrapper.isRegistered());
+ // check if it's subscribed
+ Assertions.assertTrue(serviceDiscoveryRegistryInfoWrapper.isSubscribed());
+ InMemoryWritableMetadataService inMemoryWritableMetadataService = serviceDiscoveryRegistryInfoWrapper.getInMemoryWritableMetadataService();
+ // check if the count of exported urls is right or not
+ Assertions.assertEquals(inMemoryWritableMetadataService.getExportedURLs().size(),1);
+ // check the exported url is right or not.
+ Assertions.assertTrue(inMemoryWritableMetadataService.getExportedURLs()
+ .first()
+ .contains(MultipleRegistryCenterServiceDiscoveryRegistryService.class.getName()));
+ // check the count of metadatainfo is right or not.
+ Assertions.assertEquals(inMemoryWritableMetadataService.getMetadataInfos().size(),1);
+ }
+ }
+
+ /**
+ * There are some checkpoints need to check after invoked as follow:
+ */
+ private void afterInvoke() {
+
+ }
+
+ @AfterEach
+ public void tearDown() throws IOException {
+ DubboBootstrap.reset();
+ PROVIDER_APPLICATION_NAME = null;
+ serviceConfig = null;
+ // TODO: we need to check whether this scenario is normal
+ // TODO: the Exporter and ServiceDiscoveryRegistry are same in multiple registry center
+ /*
+ for (int port: ports) {
+ Assertions.assertTrue(registryServiceListener.getStorage().contains(HOST, port));
+ ServiceDiscoveryRegistryInfoWrapper serviceDiscoveryRegistryInfoWrapper = registryServiceListener.getStorage().get(HOST, port);
+ // check if it's registered
+ Assertions.assertFalse(serviceDiscoveryRegistryInfoWrapper.isRegistered());
+ // check if it's subscribed
+ Assertions.assertFalse(serviceDiscoveryRegistryInfoWrapper.isSubscribed());
+ }
+ */
+ registryServiceListener.getStorage().clear();
+ registryServiceListener = null;
+ logger.info(getClass().getSimpleName() + " testcase is ending...");
+ // destroy registry center
+ registryCenter.shutdown();
+ registryCenter = null;
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener.java
new file mode 100644
index 0000000..a1dd4d7
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener.java
@@ -0,0 +1,103 @@
+/*
+ * 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.servicediscoveryregistry;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.metadata.WritableMetadataService;
+import org.apache.dubbo.registry.Registry;
+import org.apache.dubbo.registry.RegistryServiceListener;
+import org.apache.dubbo.registry.client.ServiceDiscoveryRegistry;
+import org.apache.dubbo.registry.client.metadata.store.InMemoryWritableMetadataService;
+
+@Activate
+public class MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener implements RegistryServiceListener {
+
+ private ServiceDiscoveryRegistryStorage storage = new ServiceDiscoveryRegistryStorage();
+
+ /**
+ * Create an {@link ServiceDiscoveryRegistryInfoWrapper} instance.
+ */
+ private ServiceDiscoveryRegistryInfoWrapper createServiceDiscoveryRegistryInfoWrapper(ServiceDiscoveryRegistry serviceDiscoveryRegistry){
+ String host = serviceDiscoveryRegistry.getUrl().getHost();
+ int port = serviceDiscoveryRegistry.getUrl().getPort();
+ ServiceDiscoveryRegistryInfoWrapper serviceDiscoveryRegistryInfoWrapper = new ServiceDiscoveryRegistryInfoWrapper();
+ serviceDiscoveryRegistryInfoWrapper.setHost(host);
+ serviceDiscoveryRegistryInfoWrapper.setPort(port);
+ serviceDiscoveryRegistryInfoWrapper.setServiceDiscoveryRegistry(serviceDiscoveryRegistry);
+ serviceDiscoveryRegistryInfoWrapper.setInMemoryWritableMetadataService((InMemoryWritableMetadataService) WritableMetadataService.getDefaultExtension());
+ serviceDiscoveryRegistryInfoWrapper.setRegistered(true);
+ return serviceDiscoveryRegistryInfoWrapper;
+ }
+
+ /**
+ * Checks if the registry is checked application
+ */
+ private boolean isCheckedApplication(Registry registry){
+ return registry.getUrl().getParameter(CommonConstants.APPLICATION_KEY)
+ .equals(MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest
+ .PROVIDER_APPLICATION_NAME);
+ }
+
+ public void onRegister(URL url, Registry registry) {
+ if (registry instanceof ServiceDiscoveryRegistry && isCheckedApplication(registry)) {
+ ServiceDiscoveryRegistry serviceDiscoveryRegistry = (ServiceDiscoveryRegistry)registry;
+ String host = serviceDiscoveryRegistry.getUrl().getHost();
+ int port = serviceDiscoveryRegistry.getUrl().getPort();
+ if (!storage.contains(host,port)){
+ storage.put(host,port,createServiceDiscoveryRegistryInfoWrapper(serviceDiscoveryRegistry));
+ }
+ storage.get(host,port).setRegistered(true);
+ }
+ }
+
+ public void onUnregister(URL url, Registry registry) {
+ if (registry instanceof ServiceDiscoveryRegistry && isCheckedApplication(registry)) {
+ String host = registry.getUrl().getHost();
+ int port = registry.getUrl().getPort();
+ storage.get(host,port).setRegistered(false);
+ }
+ }
+
+ public void onSubscribe(URL url, Registry registry) {
+ if (registry instanceof ServiceDiscoveryRegistry && isCheckedApplication(registry)) {
+ ServiceDiscoveryRegistry serviceDiscoveryRegistry = (ServiceDiscoveryRegistry)registry;
+ String host = serviceDiscoveryRegistry.getUrl().getHost();
+ int port = serviceDiscoveryRegistry.getUrl().getPort();
+ if (!storage.contains(host,port)){
+ storage.put(host,port,createServiceDiscoveryRegistryInfoWrapper(serviceDiscoveryRegistry));
+ }
+ storage.get(host,port).setSubscribed(true);
+ }
+ }
+
+ public void onUnsubscribe(URL url, Registry registry) {
+ if (registry instanceof ServiceDiscoveryRegistry && isCheckedApplication(registry)) {
+ String host = registry.getUrl().getHost();
+ int port = registry.getUrl().getPort();
+ storage.get(host,port).setSubscribed(false);
+ }
+ }
+
+ /**
+ * Return the stored {@link ServiceDiscoveryRegistryInfoWrapper} instances.
+ */
+ public ServiceDiscoveryRegistryStorage getStorage() {
+ return storage;
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryService.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryService.java
new file mode 100644
index 0000000..476ccb9
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryService.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.servicediscoveryregistry;
+/**
+ * This interface is used to check if the exported service-discovery-registry protocol works well or not.
+ */
+public interface MultipleRegistryCenterServiceDiscoveryRegistryService {
+ /**
+ * 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/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryServiceImpl.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryServiceImpl.java
new file mode 100644
index 0000000..104a513
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryServiceImpl.java
@@ -0,0 +1,29 @@
+/*
+ * 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.servicediscoveryregistry;
+/**
+ * The simple implementation for {@link MultipleRegistryCenterServiceDiscoveryRegistryService}
+ */
+public class MultipleRegistryCenterServiceDiscoveryRegistryServiceImpl implements MultipleRegistryCenterServiceDiscoveryRegistryService {
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String hello(String name) {
+ return "Hello " + name;
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/ServiceDiscoveryRegistryInfoWrapper.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/ServiceDiscoveryRegistryInfoWrapper.java
new file mode 100644
index 0000000..583eec9
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/ServiceDiscoveryRegistryInfoWrapper.java
@@ -0,0 +1,82 @@
+/*
+ * 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.servicediscoveryregistry;
+
+import org.apache.dubbo.registry.client.ServiceDiscoveryRegistry;
+import org.apache.dubbo.registry.client.metadata.store.InMemoryWritableMetadataService;
+
+/**
+ * The instance to wrap {@link org.apache.dubbo.registry.client.ServiceDiscoveryRegistry}
+ * and {@link org.apache.dubbo.registry.client.metadata.store.InMemoryWritableMetadataService}
+ */
+public class ServiceDiscoveryRegistryInfoWrapper {
+
+ private ServiceDiscoveryRegistry serviceDiscoveryRegistry;
+ private InMemoryWritableMetadataService inMemoryWritableMetadataService;
+ private boolean registered;
+ private boolean subscribed;
+ private String host;
+ private int port;
+
+ public ServiceDiscoveryRegistry getServiceDiscoveryRegistry() {
+ return serviceDiscoveryRegistry;
+ }
+
+ public void setServiceDiscoveryRegistry(ServiceDiscoveryRegistry serviceDiscoveryRegistry) {
+ this.serviceDiscoveryRegistry = serviceDiscoveryRegistry;
+ }
+
+ public InMemoryWritableMetadataService getInMemoryWritableMetadataService() {
+ return inMemoryWritableMetadataService;
+ }
+
+ public void setInMemoryWritableMetadataService(InMemoryWritableMetadataService inMemoryWritableMetadataService) {
+ this.inMemoryWritableMetadataService = inMemoryWritableMetadataService;
+ }
+
+ public boolean isRegistered() {
+ return registered;
+ }
+
+ public void setRegistered(boolean registered) {
+ this.registered = registered;
+ }
+
+ public boolean isSubscribed() {
+ return subscribed;
+ }
+
+ public void setSubscribed(boolean subscribed) {
+ this.subscribed = subscribed;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/ServiceDiscoveryRegistryStorage.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/ServiceDiscoveryRegistryStorage.java
new file mode 100644
index 0000000..ea84bea
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/ServiceDiscoveryRegistryStorage.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.servicediscoveryregistry;
+
+import org.apache.dubbo.integration.multiple.AbstractStorage;
+
+/**
+ * The storage to store {@link ServiceDiscoveryRegistryInfoWrapper} instances in multiple registry center.
+ */
+public class ServiceDiscoveryRegistryStorage extends AbstractStorage<ServiceDiscoveryRegistryInfoWrapper> {
+
+}
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 f428ef4..e1ffb81 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
@@ -177,7 +177,6 @@ public class SingleRegistryCenterDubboProtocolIntegrationTest implements Integra
* <li>Protocol name is right or not</li>
* <li>Protocol port is right or not</li>
* <li>ServiceDiscoveryRegistry's protocol is right or not</li>
- * <li>ServiceDiscoveryRegistry is destroy or not</li>
* <li>Registered service in registry center is right or not</li>
* <li>Exported url is right or not in InMemoryWritableMetadataService</li>
* <li>MetadataInfo exists or not in InMemoryWritableMetadataService</li>
@@ -221,8 +220,6 @@ public class SingleRegistryCenterDubboProtocolIntegrationTest implements Integra
Assertions.assertTrue(serviceDiscoveryRegistry.getServiceDiscovery() instanceof ZookeeperServiceDiscovery);
// Convert to ZookeeperServiceDiscovery instance
ZookeeperServiceDiscovery zookeeperServiceDiscovery = (ZookeeperServiceDiscovery) serviceDiscoveryRegistry.getServiceDiscovery();
- // ServiceDiscoveryRegistry is destroy or not
- Assertions.assertFalse(zookeeperServiceDiscovery.isDestroy());
// Gets registered service by ZookeeperServiceDiscovery
Set<String> services = zookeeperServiceDiscovery.getServices();
// check service exists
diff --git a/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryServiceListener b/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryServiceListener
new file mode 100644
index 0000000..4caa712
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryServiceListener
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+multipleConfigCenterServiceDiscoveryRegistry=org.apache.dubbo.integration.multiple.servicediscoveryregistry.MultipleRegistryCenterServiceDiscoveryRegistryRegistryServiceListener