You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2018/10/15 01:22:10 UTC

[incubator-dubbo] branch dev-metadata updated: Merge pull request #2626, simplify registry data and add a new service data store seperated from registry.

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

liujun pushed a commit to branch dev-metadata
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git


The following commit(s) were added to refs/heads/dev-metadata by this push:
     new 59dd98a  Merge pull request #2626, simplify registry data and add a new service data store seperated from registry.
59dd98a is described below

commit 59dd98a06b6faf3d4e4a856d6b43f59b65da3d8f
Author: cvictory <sh...@gmail.com>
AuthorDate: Mon Oct 15 09:22:02 2018 +0800

    Merge pull request #2626, simplify registry data and add a new service data store seperated from registry.
---
 .../java/org/apache/dubbo/common/Constants.java    |   2 +
 .../src/main/java/org/apache/dubbo/common/URL.java |  10 +-
 .../dubbo/config/AbstractInterfaceConfig.java      |   3 +-
 dubbo-servicedata/dubbo-servicedata-api/pom.xml    |  17 +-
 .../integration/ServiceStoreService.java           |  85 ++++++++--
 .../servicedata/metadata/MethodDescriptor.java     |  54 ++++++
 .../servicedata/metadata/ServiceDescriptor.java    |  55 +++++++
 .../dubbo/servicedata/metadata/TypeDescriptor.java |  65 ++++++++
 .../metadata/builder/ArrayTypeBuilder.java         |  36 ++++
 .../metadata/builder/CollectionTypeBuilder.java    |  59 +++++++
 .../metadata/builder/DefaultTypeBuilder.java       | 113 +++++++++++++
 .../metadata/builder/EnumTypeBuilder.java          |  45 +++++
 .../metadata/builder/MapTypeBuilder.java           |  60 +++++++
 .../metadata/builder/ServiceDescriptorBuilder.java |  71 ++++++++
 .../servicedata/metadata/builder/TypeBuilder.java  |  23 +++
 .../metadata/builder/TypeDescriptorBuilder.java    |  63 +++++++
 .../servicedata/{ => store}/ServiceStore.java      |   2 +-
 .../{ => store}/ServiceStoreFactory.java           |   2 +-
 .../servicedata/support/AbstractServiceStore.java  |   4 +-
 .../support/AbstractServiceStoreFactory.java       |   4 +-
 .../integration/InterfaceNameTestService.java      |   9 +
 .../integration/InterfaceNameTestService2.java     |   9 +
 .../integration/ServiceStoreServiceTest.java       | 179 +++++++++++++++++++-
 .../metadata/builder/ArrayTypeBuilderTest.java     |  91 ++++++++++
 .../builder/CollectionTypeBuilderTest.java         |  91 ++++++++++
 .../servicedata/metadata/builder/ComplexEnum.java  |  16 ++
 .../metadata/builder/ComplexObject.java            |  37 +++++
 .../metadata/builder/DefaultTypeBuilderTest.java   |  64 +++++++
 .../metadata/builder/EnumTypeBuilderTest.java      |  85 ++++++++++
 .../metadata/builder/MapTypeBuilderTest.java       |  90 ++++++++++
 .../builder/ServiceDescriptorBuilderTest.java      |  25 +++
 .../servicedata/metadata/builder/SingleEnum.java   |   8 +
 .../servicedata/metadata/builder/TestService.java  |  45 +++++
 .../builder/TypeDescriptorBuilderTest.java         | 101 ++++++++++++
 .../store/test/JTestServiceStore4Test.java}        |  42 ++---
 .../store/test/JTestServiceStoreFactory4Test.java} |   8 +-
 .../support/AbstractServiceStoreFactoryTest.java   |   4 +-
 .../support/AbstractServiceStoreTest.java          |   8 +-
 ...che.dubbo.servicedata.store.ServiceStoreFactory |   1 +
 dubbo-servicedata/dubbo-servicedata-redis/pom.xml  |  22 ++-
 .../{ => store}/redis/RedisServiceStore.java       |  20 ++-
 .../redis/RedisServiceStoreFactory.java            |   5 +-
 ...rg.apache.dubbo.servicedata.ServiceStoreFactory |   1 -
 ...che.dubbo.servicedata.store.ServiceStoreFactory |   1 +
 .../store/redis/RedisServiceStoreTest.java         | 101 ++++++++++++
 .../dubbo-servicedata-zookeeper/pom.xml            |  17 +-
 .../zookeeper/ZookeeperServiceStore.java           |  21 ++-
 .../zookeeper/ZookeeperServiceStoreFactory.java    |   4 +-
 ...rg.apache.dubbo.servicedata.ServiceStoreFactory |   1 -
 ...che.dubbo.servicedata.store.ServiceStoreFactory |   1 +
 .../store/zookeeper/ZookeeperServiceStoreTest.java | 183 +++++++++++++++++++++
 dubbo-servicedata/pom.xml                          |  17 +-
 52 files changed, 1991 insertions(+), 89 deletions(-)

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 49b0bd1..5f264fb 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
@@ -375,6 +375,8 @@ public class Constants {
 
     public static final String DEFAULT_CHANNEL_HANDLER = "default";
 
+    public static final String SERVICE_DESCIPTOR_KEY = "serviceDescriptor";
+
     public static final String ANY_VALUE = "*";
 
     public static final String COMMA_SEPARATOR = ",";
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 312b691..5d24ed5 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
@@ -250,16 +250,16 @@ public /**final**/ class URL implements Serializable {
         return new URL(protocol, username, password, host, port, path, parameters);
     }
 
-    public static URL valueOf(String url, String... reserveParams){
+    public static URL valueOf(String url, String... reserveParams) {
         URL result = valueOf(url);
-        if (reserveParams == null || reserveParams.length == 0){
+        if (reserveParams == null || reserveParams.length == 0) {
             return result;
         }
-        Map<String, String> newMap = new HashMap<String,String>(reserveParams.length);
+        Map<String, String> newMap = new HashMap<String, String>(reserveParams.length);
         Map<String, String> oldMap = result.getParameters();
-        for(String reserveParam : reserveParams){
+        for (String reserveParam : reserveParams) {
             String tmp = oldMap.get(reserveParam);
-            if(StringUtils.isNotEmpty(tmp)){
+            if (StringUtils.isNotEmpty(tmp)) {
                 newMap.put(reserveParam, tmp);
             }
         }
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 0e4f93e..ca39f71 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
@@ -35,14 +35,13 @@ import org.apache.dubbo.rpc.InvokerListener;
 import org.apache.dubbo.rpc.ProxyFactory;
 import org.apache.dubbo.rpc.cluster.Cluster;
 import org.apache.dubbo.rpc.support.MockInvoker;
-import org.apache.dubbo.servicedata.ServiceStoreFactory;
+import org.apache.dubbo.servicedata.store.ServiceStoreFactory;
 import org.apache.dubbo.servicedata.integration.ServiceStoreService;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.function.Supplier;
 
 /**
  * AbstractDefaultConfig
diff --git a/dubbo-servicedata/dubbo-servicedata-api/pom.xml b/dubbo-servicedata/dubbo-servicedata-api/pom.xml
index af5d30b..d0d9f0f 100644
--- a/dubbo-servicedata/dubbo-servicedata-api/pom.xml
+++ b/dubbo-servicedata/dubbo-servicedata-api/pom.xml
@@ -1,4 +1,19 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
 <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/integration/ServiceStoreService.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/integration/ServiceStoreService.java
index 8fad3a8..98ba7bc 100644
--- a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/integration/ServiceStoreService.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/integration/ServiceStoreService.java
@@ -16,42 +16,67 @@
  */
 package org.apache.dubbo.servicedata.integration;
 
+import com.alibaba.fastjson.JSON;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.time.DateUtils;
 import org.apache.dubbo.common.Constants;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.ConcurrentHashSet;
+import org.apache.dubbo.common.utils.NamedThreadFactory;
 import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.servicedata.ServiceStore;
-import org.apache.dubbo.servicedata.ServiceStoreFactory;
+import org.apache.dubbo.servicedata.metadata.ServiceDescriptor;
+import org.apache.dubbo.servicedata.metadata.builder.ServiceDescriptorBuilder;
+import org.apache.dubbo.servicedata.store.ServiceStore;
+import org.apache.dubbo.servicedata.store.ServiceStoreFactory;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Random;
 import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Supplier;
 
-/**
- */
+import static org.apache.dubbo.common.Constants.SERVICE_DESCIPTOR_KEY;
+
+
 public class ServiceStoreService {
 
+    protected final Logger logger = LoggerFactory.getLogger(getClass());
+    private static final int ONE_DAY_IN_MIll = 60 * 24 * 60 * 1000;
+    private static final int FOUR_HOURS_IN_MIll = 60 * 4 * 60 * 1000;
+
+    private static ServiceStoreService serviceStoreService;
+    private static Object lock = new Object();
+
+    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(0, new NamedThreadFactory("DubboRegistryFailedRetryTimer", true));
     private ServiceStoreFactory serviceStoreFactory = ExtensionLoader.getExtensionLoader(ServiceStoreFactory.class).getAdaptiveExtension();
-    private static final Set<URL> providerURLs = new HashSet<URL>();
-    private static final Set<URL> consumerURLs = new HashSet<URL>();
-    private ServiceStore serviceStore;
+    final Set<URL> providerURLs = new ConcurrentHashSet<>();
+    final Set<URL> consumerURLs = new ConcurrentHashSet<URL>();
+    ServiceStore serviceStore;
+    URL serviceStoreUrl;
+
 
-    private URL serviceStoreUrl;
 
-    private ServiceStoreService(URL serviceStoreURL) {
+    ServiceStoreService(URL serviceStoreURL) {
         if (Constants.SERVICE_STORE_KEY.equals(serviceStoreURL.getProtocol())) {
             String protocol = serviceStoreURL.getParameter(Constants.SERVICE_STORE_KEY, Constants.DEFAULT_DIRECTORY);
             serviceStoreURL = serviceStoreURL.setProtocol(protocol).removeParameter(Constants.SERVICE_STORE_KEY);
         }
         this.serviceStoreUrl = serviceStoreURL;
         serviceStore = serviceStoreFactory.getServiceStore(this.serviceStoreUrl);
+        scheduler.scheduleAtFixedRate(new Runnable() {
+            @Override
+            public void run() {
+                publishAll();
+            }
+        }, calculateStartTime(), ONE_DAY_IN_MIll, TimeUnit.MILLISECONDS);
     }
 
-    private static ServiceStoreService serviceStoreService;
-    private static Object lock = new Object();
 
     public static ServiceStoreService instance(Supplier<URL> loadServiceStoreUrl) {
         if (serviceStoreService == null) {
@@ -69,7 +94,19 @@ public class ServiceStoreService {
     }
 
     public void publishProvider(URL providerUrl) throws RpcException {
+        //first add into the list
         providerURLs.add(providerUrl);
+        try {
+            String interfaceName = providerUrl.getParameter(Constants.INTERFACE_KEY);
+            if (StringUtils.isNotEmpty(interfaceName)) {
+                Class interfaceClass = Class.forName(interfaceName);
+                ServiceDescriptor serviceDescriptor = ServiceDescriptorBuilder.build(interfaceClass);
+                providerUrl = providerUrl.addParameter(SERVICE_DESCIPTOR_KEY, JSON.toJSONString(serviceDescriptor));
+            }
+        } catch (ClassNotFoundException e) {
+            //ignore error
+            logger.error("Servicestore getServiceDescriptor error. providerUrl: " + providerUrl.toFullString(), e);
+        }
         serviceStore.put(providerUrl);
     }
 
@@ -78,4 +115,22 @@ public class ServiceStoreService {
         serviceStore.put(consumerURL);
     }
 
+    void publishAll() {
+        for (URL url : providerURLs) {
+            publishProvider(url);
+        }
+        for (URL url : consumerURLs) {
+            publishConsumer(url);
+        }
+    }
+
+    long calculateStartTime() {
+        Date now = new Date();
+        long nowMill = now.getTime();
+        long today0 = DateUtils.truncate(now, Calendar.DAY_OF_MONTH).getTime();
+        long subtract = today0 + ONE_DAY_IN_MIll - nowMill;
+        Random r = new Random();
+        return subtract + (FOUR_HOURS_IN_MIll / 2) + r.nextInt(FOUR_HOURS_IN_MIll);
+    }
+
 }
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/MethodDescriptor.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/MethodDescriptor.java
new file mode 100644
index 0000000..a27fc6b
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/MethodDescriptor.java
@@ -0,0 +1,54 @@
+package org.apache.dubbo.servicedata.metadata;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ *  2018/9/18
+ */
+public class MethodDescriptor {
+    private String name;
+    private String[] parameterTypes;
+    private String returnType;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String[] getParameterTypes() {
+        return parameterTypes;
+    }
+
+    public void setParameterTypes(String[] parameterTypes) {
+        this.parameterTypes = parameterTypes;
+    }
+
+    public String getReturnType() {
+        return returnType;
+    }
+
+    public void setReturnType(String returnType) {
+        this.returnType = returnType;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof MethodDescriptor)) return false;
+        MethodDescriptor that = (MethodDescriptor) o;
+        return Objects.equals(getName(), that.getName()) &&
+                Arrays.equals(getParameterTypes(), that.getParameterTypes()) &&
+                Objects.equals(getReturnType(), that.getReturnType());
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(getName(), getReturnType());
+        result = 31 * result + Arrays.hashCode(getParameterTypes());
+        return result;
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/ServiceDescriptor.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/ServiceDescriptor.java
new file mode 100644
index 0000000..c4a9f90
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/ServiceDescriptor.java
@@ -0,0 +1,55 @@
+package org.apache.dubbo.servicedata.metadata;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *  2018/9/18
+ */
+public class ServiceDescriptor {
+    private String name;
+    private String codeSource;
+    private List<MethodDescriptor> methodDescriptors = new ArrayList<>();
+    /**
+     * Primitive type and String will not be stored.
+     *
+     * The typeDescriptor will not store
+     */
+    private Map<String, TypeDescriptor> types = new HashMap<>();
+
+
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getCodeSource() {
+        return codeSource;
+    }
+
+    public void setCodeSource(String codeSource) {
+        this.codeSource = codeSource;
+    }
+
+    public List<MethodDescriptor> getMethodDescriptors() {
+        return methodDescriptors;
+    }
+
+    public void setMethodDescriptors(List<MethodDescriptor> methodDescriptors) {
+        this.methodDescriptors = methodDescriptors;
+    }
+
+    public Map<String, TypeDescriptor> getTypes() {
+        return types;
+    }
+
+    public void setTypes(Map<String, TypeDescriptor> types) {
+        this.types = types;
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/TypeDescriptor.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/TypeDescriptor.java
new file mode 100644
index 0000000..615ef53
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/TypeDescriptor.java
@@ -0,0 +1,65 @@
+package org.apache.dubbo.servicedata.metadata;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ *  2018/9/18
+ */
+public class TypeDescriptor {
+
+    private String type;
+    private boolean custom;
+    private Map<String, TypeDescriptor> properties = new HashMap<>();
+
+    public TypeDescriptor(String type){
+        this.type = type;
+    }
+
+    public TypeDescriptor(String type, boolean custom){
+        this.type = type;
+        this.custom = custom;
+    }
+
+    public static TypeDescriptor simplifyTypeDescriptor(TypeDescriptor typeDescriptor){
+        return new TypeDescriptor(typeDescriptor.getType(), typeDescriptor.isCustom());
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public Map<String, TypeDescriptor> getProperties() {
+        return properties;
+    }
+
+    public void setProperties(Map<String, TypeDescriptor> properties) {
+        this.properties = properties;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof TypeDescriptor)) return false;
+        TypeDescriptor that = (TypeDescriptor) o;
+        return Objects.equals(getType(), that.getType());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getType());
+    }
+
+    public boolean isCustom() {
+        return custom;
+    }
+
+    public void setCustom(boolean custom) {
+        this.custom = custom;
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/ArrayTypeBuilder.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/ArrayTypeBuilder.java
new file mode 100644
index 0000000..5a819db
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/ArrayTypeBuilder.java
@@ -0,0 +1,36 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+
+import java.lang.reflect.Type;
+import java.util.Map;
+
+/**
+ *  2018/9/18
+ */
+public class ArrayTypeBuilder implements TypeBuilder {
+
+    @Override
+    public boolean accept(Type type, Class<?> clazz) {
+        if (clazz == null) {
+            return false;
+        }
+
+        if (clazz.isArray()) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public TypeDescriptor build(Type type, Class<?> clazz, Map<Class<?>, TypeDescriptor> typeCache) {
+        // Process the component type of an array.
+        Class<?> componentType = clazz.getComponentType();
+        TypeDescriptorBuilder.build(componentType, componentType, typeCache);
+
+        final String canonicalName = clazz.getCanonicalName();
+        TypeDescriptor td = new TypeDescriptor(canonicalName);
+        return td;
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/CollectionTypeBuilder.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/CollectionTypeBuilder.java
new file mode 100644
index 0000000..3e4d567
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/CollectionTypeBuilder.java
@@ -0,0 +1,59 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ *  2018/9/18
+ */
+public class CollectionTypeBuilder implements TypeBuilder{
+    @Override
+    public boolean accept(Type type, Class<?> clazz) {
+        if (clazz == null) {
+            return false;
+        }
+
+        if (Collection.class.isAssignableFrom(clazz)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public TypeDescriptor build(Type type, Class<?> clazz, Map<Class<?>, TypeDescriptor> typeCache) {
+        if (!(type instanceof ParameterizedType)) {
+            // 没有泛型信息,就直接返回class name
+            return new TypeDescriptor(clazz.getName());
+        }
+
+        ParameterizedType parameterizedType = (ParameterizedType) type;
+        Type[] actualTypeArgs = parameterizedType.getActualTypeArguments();
+        if (actualTypeArgs == null || actualTypeArgs.length != 1) {
+            throw new IllegalArgumentException(MessageFormat.format(
+                    "[Jaket] Collection type [{0}] with unexpected amount of arguments [{1}]." + actualTypeArgs,
+                    new Object[] { type, actualTypeArgs }));
+        }
+
+        Type actualType = actualTypeArgs[0];
+        if (actualType instanceof ParameterizedType) {
+            // Nested collection or map.
+            Class<?> rawType = (Class<?>) ((ParameterizedType) actualType).getRawType();
+            TypeDescriptorBuilder.build(actualType, rawType, typeCache);
+        } else if (actualType instanceof Class<?>) {
+            Class<?> actualClass = (Class<?>) actualType;
+            if (actualClass.isArray() || actualClass.isEnum()) {
+                TypeDescriptorBuilder.build(null, actualClass, typeCache);
+            } else {
+                DefaultTypeBuilder.build(actualClass, typeCache);
+            }
+        }
+
+        return new TypeDescriptor(type.toString());
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/DefaultTypeBuilder.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/DefaultTypeBuilder.java
new file mode 100644
index 0000000..11b9bca
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/DefaultTypeBuilder.java
@@ -0,0 +1,113 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *  2018/9/18
+ */
+public class DefaultTypeBuilder {
+
+    public static TypeDescriptor build(Class<?> clazz, Map<Class<?>, TypeDescriptor> typeCache) {
+//        final String canonicalName = clazz.getCanonicalName();
+        final String name = clazz.getName();
+
+        TypeDescriptor td = new TypeDescriptor(name);
+        // Try to get a cached definition
+        if (typeCache.containsKey(clazz)) {
+            return typeCache.get(clazz);
+        }
+
+        // Primitive type
+        if (!needAnalyzing(clazz)) {
+            return td;
+        }
+
+        // Custom type
+        td.setCustom(true);
+
+        List<Field> fields = getNonStaticFields(clazz);
+        for (Field field : fields) {
+            String fieldName = field.getName();
+            Class<?> fieldClass = field.getType();
+            Type fieldType = field.getGenericType();
+
+            TypeDescriptor fieldTd = TypeDescriptorBuilder.build(fieldType, fieldClass, typeCache);
+            // if custom, renew and remove properties.
+            if(fieldTd.isCustom()){
+                fieldTd = TypeDescriptor.simplifyTypeDescriptor(fieldTd);
+            }
+            td.getProperties().put(fieldName, fieldTd);
+        }
+
+        typeCache.put(clazz, td);
+        return td;
+    }
+
+    private static List<Field> getNonStaticFields(final Class<?> clazz) {
+        List<Field> result = new ArrayList<Field>();
+        Class<?> target = clazz;
+        while (target != null) {
+
+            Field[] fields = target.getDeclaredFields();
+            for (Field field : fields) {
+                int modifiers = field.getModifiers();
+                if (Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) {
+                    continue;
+                }
+
+                result.add(field);
+            }
+            target = target.getSuperclass();
+        }
+
+        return result;
+    }
+
+
+    private static Set<String> closedTypes = new HashSet<String>(Arrays.asList("boolean", "byte", "char", "double", "float", "int", "long", "short", "void"));
+
+
+    /**
+     * <pre>
+     * 是否需要分析参数 clazz :
+     * clazz 是否为 primitive 类型
+     *    若为 primitive 类型,则不分析
+     * </pre>
+     *
+     * @param clazz
+     * @return
+     */
+    private static boolean needAnalyzing(Class<?> clazz) {
+        String canonicalName = clazz.getCanonicalName();
+
+        if (closedTypes != null && closedTypes.size() > 0) {
+            for (String type : closedTypes) {
+                if (canonicalName.startsWith(type)) {
+                    return false;
+                }
+            }
+        }
+        if (canonicalName.equals("java.lang.String")) {
+            return false;
+        }
+        // bootstrap classloader will be ignored.
+        if (clazz.getClassLoader() == null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private DefaultTypeBuilder() {
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/EnumTypeBuilder.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/EnumTypeBuilder.java
new file mode 100644
index 0000000..86561fa
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/EnumTypeBuilder.java
@@ -0,0 +1,45 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+
+import java.lang.reflect.Type;
+import java.util.Map;
+
+/**
+ *  2018/9/18
+ */
+public class EnumTypeBuilder implements TypeBuilder{
+
+    @Override
+    public boolean accept(Type type, Class<?> clazz) {
+        if (clazz == null) {
+            return false;
+        }
+
+        if (clazz.isEnum()) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public TypeDescriptor build(Type type, Class<?> clazz, Map<Class<?>, TypeDescriptor> typeCache) {
+        TypeDescriptor td = new TypeDescriptor(clazz.getCanonicalName());
+
+        try {
+            // set values
+//            Method methodValues = clazz.getDeclaredMethod("values", new Class<?>[0]);
+//            Object[] values = (Object[]) methodValues.invoke(clazz, new Object[0]);
+//            int length = values.length;t
+//            for (int i = 0; i < length; i++) {
+//                Object value = values[i];
+//                td.getEnums().add(value.toString());
+//            }
+        } catch (Throwable t) {
+        }
+
+        typeCache.put(clazz, td);
+        return td;
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/MapTypeBuilder.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/MapTypeBuilder.java
new file mode 100644
index 0000000..d44342c
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/MapTypeBuilder.java
@@ -0,0 +1,60 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.util.Map;
+
+/**
+ *  2018/9/18
+ */
+public class MapTypeBuilder implements TypeBuilder{
+
+    @Override
+    public boolean accept(Type type, Class<?> clazz) {
+        if (clazz == null) {
+            return false;
+        }
+
+        if (Map.class.isAssignableFrom(clazz)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public TypeDescriptor build(Type type, Class<?> clazz, Map<Class<?>, TypeDescriptor> typeCache) {
+        if (!(type instanceof ParameterizedType)) {
+            // 没有泛型信息,就直接返回class name
+            return new TypeDescriptor(clazz.getName());
+        }
+
+        ParameterizedType parameterizedType = (ParameterizedType) type;
+        Type[] actualTypeArgs = parameterizedType.getActualTypeArguments();
+        if (actualTypeArgs == null || actualTypeArgs.length != 2) {
+            throw new IllegalArgumentException(MessageFormat.format(
+                    "Map type [{0}] with unexpected amount of arguments [{1}]." + actualTypeArgs, new Object[] {
+                            type, actualTypeArgs }));
+        }
+
+        for (Type actualType : actualTypeArgs) {
+            if (actualType instanceof ParameterizedType) {
+                // Nested collection or map.
+                Class<?> rawType = (Class<?>) ((ParameterizedType) actualType).getRawType();
+                TypeDescriptorBuilder.build(actualType, rawType, typeCache);
+            } else if (actualType instanceof Class<?>) {
+                Class<?> actualClass = (Class<?>) actualType;
+                if (actualClass.isArray() || actualClass.isEnum()) {
+                    TypeDescriptorBuilder.build(null, actualClass, typeCache);
+                } else {
+                    DefaultTypeBuilder.build(actualClass, typeCache);
+                }
+            }
+        }
+
+        return new TypeDescriptor(type.toString());
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/ServiceDescriptorBuilder.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/ServiceDescriptorBuilder.java
new file mode 100644
index 0000000..046eed2
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/ServiceDescriptorBuilder.java
@@ -0,0 +1,71 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.MethodDescriptor;
+import org.apache.dubbo.servicedata.metadata.ServiceDescriptor;
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.net.URL;
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
+
+/**
+ *  2018/9/18
+ */
+public class ServiceDescriptorBuilder {
+
+    public static ServiceDescriptor build(final Class<?> interfaceClass) {
+        ServiceDescriptor sd = new ServiceDescriptor();
+        sd.setName(interfaceClass.getCanonicalName());
+        sd.setCodeSource(getCodeSource(interfaceClass));
+
+        TypeDescriptorBuilder builder = new TypeDescriptorBuilder();
+        Method[] methods = interfaceClass.getMethods();
+        for (Method method : methods) {
+            MethodDescriptor md = new MethodDescriptor();
+            md.setName(method.getName());
+
+            // Process parameter types.
+            Class<?>[] paramTypes = method.getParameterTypes();
+            Type[] genericParamTypes = method.getGenericParameterTypes();
+
+            String[] parameterTypes = new String[paramTypes.length];
+            for (int i = 0; i < paramTypes.length; i++) {
+                TypeDescriptor td = builder.build(genericParamTypes[i], paramTypes[i]);
+                parameterTypes[i] = td.getType();
+            }
+            md.setParameterTypes(parameterTypes);
+
+            // Process return type.
+            TypeDescriptor td = builder.build(method.getGenericReturnType(), method.getReturnType());
+            md.setReturnType(td.getType());
+
+            sd.getMethodDescriptors().add(md);
+        }
+
+        sd.setTypes(builder.getTypeDescriptorMap());
+        return sd;
+    }
+
+    static String getCodeSource(Class<?> clazz) {
+        ProtectionDomain protectionDomain = clazz.getProtectionDomain();
+        if (protectionDomain == null || protectionDomain.getCodeSource() == null) {
+            return null;
+        }
+
+        CodeSource codeSource = clazz.getProtectionDomain().getCodeSource();
+        URL location = codeSource.getLocation();
+        if (location == null) {
+            return null;
+        }
+
+        String path = codeSource.getLocation().toExternalForm();
+
+        if (path.endsWith(".jar") && path.contains("/")) {
+            return path.substring(path.lastIndexOf('/') + 1);
+        }
+        return path;
+    }
+
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/TypeBuilder.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/TypeBuilder.java
new file mode 100644
index 0000000..351b411
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/TypeBuilder.java
@@ -0,0 +1,23 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+
+import java.lang.reflect.Type;
+import java.util.Map;
+
+/**
+ *  2018/9/18
+ */
+public interface TypeBuilder {
+
+    /**
+     * Whether the build accept the type or class passed in.
+     */
+    boolean accept(Type type, Class<?> clazz);
+
+    /**
+     * Build type definition with the type or class.
+     */
+    TypeDescriptor build(Type type, Class<?> clazz, Map<Class<?>, TypeDescriptor> typeCache);
+
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/TypeDescriptorBuilder.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/TypeDescriptorBuilder.java
new file mode 100644
index 0000000..3d6d3a7
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/metadata/builder/TypeDescriptorBuilder.java
@@ -0,0 +1,63 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *  2018/9/18
+ */
+public class TypeDescriptorBuilder {
+
+    private static final List<TypeBuilder> builders = new ArrayList<TypeBuilder>();
+    private Map<Class<?>, TypeDescriptor> typeCache = new HashMap<Class<?>, TypeDescriptor>();
+
+
+    static {
+        builders.add(new ArrayTypeBuilder());
+        builders.add(new CollectionTypeBuilder());
+        builders.add(new MapTypeBuilder());
+        builders.add(new EnumTypeBuilder());
+    }
+
+
+    public static TypeDescriptor build(Type type, Class<?> clazz, Map<Class<?>, TypeDescriptor> typeCache) {
+        TypeBuilder builder = getGenericTypeBuilder(type, clazz);
+        TypeDescriptor td = null;
+        if (builder != null) {
+            td = builder.build(type, clazz, typeCache);
+        } else {
+            td = DefaultTypeBuilder.build(clazz, typeCache);
+        }
+        return td;
+    }
+
+    static TypeBuilder getGenericTypeBuilder(Type type, Class<?> clazz) {
+        for (TypeBuilder builder : builders) {
+            if (builder.accept(type, clazz)) {
+                return builder;
+            }
+        }
+        return null;
+    }
+
+    public TypeDescriptor build(Type type, Class<?> clazz) {
+        return build(type, clazz, typeCache);
+    }
+
+    public Map<String, TypeDescriptor> getTypeDescriptorMap() {
+        if (typeCache == null || typeCache.isEmpty()) {
+            return Collections.EMPTY_MAP;
+        }
+        Map<String, TypeDescriptor> typeDescriptorMap = new HashMap<>();
+        for (Map.Entry<Class<?>, TypeDescriptor> entry : typeCache.entrySet()) {
+            typeDescriptorMap.put(entry.getKey().getName(), entry.getValue());
+        }
+        return typeDescriptorMap;
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStore.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/store/ServiceStore.java
similarity index 97%
rename from dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStore.java
rename to dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/store/ServiceStore.java
index cfad3fc..7311d37 100644
--- a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStore.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/store/ServiceStore.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.servicedata;
+package org.apache.dubbo.servicedata.store;
 
 
 import org.apache.dubbo.common.URL;
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStoreFactory.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/store/ServiceStoreFactory.java
similarity index 96%
rename from dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStoreFactory.java
rename to dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/store/ServiceStoreFactory.java
index f5d351f..4ee5f03 100644
--- a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/ServiceStoreFactory.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/store/ServiceStoreFactory.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.servicedata;
+package org.apache.dubbo.servicedata.store;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.extension.Adaptive;
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStore.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStore.java
index 5002b52..01bc7a9 100644
--- a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStore.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStore.java
@@ -23,7 +23,7 @@ import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.ConcurrentHashSet;
 import org.apache.dubbo.common.utils.ConfigUtils;
 import org.apache.dubbo.common.utils.NamedThreadFactory;
-import org.apache.dubbo.servicedata.ServiceStore;
+import org.apache.dubbo.servicedata.store.ServiceStore;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -33,9 +33,7 @@ import java.io.InputStream;
 import java.io.RandomAccessFile;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileLock;
-import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactory.java b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactory.java
index 96fe7e9..cbc2c7c 100644
--- a/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactory.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/main/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactory.java
@@ -20,8 +20,8 @@ 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.servicedata.ServiceStore;
-import org.apache.dubbo.servicedata.ServiceStoreFactory;
+import org.apache.dubbo.servicedata.store.ServiceStore;
+import org.apache.dubbo.servicedata.store.ServiceStoreFactory;
 
 import java.util.Collection;
 import java.util.Collections;
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/InterfaceNameTestService.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/InterfaceNameTestService.java
new file mode 100644
index 0000000..486db23
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/InterfaceNameTestService.java
@@ -0,0 +1,9 @@
+package org.apache.dubbo.servicedata.integration;
+
+/**
+ *  2018/9/19
+ */
+public interface InterfaceNameTestService {
+
+    public void test();
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/InterfaceNameTestService2.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/InterfaceNameTestService2.java
new file mode 100644
index 0000000..b58f45a
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/InterfaceNameTestService2.java
@@ -0,0 +1,9 @@
+package org.apache.dubbo.servicedata.integration;
+
+/**
+ *  2018/9/19
+ */
+public interface InterfaceNameTestService2 {
+
+    public void test2();
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/ServiceStoreServiceTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/ServiceStoreServiceTest.java
index 75aa87c..8f22431 100644
--- a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/ServiceStoreServiceTest.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/integration/ServiceStoreServiceTest.java
@@ -1,7 +1,184 @@
 package org.apache.dubbo.servicedata.integration;
 
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.servicedata.store.test.JTestServiceStore4Test;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Supplier;
+
 /**
- * @author cvictory ON 2018/9/14
+ * 2018/9/14
  */
 public class ServiceStoreServiceTest {
+    URL url = URL.valueOf("JTest://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
+    ServiceStoreService serviceStoreService1;
+
+    @Before
+    public void before() {
+
+        serviceStoreService1 = ServiceStoreService.instance(new Supplier<URL>() {
+            @Override
+            public URL get() {
+                return url;
+            }
+        });
+    }
+
+    @Test
+    public void testInstance() {
+
+        ServiceStoreService serviceStoreService2 = ServiceStoreService.instance(new Supplier<URL>() {
+            @Override
+            public URL get() {
+                return url;
+            }
+        });
+        Assert.assertSame(serviceStoreService1, serviceStoreService2);
+        Assert.assertEquals(serviceStoreService1.serviceStoreUrl, url);
+    }
+
+    @Test
+    public void testPublishProviderNoInterfaceName() {
+
+
+        URL publishUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vicpubprovder");
+        serviceStoreService1.publishProvider(publishUrl);
+
+        Assert.assertTrue(serviceStoreService1.serviceStore instanceof JTestServiceStore4Test);
+        Assert.assertTrue(serviceStoreService1.providerURLs.size() >= 1);
+
+        JTestServiceStore4Test jTestServiceStore4Test = (JTestServiceStore4Test) serviceStoreService1.serviceStore;
+        Assert.assertTrue(jTestServiceStore4Test.store.containsKey(JTestServiceStore4Test.getKey(publishUrl)));
+
+        String value = jTestServiceStore4Test.store.get(JTestServiceStore4Test.getKey(publishUrl));
+        Map<String, String> map = queryUrlToMap(value);
+        Assert.assertEquals(map.get("application"), "vicpubprovder");
+        Assert.assertEquals(map.get("version"), "1.0.0");
+
+    }
+
+    @Test
+    public void testPublishProviderWrongInterface() {
+
+        URL publishUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vicpu&interface=ccc");
+        serviceStoreService1.publishProvider(publishUrl);
+
+        Assert.assertTrue(serviceStoreService1.serviceStore instanceof JTestServiceStore4Test);
+        Assert.assertTrue(serviceStoreService1.providerURLs.size() >= 1);
+
+        JTestServiceStore4Test jTestServiceStore4Test = (JTestServiceStore4Test) serviceStoreService1.serviceStore;
+        Assert.assertTrue(jTestServiceStore4Test.store.containsKey(JTestServiceStore4Test.getKey(publishUrl)));
+
+        String value = jTestServiceStore4Test.store.get(JTestServiceStore4Test.getKey(publishUrl));
+        Map<String, String> map = queryUrlToMap(value);
+        Assert.assertEquals(map.get("application"), "vicpu");
+        Assert.assertEquals(map.get("version"), "1.0.0");
+        Assert.assertEquals(map.get("interface"), "ccc");
+        Assert.assertNull(map.get(Constants.SERVICE_DESCIPTOR_KEY));
+    }
+
+    @Test
+    public void testPublishProviderContainInterface() {
+
+        URL publishUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.3&application=vicpubp&interface=org.apache.dubbo.servicedata.integration.InterfaceNameTestService");
+        serviceStoreService1.publishProvider(publishUrl);
+
+        Assert.assertTrue(serviceStoreService1.serviceStore instanceof JTestServiceStore4Test);
+        Assert.assertTrue(serviceStoreService1.providerURLs.size() >= 1);
+
+        JTestServiceStore4Test jTestServiceStore4Test = (JTestServiceStore4Test) serviceStoreService1.serviceStore;
+        Assert.assertTrue(jTestServiceStore4Test.store.containsKey(JTestServiceStore4Test.getKey(publishUrl)));
+
+        String value = jTestServiceStore4Test.store.get(JTestServiceStore4Test.getKey(publishUrl));
+        Map<String, String> map = queryUrlToMap(value);
+        Assert.assertEquals(map.get("application"), "vicpubp");
+        Assert.assertEquals(map.get("version"), "1.0.3");
+        Assert.assertEquals(map.get("interface"), "org.apache.dubbo.servicedata.integration.InterfaceNameTestService");
+        Assert.assertNotNull(map.get(Constants.SERVICE_DESCIPTOR_KEY));
+    }
+
+    @Test
+    public void testPublishConsumer() {
+
+        URL publishUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.x&application=vicpubconsumer&side=consumer");
+        serviceStoreService1.publishConsumer(publishUrl);
+
+        Assert.assertTrue(serviceStoreService1.serviceStore instanceof JTestServiceStore4Test);
+        Assert.assertTrue(serviceStoreService1.consumerURLs.size() >= 1);
+
+        JTestServiceStore4Test jTestServiceStore4Test = (JTestServiceStore4Test) serviceStoreService1.serviceStore;
+        Assert.assertTrue(jTestServiceStore4Test.store.containsKey(JTestServiceStore4Test.getKey(publishUrl)));
+
+        String value = jTestServiceStore4Test.store.get(JTestServiceStore4Test.getKey(publishUrl));
+        Map<String, String> map = queryUrlToMap(value);
+        Assert.assertEquals(map.get("application"), "vicpubconsumer");
+        Assert.assertEquals(map.get("version"), "1.0.x");
+
+    }
+
+    @Test
+    public void testPublishAll() {
+        //need single url
+        URL urlTmp = URL.valueOf("JTest://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestSingleService?version=1.x.x&application=vicss");
+        ServiceStoreService serviceStoreService2 = new ServiceStoreService(urlTmp);
+        URL publishUrl = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vicpubprovder");
+        serviceStoreService2.publishProvider(publishUrl);
+        serviceStoreService2.publishProvider(publishUrl);
+        URL publishUrl2 = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.3&application=vicpubp&interface=org.apache.dubbo.servicedata.integration.InterfaceNameTestService");
+        serviceStoreService2.publishProvider(publishUrl2);
+        URL publishUrl3 = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.x&application=vicpubconsumer&side=consumer");
+        serviceStoreService2.publishConsumer(publishUrl3);
+
+        Assert.assertTrue(serviceStoreService2.providerURLs.size() == 2);
+        Assert.assertTrue(serviceStoreService2.consumerURLs.size() == 1);
+
+        JTestServiceStore4Test jTestServiceStore4Test = (JTestServiceStore4Test) serviceStoreService2.serviceStore;
+        checkParam(jTestServiceStore4Test, publishUrl, "vicpubprovder", "1.0.0", null);
+        checkParam(jTestServiceStore4Test, publishUrl2, "vicpubp", "1.0.3", "org.apache.dubbo.servicedata.integration.InterfaceNameTestService");
+        checkParam(jTestServiceStore4Test, publishUrl3, "vicpubconsumer", "1.0.x", null);
+
+        Assert.assertTrue(jTestServiceStore4Test.store.size() == 3);
+
+
+        jTestServiceStore4Test.store.clear();
+        Assert.assertTrue(jTestServiceStore4Test.store.isEmpty());
+
+        //test
+        serviceStoreService2.publishAll();
+        Assert.assertTrue(jTestServiceStore4Test.store.size() == 3);
+
+        checkParam(jTestServiceStore4Test, publishUrl, "vicpubprovder", "1.0.0", null);
+        checkParam(jTestServiceStore4Test, publishUrl2, "vicpubp", "1.0.3", "org.apache.dubbo.servicedata.integration.InterfaceNameTestService");
+        checkParam(jTestServiceStore4Test, publishUrl3, "vicpubconsumer", "1.0.x", null);
+    }
+
+    private void checkParam(JTestServiceStore4Test jTestServiceStore4Test, URL publishUrl, String application, String version, String interfaceName) {
+        String value = jTestServiceStore4Test.store.get(JTestServiceStore4Test.getKey(publishUrl));
+        Map<String, String> map = queryUrlToMap(value);
+        Assert.assertEquals(map.get("application"), application);
+        Assert.assertEquals(map.get("version"), version);
+        Assert.assertEquals(map.get("interface"), interfaceName);
+    }
+
+
+    private Map<String, String> queryUrlToMap(String urlQuery) {
+        if (urlQuery == null) {
+            return Collections.emptyMap();
+        }
+        String[] pairs = urlQuery.split("&");
+        Map<String, String> map = new HashMap<>();
+        for (String pairStr : pairs) {
+            String[] pair = pairStr.split("=");
+            map.put(pair[0], pair[1]);
+        }
+        return map;
+    }
+
 }
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ArrayTypeBuilderTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ArrayTypeBuilderTest.java
new file mode 100644
index 0000000..f2542ea
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ArrayTypeBuilderTest.java
@@ -0,0 +1,91 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *  2018/9/20
+ */
+public class ArrayTypeBuilderTest {
+
+    private ArrayTypeBuilder arrayTypeBuilder = new ArrayTypeBuilder();
+
+    @Test
+    public void testAcceptWhenArray() {
+        String[] param = new String[2];
+        Class c = param.getClass();
+        Assert.assertTrue(arrayTypeBuilder.accept(null, c));
+    }
+
+    @Test
+    public void testAcceptWhenNull() {
+        Assert.assertFalse(arrayTypeBuilder.accept(null, null));
+    }
+
+    @Test
+    public void testAcceptWhenOtherClass() {
+        Assert.assertFalse(arrayTypeBuilder.accept(null, Array.class));
+    }
+
+    @Test
+    public void testBuildWhenSimpleArray() throws NoSuchMethodException {
+        Class targetClass = TestService.class;
+        Method method = targetClass.getMethod("testWriteSimpleArray", String[].class);
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        Class<?>[] paramTypes = method.getParameterTypes();
+        Type[] genericParamTypes = method.getGenericParameterTypes();
+
+        TypeDescriptor td = arrayTypeBuilder.build(genericParamTypes[0], paramTypes[0], cache);
+        System.out.println(td);
+        Assert.assertNotNull(td);
+        Assert.assertEquals(td.getType(), "java.lang.String[]");
+
+        Method readMethod = targetClass.getMethod("testReadSimpleArray", int.class);
+        Class returnType = readMethod.getReturnType();
+        Type genericReturnType = readMethod.getGenericReturnType();
+        TypeDescriptor rTd = arrayTypeBuilder.build(genericReturnType, returnType, cache);
+        Assert.assertNotNull(rTd);
+        Assert.assertEquals(rTd.getType(), "java.lang.String[]");
+
+        Assert.assertTrue(cache.isEmpty());
+    }
+
+    @Test
+    public void testBuildWhenComplexArray() throws NoSuchMethodException {
+        Class targetClass = TestService.class;
+        Method method = targetClass.getMethod("testWriteComplexArray", String[].class, ComplexObject[].class);
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        Class<?>[] paramTypes = method.getParameterTypes();
+        Type[] genericParamTypes = method.getGenericParameterTypes();
+
+        TypeDescriptor td1 = arrayTypeBuilder.build(genericParamTypes[0], paramTypes[0], cache);
+        System.out.println(td1);
+        Assert.assertNotNull(td1);
+        Assert.assertEquals(td1.getType(), "java.lang.String[]");
+
+        TypeDescriptor td2 = arrayTypeBuilder.build(genericParamTypes[1], paramTypes[1], cache);
+        System.out.println(td2);
+        Assert.assertNotNull(td2);
+        Assert.assertEquals(td2.getType(), "org.apache.dubbo.servicedata.metadata.builder.ComplexObject[]");
+
+        Method readMethod = targetClass.getMethod("testReadComplexArray", int.class);
+        Class returnType = readMethod.getReturnType();
+        Type genericReturnType = readMethod.getGenericReturnType();
+        TypeDescriptor rTd = arrayTypeBuilder.build(genericReturnType, returnType, cache);
+        Assert.assertNotNull(rTd);
+        Assert.assertEquals(rTd.getType(), "org.apache.dubbo.servicedata.metadata.builder.ComplexObject[]");
+
+        Assert.assertTrue(cache.size() == 2);
+        Assert.assertTrue(cache.get(ComplexObject.class) != null);
+        Assert.assertEquals(cache.get(ComplexObject.class).getType(), "org.apache.dubbo.servicedata.metadata.builder.ComplexObject");
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/CollectionTypeBuilderTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/CollectionTypeBuilderTest.java
new file mode 100644
index 0000000..91c9edf
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/CollectionTypeBuilderTest.java
@@ -0,0 +1,91 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *  2018/9/20
+ */
+public class CollectionTypeBuilderTest {
+
+    private CollectionTypeBuilder collectionTypeBuilder = new CollectionTypeBuilder();
+
+    @Test
+    public void testAcceptWhenNotCollection() {
+        String[] param = new String[2];
+        Class c = param.getClass();
+        Assert.assertFalse(collectionTypeBuilder.accept(null, c));
+    }
+
+    @Test
+    public void testAcceptWhenNull() {
+        Assert.assertFalse(collectionTypeBuilder.accept(null, null));
+    }
+
+    @Test
+    public void testAcceptWhenCollection() {
+        Assert.assertTrue(collectionTypeBuilder.accept(null, ArrayList.class));
+    }
+
+    @Test
+    public void testBuildWhenSimpleList() throws NoSuchMethodException {
+        Class targetClass = TestService.class;
+        Method method = targetClass.getMethod("testWriteSimpleCollection", List.class);
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        Class<?>[] paramTypes = method.getParameterTypes();
+        Type[] genericParamTypes = method.getGenericParameterTypes();
+
+        TypeDescriptor td = collectionTypeBuilder.build(genericParamTypes[0], paramTypes[0], cache);
+        System.out.println(td);
+        Assert.assertNotNull(td);
+        Assert.assertEquals(td.getType(), "java.util.List<java.lang.String>");
+
+        Method readMethod = targetClass.getMethod("testReadSimpleCollection", int.class);
+        Class returnType = readMethod.getReturnType();
+        Type genericReturnType = readMethod.getGenericReturnType();
+        TypeDescriptor rTd = collectionTypeBuilder.build(genericReturnType, returnType, cache);
+        Assert.assertNotNull(rTd);
+        Assert.assertEquals(rTd.getType(), "java.util.List<java.lang.Integer>");
+
+        Assert.assertTrue(cache.isEmpty());
+    }
+
+    @Test
+    public void testBuildWhenComplexList() throws NoSuchMethodException {
+        Class targetClass = TestService.class;
+        Method method = targetClass.getMethod("testWriteComplexCollection", List.class, List.class);
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        Class<?>[] paramTypes = method.getParameterTypes();
+        Type[] genericParamTypes = method.getGenericParameterTypes();
+
+        TypeDescriptor td1 = collectionTypeBuilder.build(genericParamTypes[0], paramTypes[0], cache);
+        System.out.println(td1);
+        Assert.assertNotNull(td1);
+        Assert.assertEquals(td1.getType(), "java.util.List<java.lang.Long>");
+
+        TypeDescriptor td2 = collectionTypeBuilder.build(genericParamTypes[1], paramTypes[1], cache);
+        System.out.println(td2);
+        Assert.assertNotNull(td2);
+        Assert.assertEquals(td2.getType(), "java.util.List<org.apache.dubbo.servicedata.metadata.builder.ComplexObject>");
+
+        Method readMethod = targetClass.getMethod("testReadComplexCollection", int.class);
+        Class returnType = readMethod.getReturnType();
+        Type genericReturnType = readMethod.getGenericReturnType();
+        TypeDescriptor rTd = collectionTypeBuilder.build(genericReturnType, returnType, cache);
+        Assert.assertNotNull(rTd);
+        Assert.assertEquals(rTd.getType(), "java.util.Set<org.apache.dubbo.servicedata.metadata.builder.ComplexObject>");
+
+        Assert.assertTrue(cache.size() == 2);
+        Assert.assertTrue(cache.get(ComplexObject.class) != null);
+        Assert.assertEquals(cache.get(ComplexObject.class).getType(), "org.apache.dubbo.servicedata.metadata.builder.ComplexObject");
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ComplexEnum.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ComplexEnum.java
new file mode 100644
index 0000000..0a637a0
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ComplexEnum.java
@@ -0,0 +1,16 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+/**
+ *  2018/9/28
+ */
+public enum ComplexEnum {
+    F(11, "t1"), S(22, "t2"), T(33, "t1");
+
+    ComplexEnum(int code, String message) {
+        this.code = code;
+        this.msg = message;
+    }
+
+    private int code;
+    private String msg;
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ComplexObject.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ComplexObject.java
new file mode 100644
index 0000000..6de58d4
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ComplexObject.java
@@ -0,0 +1,37 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ *  2018/9/28
+ */
+public class ComplexObject {
+
+    private static boolean test;
+
+    private String[] strArray;
+    private List<Integer> integerList;
+    private short s;
+    private Map<String, Long> testMap;
+    private ComplexInnerObject complexInnerObject;
+
+    public List<Integer> getIntegerList() {
+        return integerList;
+    }
+
+    public void setIntegerList(List<Integer> integerList) {
+        this.integerList = integerList;
+    }
+
+    public short getS() {
+        return s;
+    }
+
+    public void setS(short s) {
+        this.s = s;
+    }
+    static class ComplexInnerObject{
+        private String str;
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/DefaultTypeBuilderTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/DefaultTypeBuilderTest.java
new file mode 100644
index 0000000..f0644a0
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/DefaultTypeBuilderTest.java
@@ -0,0 +1,64 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *  2018/9/28
+ */
+public class DefaultTypeBuilderTest {
+
+    @Test
+    public void testWhenBigDecimal() {
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        TypeDescriptor td = DefaultTypeBuilder.build(BigDecimal.class, cache);
+        Assert.assertNotNull(td);
+        Assert.assertEquals(td.getType(), "java.math.BigDecimal");
+        Assert.assertFalse(td.isCustom());
+
+        Assert.assertTrue(cache.isEmpty());
+    }
+
+    @Test
+    public void testWhenString() {
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        TypeDescriptor td = DefaultTypeBuilder.build(String.class, cache);
+        Assert.assertNotNull(td);
+        Assert.assertEquals(td.getType(), "java.lang.String");
+        Assert.assertFalse(td.isCustom());
+
+        Assert.assertTrue(cache.isEmpty());
+    }
+
+    @Test
+    public void testWhenInt() {
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        TypeDescriptor td = DefaultTypeBuilder.build(int.class, cache);
+        Assert.assertNotNull(td);
+        Assert.assertEquals(td.getType(), "int");
+        Assert.assertFalse(td.isCustom());
+
+        Assert.assertTrue(cache.isEmpty());
+    }
+
+    @Test
+    public void testWhenComplextObject() {
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        TypeDescriptor td = DefaultTypeBuilder.build(ComplexObject.class, cache);
+        Assert.assertNotNull(td);
+        Assert.assertEquals(td.getType(), "org.apache.dubbo.servicedata.metadata.builder.ComplexObject");
+        Assert.assertTrue(td.isCustom());
+        Assert.assertTrue(td.getProperties().entrySet().size() >= 4);
+
+        Assert.assertTrue(cache.size() == 2);
+        Assert.assertEquals(td, cache.get(ComplexObject.class));
+        Assert.assertNotNull(cache.get(ComplexObject.ComplexInnerObject.class));
+    }
+
+
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/EnumTypeBuilderTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/EnumTypeBuilderTest.java
new file mode 100644
index 0000000..d585fbc
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/EnumTypeBuilderTest.java
@@ -0,0 +1,85 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *  2018/9/20
+ */
+public class EnumTypeBuilderTest {
+
+    private EnumTypeBuilder enumTypeBuilder = new EnumTypeBuilder();
+
+    @Test
+    public void testAcceptWhenEnum() {
+        Class c = SingleEnum.class;
+        Assert.assertTrue(enumTypeBuilder.accept(null, c));
+    }
+
+    @Test
+    public void testAcceptWhenNull() {
+        Assert.assertFalse(enumTypeBuilder.accept(null, null));
+    }
+
+    @Test
+    public void testAcceptWhenNotEnum() {
+        Assert.assertFalse(enumTypeBuilder.accept(null, ArrayList.class));
+    }
+
+    @Test
+    public void testBuildWhenSingleEnum() throws NoSuchMethodException {
+        Class targetClass = TestService.class;
+        Method method = targetClass.getMethod("testWriteSingleEnum", SingleEnum.class);
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        Class<?>[] paramTypes = method.getParameterTypes();
+        Type[] genericParamTypes = method.getGenericParameterTypes();
+
+        TypeDescriptor td = enumTypeBuilder.build(genericParamTypes[0], paramTypes[0], cache);
+        System.out.println(td);
+        Assert.assertNotNull(td);
+        Assert.assertEquals(td.getType(), "org.apache.dubbo.servicedata.metadata.builder.SingleEnum");
+
+        Method readMethod = targetClass.getMethod("testReadSingleEnum", int.class);
+        Class returnType = readMethod.getReturnType();
+        Type genericReturnType = readMethod.getGenericReturnType();
+        TypeDescriptor rTd = enumTypeBuilder.build(genericReturnType, returnType, cache);
+        Assert.assertNotNull(rTd);
+        Assert.assertEquals(rTd.getType(), "org.apache.dubbo.servicedata.metadata.builder.SingleEnum");
+
+        Assert.assertFalse(cache.isEmpty());
+    }
+
+    @Test
+    public void testBuildWhenComplexEnum() throws NoSuchMethodException {
+        Class targetClass = TestService.class;
+        Method method = targetClass.getMethod("testWriteComplexEnum", ComplexEnum.class);
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        Class<?>[] paramTypes = method.getParameterTypes();
+        Type[] genericParamTypes = method.getGenericParameterTypes();
+
+
+        TypeDescriptor td2 = enumTypeBuilder.build(genericParamTypes[0], paramTypes[0], cache);
+        System.out.println(td2);
+        Assert.assertNotNull(td2);
+        Assert.assertEquals(td2.getType(), "org.apache.dubbo.servicedata.metadata.builder.ComplexEnum");
+
+        Method readMethod = targetClass.getMethod("testReadComplexEnum", int.class);
+        Class returnType = readMethod.getReturnType();
+        Type genericReturnType = readMethod.getGenericReturnType();
+        TypeDescriptor rTd = enumTypeBuilder.build(genericReturnType, returnType, cache);
+        Assert.assertNotNull(rTd);
+        Assert.assertEquals(rTd.getType(), "org.apache.dubbo.servicedata.metadata.builder.ComplexEnum");
+
+        Assert.assertTrue(cache.size() == 1);
+        Assert.assertTrue(cache.get(ComplexEnum.class) != null);
+        Assert.assertEquals(cache.get(ComplexEnum.class).getType(), "org.apache.dubbo.servicedata.metadata.builder.ComplexEnum");
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/MapTypeBuilderTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/MapTypeBuilderTest.java
new file mode 100644
index 0000000..fe39833
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/MapTypeBuilderTest.java
@@ -0,0 +1,90 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *  2018/9/20
+ */
+public class MapTypeBuilderTest {
+
+    private MapTypeBuilder mapTypeBuilder = new MapTypeBuilder();
+
+    @Test
+    public void testAcceptWhenMap() {
+        String[] param = new String[2];
+        Class c = param.getClass();
+        Assert.assertFalse(mapTypeBuilder.accept(null, c));
+    }
+
+    @Test
+    public void testAcceptWhenNull() {
+        Assert.assertFalse(mapTypeBuilder.accept(null, null));
+    }
+
+    @Test
+    public void testAcceptWhenNotMap() {
+        Assert.assertFalse(mapTypeBuilder.accept(null, ArrayList.class));
+    }
+
+    @Test
+    public void testBuildWhenSimpleMap() throws NoSuchMethodException {
+        Class targetClass = TestService.class;
+        Method method = targetClass.getMethod("testWriteSimpleMap", Map.class);
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        Class<?>[] paramTypes = method.getParameterTypes();
+        Type[] genericParamTypes = method.getGenericParameterTypes();
+
+        TypeDescriptor td = mapTypeBuilder.build(genericParamTypes[0], paramTypes[0], cache);
+        System.out.println(td);
+        Assert.assertNotNull(td);
+        Assert.assertEquals(td.getType(), "java.util.Map<java.lang.String, java.lang.Integer>");
+
+        Method readMethod = targetClass.getMethod("testReadSimpleMap", int.class);
+        Class returnType = readMethod.getReturnType();
+        Type genericReturnType = readMethod.getGenericReturnType();
+        TypeDescriptor rTd = mapTypeBuilder.build(genericReturnType, returnType, cache);
+        Assert.assertNotNull(rTd);
+        Assert.assertEquals(rTd.getType(), "java.util.Map<java.lang.String, java.lang.Integer>");
+
+        Assert.assertTrue(cache.isEmpty());
+    }
+
+    @Test
+    public void testBuildWhenComplexMap() throws NoSuchMethodException {
+        Class targetClass = TestService.class;
+        Method method = targetClass.getMethod("testWriteComplexMap", Map.class, Map.class);
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        Class<?>[] paramTypes = method.getParameterTypes();
+        Type[] genericParamTypes = method.getGenericParameterTypes();
+
+        TypeDescriptor td1 = mapTypeBuilder.build(genericParamTypes[0], paramTypes[0], cache);
+        System.out.println(td1);
+        Assert.assertNotNull(td1);
+        Assert.assertEquals(td1.getType(), "java.util.Map<java.lang.String, java.lang.String>");
+
+        TypeDescriptor td2 = mapTypeBuilder.build(genericParamTypes[1], paramTypes[1], cache);
+        System.out.println(td2);
+        Assert.assertNotNull(td2);
+        Assert.assertEquals(td2.getType(), "java.util.Map<java.lang.String, org.apache.dubbo.servicedata.metadata.builder.ComplexObject>");
+
+        Method readMethod = targetClass.getMethod("testReadComplexMap", int.class);
+        Class returnType = readMethod.getReturnType();
+        Type genericReturnType = readMethod.getGenericReturnType();
+        TypeDescriptor rTd = mapTypeBuilder.build(genericReturnType, returnType, cache);
+        Assert.assertNotNull(rTd);
+        Assert.assertEquals(rTd.getType(), "java.util.Map<java.lang.String, org.apache.dubbo.servicedata.metadata.builder.ComplexObject>");
+
+        Assert.assertTrue(cache.size() == 2);
+        Assert.assertTrue(cache.get(ComplexObject.class) != null);
+        Assert.assertEquals(cache.get(ComplexObject.class).getType(), "org.apache.dubbo.servicedata.metadata.builder.ComplexObject");
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ServiceDescriptorBuilderTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ServiceDescriptorBuilderTest.java
new file mode 100644
index 0000000..1c76882
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/ServiceDescriptorBuilderTest.java
@@ -0,0 +1,25 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.ServiceDescriptor;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *  2018/9/29
+ */
+public class ServiceDescriptorBuilderTest {
+
+    @Test
+    public void testGetCodeSource(){
+        String codeSource = ServiceDescriptorBuilder.getCodeSource(ServiceDescriptorBuilder.class);
+        Assert.assertNotNull(codeSource);
+    }
+
+    @Test
+    public void testBuild(){
+        ServiceDescriptor serviceDescriptor = ServiceDescriptorBuilder.build(TestService.class);
+        Assert.assertNotNull(serviceDescriptor);
+        Assert.assertTrue(serviceDescriptor.getMethodDescriptors().size() == 17);
+        Assert.assertTrue(serviceDescriptor.getTypes().size() == 4);
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/SingleEnum.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/SingleEnum.java
new file mode 100644
index 0000000..a9a2deb
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/SingleEnum.java
@@ -0,0 +1,8 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+/**
+ *  2018/9/28
+ */
+public enum SingleEnum {
+    FIRST,SECOND
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/TestService.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/TestService.java
new file mode 100644
index 0000000..d3c6fad
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/TestService.java
@@ -0,0 +1,45 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 2018/9/28
+ */
+public interface TestService {
+
+    void testWriteSimpleArray(String[] args);
+
+    String[] testReadSimpleArray(int i);
+
+    void testWriteComplexArray(String[] args, ComplexObject[] complexObjects);
+
+    ComplexObject[] testReadComplexArray(int i);
+
+    void testWriteSimpleCollection(List<String> args);
+
+    List<Integer> testReadSimpleCollection(int i);
+
+    void testWriteComplexCollection(List<Long> args, List<ComplexObject> complexObjects);
+
+    Set<ComplexObject> testReadComplexCollection(int i);
+
+    void testWriteSingleEnum(SingleEnum singleEnum);
+
+    SingleEnum testReadSingleEnum(int i);
+
+    void testWriteComplexEnum(ComplexEnum complexEnum);
+
+    ComplexEnum testReadComplexEnum(int i);
+
+    void testWriteSimpleMap(Map<String, Integer> args);
+
+    Map<String, Integer> testReadSimpleMap(int i);
+
+    void testWriteComplexMap(Map<String, String> arg, Map<String, ComplexObject> complexObjects);
+
+    Map<String, ComplexObject> testReadComplexMap(int i);
+
+    void testWriteComplexObject(ComplexObject complexObject);
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/TypeDescriptorBuilderTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/TypeDescriptorBuilderTest.java
new file mode 100644
index 0000000..fd072cc
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/metadata/builder/TypeDescriptorBuilderTest.java
@@ -0,0 +1,101 @@
+package org.apache.dubbo.servicedata.metadata.builder;
+
+import org.apache.dubbo.servicedata.metadata.TypeDescriptor;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *  2018/9/29
+ */
+public class TypeDescriptorBuilderTest {
+
+
+    @Test
+    public void testStaticBuildWhenSimpleArray() throws NoSuchMethodException {
+        Class targetClass = TestService.class;
+        Method method = targetClass.getMethod("testWriteSimpleArray", String[].class);
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        Class<?>[] paramTypes = method.getParameterTypes();
+        Type[] genericParamTypes = method.getGenericParameterTypes();
+
+        TypeDescriptor td = TypeDescriptorBuilder.build(genericParamTypes[0], paramTypes[0], cache);
+        System.out.println(td);
+        Assert.assertNotNull(td);
+        Assert.assertEquals(td.getType(), "java.lang.String[]");
+
+        Method readMethod = targetClass.getMethod("testReadSimpleArray", int.class);
+        Class returnType = readMethod.getReturnType();
+        Type genericReturnType = readMethod.getGenericReturnType();
+        TypeDescriptor rTd = TypeDescriptorBuilder.build(genericReturnType, returnType, cache);
+        Assert.assertNotNull(rTd);
+        Assert.assertEquals(rTd.getType(), "java.lang.String[]");
+
+        Assert.assertTrue(cache.isEmpty());
+    }
+
+    @Test
+    public void testStaticBuildWhenComplextObject() throws NoSuchMethodException {
+
+        Class targetClass = TestService.class;
+        Method method = targetClass.getMethod("testWriteComplexObject", ComplexObject.class);
+        Map<Class<?>, TypeDescriptor> cache = new HashMap<Class<?>, TypeDescriptor>();
+        Class<?>[] paramTypes = method.getParameterTypes();
+        Type[] genericParamTypes = method.getGenericParameterTypes();
+
+
+        TypeDescriptor td = TypeDescriptorBuilder.build(genericParamTypes[0], paramTypes[0], cache);
+        Assert.assertNotNull(td);
+        Assert.assertEquals(td.getType(), "org.apache.dubbo.servicedata.metadata.builder.ComplexObject");
+        Assert.assertTrue(td.isCustom());
+        Assert.assertTrue(td.getProperties().entrySet().size() >= 4);
+
+        Assert.assertTrue(cache.size() == 2);
+        Assert.assertEquals(td, cache.get(ComplexObject.class));
+        Assert.assertNotNull(cache.get(ComplexObject.ComplexInnerObject.class));
+    }
+
+    /**
+     * test builder and getTypeDescriptorMap method.
+     *
+     * @throws NoSuchMethodException
+     */
+    @Test
+    public void testBuildWhenComplextObject() throws NoSuchMethodException {
+        TypeDescriptorBuilder typeDescriptorBuilder = new TypeDescriptorBuilder();
+
+        Class targetClass = TestService.class;
+        Method method = targetClass.getMethod("testWriteComplexObject", ComplexObject.class);
+        Class<?>[] paramTypes = method.getParameterTypes();
+        Type[] genericParamTypes = method.getGenericParameterTypes();
+
+
+        TypeDescriptor td = typeDescriptorBuilder.build(genericParamTypes[0], paramTypes[0]);
+        Assert.assertNotNull(td);
+        Assert.assertEquals(td.getType(), "org.apache.dubbo.servicedata.metadata.builder.ComplexObject");
+        Assert.assertTrue(td.isCustom());
+        Assert.assertTrue(td.getProperties().entrySet().size() >= 4);
+
+        Assert.assertTrue(typeDescriptorBuilder.getTypeDescriptorMap().size() == 2);
+        Assert.assertEquals(td, typeDescriptorBuilder.getTypeDescriptorMap().get(ComplexObject.class.getName()));
+        Assert.assertNotNull(typeDescriptorBuilder.getTypeDescriptorMap().get(ComplexObject.ComplexInnerObject.class.getName()));
+    }
+
+    @Test
+    public void testGetGenericTypeBuilder() {
+        Assert.assertNull(TypeDescriptorBuilder.getGenericTypeBuilder(null, ComplexObject.class));
+        Assert.assertNotNull(TypeDescriptorBuilder.getGenericTypeBuilder(null, String[].class));
+        Assert.assertTrue(TypeDescriptorBuilder.getGenericTypeBuilder(null, String[].class) instanceof ArrayTypeBuilder);
+        Assert.assertNotNull(TypeDescriptorBuilder.getGenericTypeBuilder(null, ArrayList.class));
+        Assert.assertTrue(TypeDescriptorBuilder.getGenericTypeBuilder(null, ArrayList.class) instanceof CollectionTypeBuilder);
+        Assert.assertNotNull(TypeDescriptorBuilder.getGenericTypeBuilder(null, HashMap.class));
+        Assert.assertTrue(TypeDescriptorBuilder.getGenericTypeBuilder(null, HashMap.class) instanceof MapTypeBuilder);
+        Assert.assertNotNull(TypeDescriptorBuilder.getGenericTypeBuilder(null, SingleEnum.class));
+        Assert.assertTrue(TypeDescriptorBuilder.getGenericTypeBuilder(null, SingleEnum.class) instanceof EnumTypeBuilder);
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStore.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/store/test/JTestServiceStore4Test.java
similarity index 51%
copy from dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStore.java
copy to dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/store/test/JTestServiceStore4Test.java
index 52a2861..833eba9 100644
--- a/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStore.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/store/test/JTestServiceStore4Test.java
@@ -14,60 +14,52 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.servicedata.redis;
+package org.apache.dubbo.servicedata.store.test;
 
 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.rpc.RpcException;
+import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
 import org.apache.dubbo.servicedata.support.AbstractServiceStore;
-import redis.clients.jedis.Jedis;
-import redis.clients.jedis.JedisPool;
-import redis.clients.jedis.JedisPoolConfig;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * ZookeeperRegistry
  */
-public class RedisServiceStore extends AbstractServiceStore {
+public class JTestServiceStore4Test extends AbstractServiceStore {
 
-    private final static Logger logger = LoggerFactory.getLogger(RedisServiceStore.class);
+    private final static Logger logger = LoggerFactory.getLogger(JTestServiceStore4Test.class);
 
-    private final static String TAG = "sd.";
 
-    private final JedisPool pool;
 
-    public RedisServiceStore(URL url) {
+    public JTestServiceStore4Test(URL url, ZookeeperTransporter zookeeperTransporter) {
         super(url);
-        pool = new JedisPool(new JedisPoolConfig(), url.getHost(), url.getPort());
     }
 
+    public Map<String, String> store = new ConcurrentHashMap<>();
+
     @Override
     protected void doPutService(URL url) {
-        try (Jedis jedis = pool.getResource()) {
-            jedis.set(TAG + getProtocol(url) + "." + url.getServiceKey(), url.toParameterString());
-        } catch (Throwable e) {
-            logger.error("Failed to put " + url + " to redis " + url + ", cause: " + e.getMessage(), e);
-            throw new RpcException("Failed to put " + url + " to redis " + getUrl() + ", cause: " + e.getMessage(), e);
-        }
+        store.put(getKey(url), url.toParameterString());
     }
 
     @Override
     protected URL doPeekService(URL url) {
-        try (Jedis jedis = pool.getResource()) {
-            String value = jedis.get(TAG + getProtocol(url) + "." + url.getServiceKey());
-            return url.addParameterString(value);
-        } catch (Throwable e) {
-            logger.error("Failed to peek " + url + " to redis " + url + ", cause: " + e.getMessage(), e);
-            throw new RpcException("Failed to put " + url + " to redis " + getUrl() + ", cause: " + e.getMessage(), e);
-        }
+        String queryV = store.get(getKey(url));
+        return url.clearParameters().addParameterString(queryV);
     }
 
-    private String getProtocol(URL url) {
+    private static String getProtocol(URL url) {
         String protocol = url.getParameter(Constants.SIDE_KEY);
         protocol = protocol == null ? url.getProtocol() : protocol;
         return protocol;
     }
 
+    public static String getKey(URL url){
+        return getProtocol(url) + url.getServiceKey();
+    }
 
 }
diff --git a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStoreFactory.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/store/test/JTestServiceStoreFactory4Test.java
similarity index 83%
copy from dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStoreFactory.java
copy to dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/store/test/JTestServiceStoreFactory4Test.java
index 4f0deb8..bfb1ac9 100644
--- a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStoreFactory.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/store/test/JTestServiceStoreFactory4Test.java
@@ -14,18 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.servicedata.zookeeper;
+package org.apache.dubbo.servicedata.store.test;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
-import org.apache.dubbo.servicedata.ServiceStore;
+import org.apache.dubbo.servicedata.store.ServiceStore;
 import org.apache.dubbo.servicedata.support.AbstractServiceStoreFactory;
 
 /**
  * ZookeeperRegistryFactory.
  *
  */
-public class ZookeeperServiceStoreFactory extends AbstractServiceStoreFactory {
+public class JTestServiceStoreFactory4Test extends AbstractServiceStoreFactory {
 
     private ZookeeperTransporter zookeeperTransporter;
 
@@ -35,7 +35,7 @@ public class ZookeeperServiceStoreFactory extends AbstractServiceStoreFactory {
 
     @Override
     public ServiceStore createServiceStore(URL url) {
-        return new ZookeeperServiceStore(url, zookeeperTransporter);
+        return new JTestServiceStore4Test(url, zookeeperTransporter);
     }
 
 }
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactoryTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactoryTest.java
index 94cf1bf..855d9a3 100644
--- a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactoryTest.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreFactoryTest.java
@@ -2,7 +2,7 @@ package org.apache.dubbo.servicedata.support;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.servicedata.ServiceStore;
+import org.apache.dubbo.servicedata.store.ServiceStore;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -10,7 +10,7 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
- * @author cvictory ON 2018/9/14
+ *  2018/9/14
  */
 public class AbstractServiceStoreFactoryTest {
 
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreTest.java b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreTest.java
index 2134296..4df7f47 100644
--- a/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreTest.java
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/java/org/apache/dubbo/servicedata/support/AbstractServiceStoreTest.java
@@ -33,14 +33,12 @@ import java.util.concurrent.ConcurrentHashMap;
 public class AbstractServiceStoreTest {
 
     private NewServiceStore abstractServiceStore;
-    private NewServiceStore singleServiceStore;
+
 
     @Before
     public void before() {
         URL url = URL.valueOf("zookeeper://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
         abstractServiceStore = new NewServiceStore(url);
-        URL singleUrl = URL.valueOf("redis://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=singleTest");
-        singleServiceStore = new NewServiceStore(singleUrl);
     }
 
     @Test
@@ -68,6 +66,10 @@ public class AbstractServiceStoreTest {
 
     @Test
     public void testFileExistAfterPut() throws InterruptedException {
+        //just for one method
+        URL singleUrl = URL.valueOf("redis://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=singleTest");
+        NewServiceStore singleServiceStore = new NewServiceStore(singleUrl);
+
         Assert.assertFalse(singleServiceStore.file.exists());
         URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
         singleServiceStore.put(url);
diff --git a/dubbo-servicedata/dubbo-servicedata-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.store.ServiceStoreFactory b/dubbo-servicedata/dubbo-servicedata-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.store.ServiceStoreFactory
new file mode 100644
index 0000000..c5c7ddc
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-api/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.store.ServiceStoreFactory
@@ -0,0 +1 @@
+JTest=org.apache.dubbo.servicedata.store.test.JTestServiceStoreFactory4Test
diff --git a/dubbo-servicedata/dubbo-servicedata-redis/pom.xml b/dubbo-servicedata/dubbo-servicedata-redis/pom.xml
index 2896c33..9e82707 100644
--- a/dubbo-servicedata/dubbo-servicedata-redis/pom.xml
+++ b/dubbo-servicedata/dubbo-servicedata-redis/pom.xml
@@ -1,4 +1,19 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
 <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
@@ -30,5 +45,10 @@
             <artifactId>curator-test</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.github.kstyrc</groupId>
+            <artifactId>embedded-redis</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStore.java b/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/store/redis/RedisServiceStore.java
similarity index 80%
rename from dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStore.java
rename to dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/store/redis/RedisServiceStore.java
index 52a2861..7b38e24 100644
--- a/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStore.java
+++ b/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/store/redis/RedisServiceStore.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.servicedata.redis;
+package org.apache.dubbo.servicedata.store.redis;
 
 import org.apache.dubbo.common.Constants;
 import org.apache.dubbo.common.URL;
@@ -35,7 +35,7 @@ public class RedisServiceStore extends AbstractServiceStore {
 
     private final static String TAG = "sd.";
 
-    private final JedisPool pool;
+    final JedisPool pool;
 
     public RedisServiceStore(URL url) {
         super(url);
@@ -45,7 +45,7 @@ public class RedisServiceStore extends AbstractServiceStore {
     @Override
     protected void doPutService(URL url) {
         try (Jedis jedis = pool.getResource()) {
-            jedis.set(TAG + getProtocol(url) + "." + url.getServiceKey(), url.toParameterString());
+            jedis.set(getKey(url), url.toParameterString());
         } catch (Throwable e) {
             logger.error("Failed to put " + url + " to redis " + url + ", cause: " + e.getMessage(), e);
             throw new RpcException("Failed to put " + url + " to redis " + getUrl() + ", cause: " + e.getMessage(), e);
@@ -55,7 +55,10 @@ public class RedisServiceStore extends AbstractServiceStore {
     @Override
     protected URL doPeekService(URL url) {
         try (Jedis jedis = pool.getResource()) {
-            String value = jedis.get(TAG + getProtocol(url) + "." + url.getServiceKey());
+            String value = jedis.get(getKey(url));
+            if (value == null) {
+                return null;
+            }
             return url.addParameterString(value);
         } catch (Throwable e) {
             logger.error("Failed to peek " + url + " to redis " + url + ", cause: " + e.getMessage(), e);
@@ -63,7 +66,14 @@ public class RedisServiceStore extends AbstractServiceStore {
         }
     }
 
-    private String getProtocol(URL url) {
+    String getKey(URL url) {
+        String protocol = getProtocol(url);
+        String app = url.getParameter(Constants.APPLICATION_KEY);
+        String appStr = Constants.PROVIDER_PROTOCOL.equals(protocol) ? "" : (app == null ? "" : (app + "."));
+        return TAG + protocol + "." + appStr + url.getServiceKey();
+    }
+
+    String getProtocol(URL url) {
         String protocol = url.getParameter(Constants.SIDE_KEY);
         protocol = protocol == null ? url.getProtocol() : protocol;
         return protocol;
diff --git a/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStoreFactory.java b/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/store/redis/RedisServiceStoreFactory.java
similarity index 87%
rename from dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStoreFactory.java
rename to dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/store/redis/RedisServiceStoreFactory.java
index eccf433..e308190 100644
--- a/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/redis/RedisServiceStoreFactory.java
+++ b/dubbo-servicedata/dubbo-servicedata-redis/src/main/java/org/apache/dubbo/servicedata/store/redis/RedisServiceStoreFactory.java
@@ -14,11 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.servicedata.redis;
+package org.apache.dubbo.servicedata.store.redis;
 
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
-import org.apache.dubbo.servicedata.ServiceStore;
+import org.apache.dubbo.servicedata.store.ServiceStore;
 import org.apache.dubbo.servicedata.support.AbstractServiceStoreFactory;
 
 /**
diff --git a/dubbo-servicedata/dubbo-servicedata-redis/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory b/dubbo-servicedata/dubbo-servicedata-redis/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory
deleted file mode 100644
index b5caef2..0000000
--- a/dubbo-servicedata/dubbo-servicedata-redis/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory
+++ /dev/null
@@ -1 +0,0 @@
-redis=org.apache.dubbo.servicedata.redis.RedisServiceStoreFactory
diff --git a/dubbo-servicedata/dubbo-servicedata-redis/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.store.ServiceStoreFactory b/dubbo-servicedata/dubbo-servicedata-redis/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.store.ServiceStoreFactory
new file mode 100644
index 0000000..3b96794
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-redis/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.store.ServiceStoreFactory
@@ -0,0 +1 @@
+redis=org.apache.dubbo.servicedata.store.redis.RedisServiceStoreFactory
diff --git a/dubbo-servicedata/dubbo-servicedata-redis/src/test/java/org/apache/dubbo/servicedata/store/redis/RedisServiceStoreTest.java b/dubbo-servicedata/dubbo-servicedata-redis/src/test/java/org/apache/dubbo/servicedata/store/redis/RedisServiceStoreTest.java
new file mode 100644
index 0000000..f0cb2cb
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-redis/src/test/java/org/apache/dubbo/servicedata/store/redis/RedisServiceStoreTest.java
@@ -0,0 +1,101 @@
+package org.apache.dubbo.servicedata.store.redis;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.rpc.RpcException;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import redis.clients.jedis.Jedis;
+import redis.embedded.RedisServer;
+
+import java.io.IOException;
+
+/**
+ *  2018/10/9
+ */
+public class RedisServiceStoreTest {
+    RedisServiceStore redisServiceStore;
+    RedisServer redisServer;
+
+    @Before
+    public void constructor() throws IOException {
+        int redisPort = NetUtils.getAvailablePort();
+        this.redisServer = new RedisServer(redisPort);
+        this.redisServer.start();
+        URL registryUrl = URL.valueOf("redis://localhost:" + redisPort);
+        redisServiceStore = (RedisServiceStore) new RedisServiceStoreFactory().createServiceStore(registryUrl);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        this.redisServer.stop();
+    }
+
+    @Test
+    public void testGetProtocol(){
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic&side=provider");
+        String protocol = redisServiceStore.getProtocol(url);
+        Assert.assertEquals(protocol, "provider");
+
+        URL url2 = URL.valueOf("consumer://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.0&application=vic");
+        String protocol2 = redisServiceStore.getProtocol(url2);
+        Assert.assertEquals(protocol2, "consumer");
+    }
+
+    @Test
+    public void testDoPut(){
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.9&application=vicss&side=provider");
+        redisServiceStore.doPutService(url);
+
+        try {
+            Jedis jedis = redisServiceStore.pool.getResource();
+            String value = jedis.get(redisServiceStore.getKey(url));
+            URL result = new URL("dubbo","127.0.0.1", 8090);
+            Assert.assertTrue(result.getParameters().isEmpty());
+            result = result.addParameterString(value);
+            Assert.assertFalse(result.getParameters().isEmpty());
+            Assert.assertEquals(result.getParameter("version"),"1.0.9");
+            Assert.assertEquals(result.getParameter("application"),"vicss");
+            Assert.assertEquals(result.getParameter("side"),"provider");
+        } catch (Throwable e) {
+            throw new RpcException("Failed to put " + url + " to redis . cause: " + e.getMessage(), e);
+        } finally {
+            redisServiceStore.pool.close();
+        }
+    }
+
+    @Test
+    public void testDoPeek(){
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.TestService?version=1.0.9&application=vicss&side=provider");
+        redisServiceStore.doPutService(url);
+
+        try {
+            URL result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.TestService?version=1.0.9&application=vicww&side=provider");
+            result = redisServiceStore.doPeekService(result);
+            Assert.assertFalse(result.getParameters().isEmpty());
+            Assert.assertEquals(result.getParameter("version"),"1.0.9");
+            Assert.assertEquals(result.getParameter("application"),"vicss");
+            Assert.assertEquals(result.getParameter("side"),"provider");
+
+
+            result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.TestDD?version=1.0.9&application=vicss&side=provider");
+            result = redisServiceStore.doPeekService(result);
+            Assert.assertNull(result);
+
+            result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.TestService?version=1.0.999&application=vicss&side=provider");
+            result = redisServiceStore.doPeekService(result);
+            Assert.assertNull(result);
+
+            result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.TestService?version=1.0.9&application=vicss&side=consumer");
+            result = redisServiceStore.doPeekService(result);
+            Assert.assertNull(result);
+
+        } catch (Throwable e) {
+            throw new RpcException("Failed to put " + url + " to redis . cause: " + e.getMessage(), e);
+        } finally {
+            redisServiceStore.pool.close();
+        }
+    }
+}
diff --git a/dubbo-servicedata/dubbo-servicedata-zookeeper/pom.xml b/dubbo-servicedata/dubbo-servicedata-zookeeper/pom.xml
index a9f9805..359ae74 100644
--- a/dubbo-servicedata/dubbo-servicedata-zookeeper/pom.xml
+++ b/dubbo-servicedata/dubbo-servicedata-zookeeper/pom.xml
@@ -1,4 +1,19 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
 <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
diff --git a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStore.java b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/store/zookeeper/ZookeeperServiceStore.java
similarity index 87%
rename from dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStore.java
rename to dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/store/zookeeper/ZookeeperServiceStore.java
index 486c8c0..8199e9f 100644
--- a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStore.java
+++ b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/store/zookeeper/ZookeeperServiceStore.java
@@ -14,14 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.servicedata.zookeeper;
+package org.apache.dubbo.servicedata.store.zookeeper;
 
 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.common.utils.CollectionUtils;
-import org.apache.dubbo.common.utils.UrlUtils;
 import org.apache.dubbo.remoting.zookeeper.ZookeeperClient;
 import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
 import org.apache.dubbo.rpc.RpcException;
@@ -39,11 +38,11 @@ public class ZookeeperServiceStore extends AbstractServiceStore {
 
     private final static String DEFAULT_ROOT = "dubbo";
 
-    private final static String TAG = "servicestore";
+    final static String TAG = "servicestore";
 
     private final String root;
 
-    private final ZookeeperClient zkClient;
+    final ZookeeperClient zkClient;
 
     public ZookeeperServiceStore(URL url, ZookeeperTransporter zookeeperTransporter) {
         super(url);
@@ -89,9 +88,7 @@ public class ZookeeperServiceStore extends AbstractServiceStore {
             if (urlStrs != null && !urlStrs.isEmpty()) {
                 for (String urlStr : urlStrs) {
                     urlStr = URL.decode(urlStr);
-                    if (urlStr.contains("://")) {
-                        urls.add(URL.valueOf(urlStr));
-                    }
+                    return url.addParameterString(urlStr);
                 }
             }
             return urls.isEmpty() ? null : urls.get(0);
@@ -120,9 +117,15 @@ public class ZookeeperServiceStore extends AbstractServiceStore {
         return toRootDir() + URL.encode(name);
     }
 
-    private String toCategoryPath(URL url) {
+    String toCategoryPath(URL url) {
         String protocol = url.getParameter(Constants.SIDE_KEY);
-        return toServicePath(url) + Constants.PATH_SEPARATOR + TAG + Constants.PATH_SEPARATOR + (protocol != null ? protocol : url.getProtocol());
+        String version = url.getParameter(Constants.VERSION_KEY);
+
+        String app = url.getParameter(Constants.APPLICATION_KEY);
+        String appStr = Constants.PROVIDER_PROTOCOL.equals(protocol) ? "" : (app == null ? "" : (Constants.PATH_SEPARATOR + app));
+
+        return toServicePath(url) + Constants.PATH_SEPARATOR + TAG + Constants.PATH_SEPARATOR + (version == null ? "" : (version + Constants.PATH_SEPARATOR))
+                + (protocol != null ? protocol : url.getProtocol()) + appStr;
     }
 
     private String toUrlPathWithParameter(URL url) {
diff --git a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStoreFactory.java b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/store/zookeeper/ZookeeperServiceStoreFactory.java
similarity index 92%
rename from dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStoreFactory.java
rename to dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/store/zookeeper/ZookeeperServiceStoreFactory.java
index 4f0deb8..e9aee2c 100644
--- a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/zookeeper/ZookeeperServiceStoreFactory.java
+++ b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/java/org/apache/dubbo/servicedata/store/zookeeper/ZookeeperServiceStoreFactory.java
@@ -14,11 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.servicedata.zookeeper;
+package org.apache.dubbo.servicedata.store.zookeeper;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
-import org.apache.dubbo.servicedata.ServiceStore;
+import org.apache.dubbo.servicedata.store.ServiceStore;
 import org.apache.dubbo.servicedata.support.AbstractServiceStoreFactory;
 
 /**
diff --git a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory
deleted file mode 100644
index ed32c44..0000000
--- a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.ServiceStoreFactory
+++ /dev/null
@@ -1 +0,0 @@
-zookeeper=org.apache.dubbo.servicedata.zookeeper.ZookeeperServiceStoreFactory
diff --git a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.store.ServiceStoreFactory b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.store.ServiceStoreFactory
new file mode 100644
index 0000000..35ac42a
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.servicedata.store.ServiceStoreFactory
@@ -0,0 +1 @@
+zookeeper=org.apache.dubbo.servicedata.store.zookeeper.ZookeeperServiceStoreFactory
diff --git a/dubbo-servicedata/dubbo-servicedata-zookeeper/src/test/java/org/apache/dubbo/servicedata/store/zookeeper/ZookeeperServiceStoreTest.java b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/test/java/org/apache/dubbo/servicedata/store/zookeeper/ZookeeperServiceStoreTest.java
new file mode 100644
index 0000000..bc0f3f3
--- /dev/null
+++ b/dubbo-servicedata/dubbo-servicedata-zookeeper/src/test/java/org/apache/dubbo/servicedata/store/zookeeper/ZookeeperServiceStoreTest.java
@@ -0,0 +1,183 @@
+package org.apache.dubbo.servicedata.store.zookeeper;
+
+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.curator.CuratorZookeeperTransporter;
+import org.apache.dubbo.rpc.RpcException;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ *  2018/10/9
+ */
+public class ZookeeperServiceStoreTest {
+    private TestingServer zkServer;
+    private ZookeeperServiceStore zookeeperServiceStore;
+    private URL registryUrl;
+    private ZookeeperServiceStoreFactory zookeeperServiceStoreFactory;
+
+    @Before
+    public void setUp() throws Exception {
+        int zkServerPort = NetUtils.getAvailablePort();
+        this.zkServer = new TestingServer(zkServerPort, true);
+        this.registryUrl = URL.valueOf("zookeeper://localhost:" + zkServerPort);
+
+        zookeeperServiceStoreFactory = new ZookeeperServiceStoreFactory();
+        zookeeperServiceStoreFactory.setZookeeperTransporter(new CuratorZookeeperTransporter());
+        this.zookeeperServiceStore = (ZookeeperServiceStore) zookeeperServiceStoreFactory.createServiceStore(registryUrl);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        zkServer.stop();
+    }
+
+    @Test
+    public void testToCategoryPathWithNormal() {
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.ZkService?version=1.55.88&application=zktest&side=provider");
+        String categoryUrl = zookeeperServiceStore.toCategoryPath(url);
+        Assert.assertEquals(categoryUrl, "/dubbo/org.apache.dubbo.ZkService/" + zookeeperServiceStore.TAG + "/1.55.88/provider");
+    }
+
+    @Test
+    public void testToCategoryPathNoVersion() {
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.ZkService?application=zktestNoV&side=provider");
+        String categoryUrl = zookeeperServiceStore.toCategoryPath(url);
+        Assert.assertEquals(categoryUrl, "/dubbo/org.apache.dubbo.ZkService/" + zookeeperServiceStore.TAG + "/provider");
+    }
+
+    @Test
+    public void testToCategoryPathNoSide() {
+        URL url = URL.valueOf("consumer://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.ZkService?version=1.55.88&application=zktestNoSide");
+        String categoryUrl = zookeeperServiceStore.toCategoryPath(url);
+        Assert.assertEquals(categoryUrl, "/dubbo/org.apache.dubbo.ZkService/" + zookeeperServiceStore.TAG + "/1.55.88/consumer/zktestNoSide");
+    }
+
+    @Test
+    public void testToCategoryPathNoSideNoVersion() {
+        URL url = URL.valueOf("consumer://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.ZkService?application=zktestNoSideVersion");
+        String categoryUrl = zookeeperServiceStore.toCategoryPath(url);
+        Assert.assertEquals(categoryUrl, "/dubbo/org.apache.dubbo.ZkService/" + zookeeperServiceStore.TAG + "/consumer/zktestNoSideVersion");
+    }
+
+    @Test
+    public void testDoPut() {
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.ZkService?version=1.55.8899&application=zktestPut&side=provider");
+        zookeeperServiceStore.doPutService(url);
+
+        try {
+            String path = zookeeperServiceStore.toCategoryPath(url);
+            List<String> resultStr = zookeeperServiceStore.zkClient.getChildren(path);
+            Assert.assertTrue(resultStr.size() == 1);
+            URL result = new URL("dubbo","127.0.0.1", 8090);
+            Assert.assertTrue(result.getParameters().isEmpty());
+            result = result.addParameterString(URL.decode(resultStr.get(0)));
+            Assert.assertFalse(result.getParameters().isEmpty());
+            Assert.assertEquals(result.getParameter("version"),"1.55.8899");
+            Assert.assertEquals(result.getParameter("application"),"zktestPut");
+            Assert.assertEquals(result.getParameter("side"),"provider");
+        } catch (Throwable e) {
+            throw new RpcException("Failed to put " + url + " to redis . cause: " + e.getMessage(), e);
+        }
+    }
+
+    @Test
+    public void testDoPeekProvider() {
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.ZkService?version=1.55.8899&application=zktestPut&side=provider");
+        zookeeperServiceStore.doPutService(url);
+
+        try {
+            URL result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.ZkService?version=1.55.8899&application=zkDoPeek&side=provider");
+            result = zookeeperServiceStore.doPeekService(result);
+            Assert.assertFalse(result.getParameters().isEmpty());
+            Assert.assertEquals(result.getParameter("version"),"1.55.8899");
+            Assert.assertEquals(result.getParameter("application"),"zktestPut");
+            Assert.assertEquals(result.getParameter("side"),"provider");
+
+
+            result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.TestDD?version=1.55.8899&application=zkDoPeek&side=provider");
+            result = zookeeperServiceStore.doPeekService(result);
+            Assert.assertNull(result);
+
+            result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.ZkService?version=1.55.8000&application=zkDoPeek&side=provider");
+            result = zookeeperServiceStore.doPeekService(result);
+            Assert.assertNull(result);
+
+            result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.ZkService?version=1.55.8899&application=zkDoPeek&side=consumer");
+            result = zookeeperServiceStore.doPeekService(result);
+            Assert.assertNull(result);
+
+        } catch (Throwable e) {
+            throw new RpcException("Failed to put " + url + " to redis . cause: " + e.getMessage(), e);
+        }
+    }
+
+    @Test
+    public void testDoPeekConsumer() {
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.ZkServicePeek2?version=1.55.8899&application=zkDoPeek2&side=consumer");
+        zookeeperServiceStore.doPutService(url);
+
+        try {
+            URL result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.ZkServicePeek2?version=1.55.8899&application=zkDoPeek2&side=consumer");
+            result = zookeeperServiceStore.doPeekService(result);
+            Assert.assertFalse(result.getParameters().isEmpty());
+            Assert.assertEquals(result.getParameter("version"),"1.55.8899");
+            Assert.assertEquals(result.getParameter("application"),"zkDoPeek2");
+            Assert.assertEquals(result.getParameter("side"),"consumer");
+
+
+            result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.ZkServicePeek2?version=1.55.8899&application=zkDoPeek&side=consumer");
+            result = zookeeperServiceStore.doPeekService(result);
+            Assert.assertNull(result);
+
+            result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.TestDDw?version=1.55.8899&application=zkDoPeek&side=consumer");
+            result = zookeeperServiceStore.doPeekService(result);
+            Assert.assertNull(result);
+
+            result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.ZkServicePeek2?version=1.55.8000&application=zkDoPeek&side=consumer");
+            result = zookeeperServiceStore.doPeekService(result);
+            Assert.assertNull(result);
+
+            result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.ZkServicePeek2?version=1.55.8899&application=zkDoPeek&side=provider");
+            result = zookeeperServiceStore.doPeekService(result);
+            Assert.assertNull(result);
+
+        } catch (Throwable e) {
+            throw new RpcException("Failed to put " + url + " to redis . cause: " + e.getMessage(), e);
+        }
+    }
+
+    @Test
+    public void testDoPeekConsumerPutTwice() {
+        URL url = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.ZkServicePeek2?version=1.55.8899&application=zkDoPeekT1&side=consumer");
+        zookeeperServiceStore.doPutService(url);
+        URL url2 = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4444/org.apache.dubbo.ZkServicePeek2?version=1.55.8899&application=zkDoPeekT2&side=consumer");
+        zookeeperServiceStore.doPutService(url2);
+
+        try {
+            URL result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.ZkServicePeek2?version=1.55.8899&application=zkDoPeekT1&side=consumer");
+            result = zookeeperServiceStore.doPeekService(result);
+            Assert.assertFalse(result.getParameters().isEmpty());
+            Assert.assertEquals(result.getParameter("version"),"1.55.8899");
+            Assert.assertEquals(result.getParameter("application"),"zkDoPeekT1");
+            Assert.assertEquals(result.getParameter("side"),"consumer");
+
+
+            result = URL.valueOf("dubbo://" + NetUtils.getLocalAddress().getHostName() + ":4667/org.apache.dubbo.ZkServicePeek2?version=1.55.8899&application=zkDoPeekT2&side=consumer");
+            result = zookeeperServiceStore.doPeekService(result);
+            Assert.assertFalse(result.getParameters().isEmpty());
+            Assert.assertEquals(result.getParameter("version"),"1.55.8899");
+            Assert.assertEquals(result.getParameter("application"),"zkDoPeekT2");
+            Assert.assertEquals(result.getParameter("side"),"consumer");
+
+        } catch (Throwable e) {
+            throw new RpcException("Failed to put " + url + " to redis . cause: " + e.getMessage(), e);
+        }
+    }
+}
diff --git a/dubbo-servicedata/pom.xml b/dubbo-servicedata/pom.xml
index 25964ff..55b4c5f 100644
--- a/dubbo-servicedata/pom.xml
+++ b/dubbo-servicedata/pom.xml
@@ -1,4 +1,19 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
 <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">