diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
index 1a2f5536ac..c5e1248c33 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
@@ -482,12 +482,14 @@
 
     /**
      * simple the registry for provider.
+     *
      * @since 2.7.0
      */
     public static final String SIMPLIFIED_KEY = "simplified";
 
     /**
      * After simplify the registry, should add some paramter individually for 
provider.
+     *
      * @since 2.7.0
      */
     public static final String EXTRA_KEYS_KEY = "extra-keys";
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
index e5d8537ec4..eb096f7e71 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
@@ -248,7 +248,7 @@ public static URL valueOf(String url) {
                 // see https://howdoesinternetwork.com/2013/ipv6-zone-id
                 // ignore
             } else {
-                port = Integer.parseInt(url.substring(i+1));
+                port = Integer.parseInt(url.substring(i + 1));
                 url = url.substring(0, i);
             }
         }
@@ -364,7 +364,7 @@ public URL setHost(String host) {
 
     /**
      * Fetch IP address for this URL.
-     *
+     * <p>
      * Pls. note that IP should be used instead of Host when to compare with 
socket's address or to search in a map
      * which use address as its key.
      *
@@ -498,6 +498,15 @@ public String getParameter(String key, String 
defaultValue) {
         return Constants.COMMA_SPLIT_PATTERN.split(value);
     }
 
+    public List<String> getParameter(String key, List<String> defaultValue) {
+        String value = getParameter(key);
+        if (value == null || value.length() == 0) {
+            return defaultValue;
+        }
+        String[] strArray = Constants.COMMA_SPLIT_PATTERN.split(value);
+        return Arrays.asList(strArray);
+    }
+
     private Map<String, Number> getNumbers() {
         if (numbers == null) { // concurrent initialization is tolerant
             numbers = new ConcurrentHashMap<String, Number>();
@@ -1267,6 +1276,7 @@ private String buildString(boolean appendUser, boolean 
appendParameter, boolean
             buf.append("/");
             buf.append(path);
         }
+
         if (appendParameter) {
             buildParameters(buf, true, parameters);
         }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java 
b/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java
index 37696e63ac..cc2a5dbcbb 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/URLTest.java
@@ -17,7 +17,6 @@
 package org.apache.dubbo.common;
 
 import org.apache.dubbo.common.utils.CollectionUtils;
-
 import org.junit.Test;
 
 import java.io.File;
@@ -124,7 +123,7 @@ public void test_valueOf_noHost() throws Exception {
         assertEquals("home/user1/router.js", url.getPath());
         assertEquals(0, url.getParameters().size());
 
-        // Caution!! 
+        // Caution!!
         url = URL.valueOf("file://home/user1/router.js");
         //                      ^^ only tow slash!
         assertEquals("file", url.getProtocol());
@@ -680,4 +679,4 @@ public void testIpV6AddressWithScopeId(){
         assertEquals("1.0.0", url.getParameter("version"));
         assertEquals("morgan", url.getParameter("application"));
     }
-}
\ No newline at end of file
+}
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
index b9d61732c9..d25dfd6240 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
@@ -52,7 +52,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import static org.apache.dubbo.common.Constants.APPLICATION_KEY;
 import static 
org.apache.dubbo.common.config.ConfigurationUtils.parseProperties;
 import static 
org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
 
@@ -376,7 +375,6 @@ private URL loadMetadataReporterURL() {
             return null;
         }
         Map<String, String> map = new HashMap<String, String>();
-        map.put(APPLICATION_KEY, application.getName());
         appendParameters(map, metadataReportConfig);
         return UrlUtils.parseURL(address, map);
     }
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/MetadataReportConfig.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/MetadataReportConfig.java
index d1bb53b14f..a4ace7a266 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/MetadataReportConfig.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/MetadataReportConfig.java
@@ -50,6 +50,11 @@
     // Request timeout in milliseconds for register center
     private Integer timeout;
 
+    /**
+     * The group the metadata in . It is the same as registry
+     */
+    private String group;
+
     // Customized parameters
     private Map<String, String> parameters;
 
@@ -73,6 +78,7 @@ public MetadataReportConfig(String address) {
         setAddress(address);
     }
 
+    @Parameter(excluded = true)
     public String getAddress() {
         return address;
     }
@@ -160,4 +166,12 @@ public String getPrefix() {
     public boolean isValid() {
         return StringUtils.isNotEmpty(address);
     }
+
+    public String getGroup() {
+        return group;
+    }
+
+    public void setGroup(String group) {
+        this.group = group;
+    }
 }
diff --git 
a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd 
b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd
index 195e9a1b8c..30e8f14c92 100644
--- 
a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd
+++ 
b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd
@@ -606,6 +606,12 @@
                 <xsd:documentation><![CDATA[ The request timeout. 
]]></xsd:documentation>
             </xsd:annotation>
         </xsd:attribute>
+        <xsd:attribute name="group" type="xsd:string" use="optional">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ The group of metadata-report. 
]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+
         <xsd:attribute name="retry-times" type="xsd:integer" use="optional">
             <xsd:annotation>
                 <xsd:documentation><![CDATA[ if fail, retry times. 
]]></xsd:documentation>
diff --git 
a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd 
b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
index c481d710d8..c5b890c7fc 100644
--- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
+++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
@@ -600,6 +600,11 @@
                 <xsd:documentation><![CDATA[ The request timeout. 
]]></xsd:documentation>
             </xsd:annotation>
         </xsd:attribute>
+        <xsd:attribute name="group" type="xsd:string" use="optional">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ The group of metadata-report. 
]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
 
         <xsd:attribute name="retry-times" type="xsd:integer" use="optional">
             <xsd:annotation>
diff --git 
a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReport.java
 
b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReport.java
index 9aab901f5d..d29b6365c2 100644
--- 
a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReport.java
+++ 
b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReport.java
@@ -329,6 +329,7 @@ private boolean 
doHandleMetadataCollection(Map<MetadataIdentifier, Object> metad
      * not private. just for unittest.
      */
     void publishAll() {
+        logger.info("start to publish all metadata.");
         this.doHandleMetadataCollection(allMetadataReports);
     }
 
diff --git 
a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReportFactory.java
 
b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReportFactory.java
index 392350ccd7..f3ce5d68c9 100644
--- 
a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReportFactory.java
+++ 
b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReportFactory.java
@@ -38,7 +38,6 @@
     @Override
     public MetadataReport getMetadataReport(URL url) {
         url = url.setPath(MetadataReport.class.getName())
-                .addParameter(Constants.INTERFACE_KEY, 
MetadataReport.class.getName())
                 .removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
         String key = url.toServiceString();
         // Lock the registry access process to ensure a single instance of the 
registry
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java
index e1315e3ef4..a78edda76a 100644
--- 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java
@@ -16,19 +16,18 @@
  */
 package org.apache.dubbo.remoting.zookeeper.curator;
 
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.remoting.zookeeper.ChildListener;
-import org.apache.dubbo.remoting.zookeeper.StateListener;
-import org.apache.dubbo.remoting.zookeeper.support.AbstractZookeeperClient;
-
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.framework.api.CuratorWatcher;
 import org.apache.curator.framework.state.ConnectionState;
 import org.apache.curator.framework.state.ConnectionStateListener;
 import org.apache.curator.retry.RetryNTimes;
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.remoting.zookeeper.ChildListener;
+import org.apache.dubbo.remoting.zookeeper.StateListener;
+import org.apache.dubbo.remoting.zookeeper.support.AbstractZookeeperClient;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException.NoNodeException;
 import org.apache.zookeeper.KeeperException.NodeExistsException;
@@ -43,6 +42,7 @@
     private final Charset charset = Charset.forName("UTF-8");
     private final CuratorFramework client;
 
+
     public CuratorZookeeperClient(URL url) {
         super(url);
         try {
@@ -147,6 +147,7 @@ public boolean checkExists(String path) {
         }
         return false;
     }
+
     @Override
     public boolean isConnected() {
         return client.getZookeeperClient().isConnected();
@@ -156,12 +157,9 @@ public boolean isConnected() {
     public String doGetContent(String path) {
         try {
             byte[] dataBytes = client.getData().forPath(path);
-            if(dataBytes == null || dataBytes.length == 0){
-                return null;
-            }
-            return new String(dataBytes, charset);
-        } catch (NodeExistsException e) {
+            return (dataBytes == null || dataBytes.length == 0) ? null : new 
String(dataBytes, charset);
         } catch (NoNodeException e) {
+            // ignore NoNode Exception.
         } catch (Exception e) {
             throw new IllegalStateException(e.getMessage(), e);
         }
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporter.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporter.java
index 363a69750d..b6a6c3ec9f 100644
--- 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporter.java
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporter.java
@@ -18,13 +18,13 @@
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.remoting.zookeeper.ZookeeperClient;
-import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
+import 
org.apache.dubbo.remoting.zookeeper.support.AbstractZookeeperTransporter;
 
-public class CuratorZookeeperTransporter implements ZookeeperTransporter {
+public class CuratorZookeeperTransporter extends AbstractZookeeperTransporter {
 
-    @Override
-    public ZookeeperClient connect(URL url) {
+    public ZookeeperClient createZookeeperClient(URL url) {
         return new CuratorZookeeperClient(url);
     }
 
+
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperTransporter.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperTransporter.java
new file mode 100644
index 0000000000..43d848ae0a
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperTransporter.java
@@ -0,0 +1,155 @@
+/*
+ * 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.remoting.zookeeper.support;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.remoting.zookeeper.ZookeeperClient;
+import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * AbstractZookeeperTransporter is abstract implements of ZookeeperTransporter.
+ * <p>
+ * If you want to extends this, implements createZookeeperClient.
+ */
+public abstract class AbstractZookeeperTransporter implements 
ZookeeperTransporter {
+    private static final Logger logger = 
LoggerFactory.getLogger(ZookeeperTransporter.class);
+    private final Map<String, ZookeeperClient> zookeeperClientMap = new 
ConcurrentHashMap<>();
+
+    /**
+     * share connnect for registry, metadata, etc..
+     * <p>
+     * Make sure the connection is connected.
+     *
+     * @param url
+     * @return
+     */
+    public ZookeeperClient connect(URL url) {
+        ZookeeperClient zookeeperClient;
+        List<String> addressList = getURLBackupAddress(url);
+        // The field define the zookeeper server , including protocol, host, 
port, username, password
+        if ((zookeeperClient = 
fetchAndUpdateZookeeperClientCache(addressList)) != null && 
zookeeperClient.isConnected()) {
+            logger.info("Get result from map for the first time when invoking 
zookeeperTransporter.connnect .");
+            return zookeeperClient;
+        }
+        // avoid creating too many connections, so add lock
+        synchronized (zookeeperClientMap) {
+            if ((zookeeperClient = 
fetchAndUpdateZookeeperClientCache(addressList)) != null && 
zookeeperClient.isConnected()) {
+                logger.info("Get result from map for the second time when 
invoking zookeeperTransporter.connnect .");
+                return zookeeperClient;
+            }
+
+            zookeeperClient = createZookeeperClient(createServerURL(url));
+            logger.info("Get result by creating new connection when invoking 
zookeeperTransporter.connnect .");
+            writeToClientMap(addressList, zookeeperClient);
+        }
+        return zookeeperClient;
+    }
+
+    /**
+     * @param url the url that will create zookeeper connection .
+     *            The url in AbstractZookeeperTransporter#connect parameter is 
rewritten by this one.
+     *            such as: 
zookeeper://127.0.0.1:2181/org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter
+     * @return
+     */
+    protected abstract ZookeeperClient createZookeeperClient(URL url);
+
+    /**
+     * get the ZookeeperClient from cache, the ZookeeperClient must be 
connected.
+     * <p>
+     * It is not private method for unit test.
+     *
+     * @param addressList
+     * @return
+     */
+    ZookeeperClient fetchAndUpdateZookeeperClientCache(List<String> 
addressList) {
+
+        ZookeeperClient zookeeperClient = null;
+        for (String address : addressList) {
+            if ((zookeeperClient = zookeeperClientMap.get(address)) != null && 
zookeeperClient.isConnected()) {
+                break;
+            }
+        }
+        if (zookeeperClient != null && zookeeperClient.isConnected()) {
+            writeToClientMap(addressList, zookeeperClient);
+        }
+        return zookeeperClient;
+    }
+
+    /**
+     * get all zookeeper urls (such as 
:zookeeper://127.0.0.1:2181?127.0.0.1:8989,127.0.0.1:9999)
+     *
+     * @param url such 
as:zookeeper://127.0.0.1:2181?127.0.0.1:8989,127.0.0.1:9999
+     * @return such as 127.0.0.1:2181,127.0.0.1:8989,127.0.0.1:9999
+     */
+    List<String> getURLBackupAddress(URL url) {
+        List<String> addressList = new ArrayList<String>();
+        addressList.add(url.getAddress());
+
+        addressList.addAll(url.getParameter(Constants.BACKUP_KEY, 
Collections.EMPTY_LIST));
+        return addressList;
+    }
+
+    /**
+     * write address-ZookeeperClient relationship to Map
+     *
+     * @param addressList
+     * @param zookeeperClient
+     */
+    void writeToClientMap(List<String> addressList, ZookeeperClient 
zookeeperClient) {
+        for (String address : addressList) {
+            zookeeperClientMap.put(address, zookeeperClient);
+        }
+    }
+
+    /**
+     * redefine the url for zookeeper. just keep protocol, username, password, 
host, port, and individual parameter.
+     *
+     * @param url
+     * @return
+     */
+    URL createServerURL(URL url) {
+        Map<String, String> parameterMap = new HashMap<>();
+        // for CuratorZookeeperClient
+        if (url.getParameter(Constants.TIMEOUT_KEY) != null) {
+            parameterMap.put(Constants.TIMEOUT_KEY, 
url.getParameter(Constants.TIMEOUT_KEY));
+        }
+        if (url.getParameter(Constants.BACKUP_KEY) != null) {
+            parameterMap.put(Constants.BACKUP_KEY, 
url.getParameter(Constants.BACKUP_KEY));
+        }
+        return new URL(url.getProtocol(), url.getUsername(), 
url.getPassword(), url.getHost(), url.getPort(),
+                ZookeeperTransporter.class.getName(), parameterMap);
+    }
+
+    /**
+     * for unit test
+     *
+     * @return
+     */
+    Map<String, ZookeeperClient> getZookeeperClientMap() {
+        return zookeeperClientMap;
+    }
+}
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkClientWrapper.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkClientWrapper.java
index 3f873affa4..ae8a3ef87b 100644
--- 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkClientWrapper.java
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkClientWrapper.java
@@ -16,13 +16,12 @@
  */
 package org.apache.dubbo.remoting.zookeeper.zkclient;
 
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.Assert;
-
 import org.I0Itec.zkclient.IZkChildListener;
 import org.I0Itec.zkclient.IZkStateListener;
 import org.I0Itec.zkclient.ZkClient;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.Assert;
 import org.apache.zookeeper.Watcher.Event.KeeperState;
 
 import java.util.List;
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java
index 21339520fc..c36640025b 100644
--- 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java
@@ -16,6 +16,11 @@
  */
 package org.apache.dubbo.remoting.zookeeper.zkclient;
 
+
+import org.I0Itec.zkclient.IZkChildListener;
+import org.I0Itec.zkclient.IZkStateListener;
+import org.I0Itec.zkclient.exception.ZkNoNodeException;
+import org.I0Itec.zkclient.exception.ZkNodeExistsException;
 import org.apache.dubbo.common.Constants;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.logger.Logger;
@@ -23,11 +28,6 @@
 import org.apache.dubbo.remoting.zookeeper.ChildListener;
 import org.apache.dubbo.remoting.zookeeper.StateListener;
 import org.apache.dubbo.remoting.zookeeper.support.AbstractZookeeperClient;
-
-import org.I0Itec.zkclient.IZkChildListener;
-import org.I0Itec.zkclient.IZkStateListener;
-import org.I0Itec.zkclient.exception.ZkNoNodeException;
-import org.I0Itec.zkclient.exception.ZkNodeExistsException;
 import org.apache.zookeeper.Watcher.Event.KeeperState;
 
 import java.util.List;
@@ -63,7 +63,6 @@ public void handleNewSession() throws Exception {
         client.start();
     }
 
-
     @Override
     public void createPersistent(String path) {
         try {
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperTransporter.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperTransporter.java
index de5ee4b9d4..eef25afb3f 100644
--- 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperTransporter.java
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperTransporter.java
@@ -18,12 +18,11 @@
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.remoting.zookeeper.ZookeeperClient;
-import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
+import 
org.apache.dubbo.remoting.zookeeper.support.AbstractZookeeperTransporter;
 
-public class ZkclientZookeeperTransporter implements ZookeeperTransporter {
+public class ZkclientZookeeperTransporter extends AbstractZookeeperTransporter 
{
 
-    @Override
-    public ZookeeperClient connect(URL url) {
+    public ZookeeperClient createZookeeperClient(URL url) {
         return new ZkclientZookeeperClient(url);
     }
 
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporterTest.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporterTest.java
index 2c9dbb9a40..c9339cf667 100644
--- 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporterTest.java
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporterTest.java
@@ -16,10 +16,10 @@
  */
 package org.apache.dubbo.remoting.zookeeper.curator;
 
+import org.apache.curator.test.TestingServer;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.NetUtils;
 import org.apache.dubbo.remoting.zookeeper.ZookeeperClient;
-import org.apache.curator.test.TestingServer;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -31,13 +31,22 @@
 public class CuratorZookeeperTransporterTest {
     private TestingServer zkServer;
     private ZookeeperClient zookeeperClient;
+    private CuratorZookeeperTransporter curatorZookeeperTransporter;
+    private int zkServerPort;
 
     @Before
     public void setUp() throws Exception {
-        int zkServerPort = NetUtils.getAvailablePort();
+        zkServerPort = NetUtils.getAvailablePort();
         zkServer = new TestingServer(zkServerPort, true);
         zookeeperClient = new 
CuratorZookeeperTransporter().connect(URL.valueOf("zookeeper://127.0.0.1:" +
                 zkServerPort + "/service"));
+        curatorZookeeperTransporter = new CuratorZookeeperTransporter();
+    }
+
+
+    @After
+    public void tearDown() throws Exception {
+        zkServer.stop();
     }
 
     @Test
@@ -46,8 +55,4 @@ public void testZookeeperClient() {
         zookeeperClient.close();
     }
 
-    @After
-    public void tearDown() throws Exception {
-        zkServer.stop();
-    }
-}
\ No newline at end of file
+}
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperTransporterTest.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperTransporterTest.java
new file mode 100644
index 0000000000..24319365b9
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperTransporterTest.java
@@ -0,0 +1,237 @@
+/*
+ * 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.remoting.zookeeper.support;
+
+import org.apache.curator.test.TestingServer;
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.remoting.zookeeper.ZookeeperClient;
+import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
+import org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperTransporter;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.core.IsNull.nullValue;
+
+/**
+ * AbstractZookeeperTransporterTest
+ */
+public class AbstractZookeeperTransporterTest {
+    private TestingServer zkServer;
+    private ZookeeperClient zookeeperClient;
+    private AbstractZookeeperTransporter abstractZookeeperTransporter;
+    private int zkServerPort;
+
+    @Before
+    public void setUp() throws Exception {
+        zkServerPort = NetUtils.getAvailablePort();
+        zkServer = new TestingServer(zkServerPort, true);
+        zookeeperClient = new 
CuratorZookeeperTransporter().connect(URL.valueOf("zookeeper://127.0.0.1:" +
+                zkServerPort + "/service"));
+        abstractZookeeperTransporter = new CuratorZookeeperTransporter();
+    }
+
+
+    @After
+    public void tearDown() throws Exception {
+        zkServer.stop();
+    }
+
+    @Test
+    public void testZookeeperClient() {
+        assertThat(zookeeperClient, not(nullValue()));
+        zookeeperClient.close();
+    }
+
+    @Test
+    public void testCreateServerURL() {
+        URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + 
"/org.apache.dubbo.registry.RegistryService?application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT&timestamp=1547102428828&timeout=2300");
+        URL newUrl = abstractZookeeperTransporter.createServerURL(url);
+        Assert.assertEquals(newUrl.getProtocol(), "zookeeper");
+        Assert.assertEquals(newUrl.getHost(), "127.0.0.1");
+        Assert.assertEquals(newUrl.getPort(), zkServerPort);
+        Assert.assertNull(newUrl.getUsername());
+        Assert.assertNull(newUrl.getPassword());
+        Assert.assertEquals(newUrl.getParameter(Constants.TIMEOUT_KEY, 5000), 
2300);
+        Assert.assertEquals(newUrl.getParameters().size(), 1);
+        Assert.assertEquals(newUrl.getPath(), 
ZookeeperTransporter.class.getName());
+    }
+
+
+    @Test
+    public void testCreateServerURLWhenHasUser() {
+        URL url = URL.valueOf("zookeeper://us2:[email protected]:" + zkServerPort 
+ 
"/org.apache.dubbo.registry.RegistryService?application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT&timestamp=1547102428828");
+        URL newUrl = abstractZookeeperTransporter.createServerURL(url);
+        Assert.assertEquals(newUrl.getProtocol(), "zookeeper");
+        Assert.assertEquals(newUrl.getHost(), "127.0.0.1");
+        Assert.assertEquals(newUrl.getPort(), zkServerPort);
+        Assert.assertEquals(newUrl.getUsername(), "us2");
+        Assert.assertEquals(newUrl.getPassword(), "pw2");
+        Assert.assertEquals(newUrl.getParameters().size(), 0);
+        Assert.assertEquals(newUrl.getPath(), 
ZookeeperTransporter.class.getName());
+    }
+
+    @Test
+    public void testGetURLBackupAddress() {
+        URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + 
"/org.apache.dubbo.registry.RegistryService?backup=127.0.0.1:" + 9099 + 
"&application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT&timestamp=1547102428828");
+        List<String> stringList = 
abstractZookeeperTransporter.getURLBackupAddress(url);
+        Assert.assertEquals(stringList.size(), 2);
+        Assert.assertEquals(stringList.get(0), "127.0.0.1:" + zkServerPort);
+        Assert.assertEquals(stringList.get(1), "127.0.0.1:9099");
+    }
+
+    @Test
+    public void testGetURLBackupAddressNoBack() {
+        URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + 
"/org.apache.dubbo.registry.RegistryService?application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT&timestamp=1547102428828");
+        List<String> stringList = 
abstractZookeeperTransporter.getURLBackupAddress(url);
+        Assert.assertEquals(stringList.size(), 1);
+        Assert.assertEquals(stringList.get(0), "127.0.0.1:" + zkServerPort);
+    }
+
+    @Test
+    public void testFetchAndUpdateZookeeperClientCache() throws Exception {
+        int zkServerPort2 = NetUtils.getAvailablePort();
+        TestingServer zkServer2 = new TestingServer(zkServerPort2, true);
+
+        int zkServerPort3 = NetUtils.getAvailablePort();
+        TestingServer zkServer3 = new TestingServer(zkServerPort3, true);
+
+        URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + 
"/org.apache.dubbo.registry.RegistryService?backup=127.0.0.1:" + zkServerPort3 
+ ",127.0.0.1:" + zkServerPort2 + 
"&application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT&timestamp=1547102428828");
+        ZookeeperClient newZookeeperClient = 
abstractZookeeperTransporter.connect(url);
+        //just for connected
+        newZookeeperClient.getContent("/dubbo/test");
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(),
 3);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:"
 + zkServerPort), newZookeeperClient);
+
+        URL url2 = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + 
"/org.apache.dubbo.metadata.store.MetadataReport?address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true");
+        checkFetchAndUpdateCacheNotNull(url2);
+        URL url3 = 
URL.valueOf("zookeeper://127.0.0.1:8778/org.apache.dubbo.metadata.store.MetadataReport?backup=127.0.0.1:"
 + zkServerPort3 + 
"&address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true");
+        checkFetchAndUpdateCacheNotNull(url3);
+
+        zkServer2.stop();
+        zkServer3.stop();
+    }
+
+    private void checkFetchAndUpdateCacheNotNull(URL url) {
+        List<String> addressList = 
abstractZookeeperTransporter.getURLBackupAddress(url);
+        ZookeeperClient zookeeperClient = 
abstractZookeeperTransporter.fetchAndUpdateZookeeperClientCache(addressList);
+        Assert.assertNotNull(zookeeperClient);
+    }
+
+    @Test
+    public void testRepeatConnect() {
+        URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + 
"/org.apache.dubbo.registry.RegistryService?application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT&timestamp=1547102428828");
+        URL url2 = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + 
"/org.apache.dubbo.metadata.store.MetadataReport?address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true");
+        ZookeeperClient newZookeeperClient = 
abstractZookeeperTransporter.connect(url);
+        //just for connected
+        newZookeeperClient.getContent("/dubbo/test");
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(),
 1);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:"
 + zkServerPort), newZookeeperClient);
+        Assert.assertTrue(newZookeeperClient.isConnected());
+
+        ZookeeperClient newZookeeperClient2 = 
abstractZookeeperTransporter.connect(url2);
+        //just for connected
+        newZookeeperClient2.getContent("/dubbo/test");
+        Assert.assertEquals(newZookeeperClient, newZookeeperClient2);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(),
 1);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:"
 + zkServerPort), newZookeeperClient);
+    }
+
+    @Test
+    public void testNotRepeatConnect() throws Exception {
+        int zkServerPort2 = NetUtils.getAvailablePort();
+        TestingServer zkServer2 = new TestingServer(zkServerPort2, true);
+
+        URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + 
"/org.apache.dubbo.registry.RegistryService?application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT&timestamp=1547102428828");
+        URL url2 = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort2 + 
"/org.apache.dubbo.metadata.store.MetadataReport?address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true");
+        ZookeeperClient newZookeeperClient = 
abstractZookeeperTransporter.connect(url);
+        //just for connected
+        newZookeeperClient.getContent("/dubbo/test");
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(),
 1);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:"
 + zkServerPort), newZookeeperClient);
+
+        ZookeeperClient newZookeeperClient2 = 
abstractZookeeperTransporter.connect(url2);
+        //just for connected
+        newZookeeperClient2.getContent("/dubbo/test");
+        Assert.assertNotEquals(newZookeeperClient, newZookeeperClient2);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(),
 2);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:"
 + zkServerPort2), newZookeeperClient2);
+
+        zkServer2.stop();
+    }
+
+    @Test
+    public void testRepeatConnectForBackUpAdd() throws Exception {
+        int zkServerPort2 = NetUtils.getAvailablePort();
+        TestingServer zkServer2 = new TestingServer(zkServerPort2, true);
+
+        int zkServerPort3 = NetUtils.getAvailablePort();
+        TestingServer zkServer3 = new TestingServer(zkServerPort3, true);
+
+        URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + 
"/org.apache.dubbo.registry.RegistryService?backup=127.0.0.1:" + zkServerPort2 
+ 
"&application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT&timestamp=1547102428828");
+        URL url2 = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort2 + 
"/org.apache.dubbo.metadata.store.MetadataReport?backup=127.0.0.1:" + 
zkServerPort3 + 
"&address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true");
+        ZookeeperClient newZookeeperClient = 
abstractZookeeperTransporter.connect(url);
+        //just for connected
+        newZookeeperClient.getContent("/dubbo/test");
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(),
 2);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:"
 + zkServerPort), newZookeeperClient);
+
+        ZookeeperClient newZookeeperClient2 = 
abstractZookeeperTransporter.connect(url2);
+        //just for connected
+        newZookeeperClient2.getContent("/dubbo/test");
+        Assert.assertEquals(newZookeeperClient, newZookeeperClient2);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(),
 3);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:"
 + zkServerPort2), newZookeeperClient2);
+
+        zkServer2.stop();
+        zkServer3.stop();
+    }
+
+    @Test
+    public void testRepeatConnectForNoMatchBackUpAdd() throws Exception {
+        int zkServerPort2 = NetUtils.getAvailablePort();
+        TestingServer zkServer2 = new TestingServer(zkServerPort2, true);
+
+        int zkServerPort3 = NetUtils.getAvailablePort();
+        TestingServer zkServer3 = new TestingServer(zkServerPort3, true);
+
+        URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + 
"/org.apache.dubbo.registry.RegistryService?backup=127.0.0.1:" + zkServerPort3 
+ 
"&application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT&timestamp=1547102428828");
+        URL url2 = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort2 + 
"/org.apache.dubbo.metadata.store.MetadataReport?address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true");
+        ZookeeperClient newZookeeperClient = 
abstractZookeeperTransporter.connect(url);
+        //just for connected
+        newZookeeperClient.getContent("/dubbo/test");
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(),
 2);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:"
 + zkServerPort), newZookeeperClient);
+
+        ZookeeperClient newZookeeperClient2 = 
abstractZookeeperTransporter.connect(url2);
+        //just for connected
+        newZookeeperClient2.getContent("/dubbo/test");
+        Assert.assertNotEquals(newZookeeperClient, newZookeeperClient2);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(),
 3);
+        
Assert.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:"
 + zkServerPort2), newZookeeperClient2);
+
+        zkServer2.stop();
+        zkServer3.stop();
+    }
+}


With regards,
Apache Git Services

Reply via email to