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

[dubbo-admin] branch develop-for-dubbo-3.x updated: [ISSUE #760]Application discover support (#807)

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

ranke pushed a commit to branch develop-for-dubbo-3.x
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git


The following commit(s) were added to refs/heads/develop-for-dubbo-3.x by this push:
     new 8f37d30  [ISSUE #760]Application discover support (#807)
8f37d30 is described below

commit 8f37d307258d15273fcbd5e885beb4f3d71b78e9
Author: haoyann <10...@qq.com>
AuthorDate: Wed Sep 1 10:00:39 2021 +0800

    [ISSUE #760]Application discover support (#807)
    
    * application discover support
    
    * fix checkstyle
    
    * fix ci
    
    * remove useless pom import,modify Chinese comment
---
 dubbo-admin-server/pom.xml                         |  10 +-
 .../apache/dubbo/admin/common/util/Constants.java  |   1 +
 .../dubbo/admin/common/util/ServiceTestUtil.java   |  13 +-
 ...ServiceTestUtil.java => ServiceTestV3Util.java} |  51 +++--
 .../apache/dubbo/admin/common/util/SyncUtils.java  |  13 +-
 .../apache/dubbo/admin/config/ConfigCenter.java    |  38 +++-
 .../admin/controller/MeshRouteController.java      |  13 +-
 .../dubbo/admin/controller/ServiceController.java  |  18 +-
 .../admin/controller/ServiceTestController.java    |  31 ++-
 .../admin/model/domain/FullServiceDefinition.java  |  41 ++++
 .../dubbo/admin/model/domain/MethodDefinition.java | 108 +++++++++
 .../apache/dubbo/admin/model/domain/Provider.java  |  10 +
 .../dubbo/admin/model/domain/RegistrySource.java   |  26 +++
 .../admin/model/domain/ServiceDefinition.java      | 133 +++++++++++
 .../dubbo/admin/model/domain/TypeDefinition.java   | 161 +++++++++++++
 .../apache/dubbo/admin/model/dto/ServiceDTO.java   |  19 +-
 .../dubbo/admin/model/dto/ServiceDetailDTO.java    |   7 +-
 .../registry/mapping/AddressChangeListener.java    |  32 +++
 .../registry/mapping/AdminMappingListener.java     | 131 +++++++++++
 .../AdminServiceInstancesChangedListener.java      |  50 ++++
 .../admin/registry/mapping/ServiceMapping.java     |  36 +++
 .../registry/mapping/impl/NoOpServiceMapping.java  |  40 ++++
 .../mapping/impl/ZookeeperServiceMapping.java      |  93 ++++++++
 .../dubbo/admin/service/ProviderService.java       |  39 +---
 .../apache/dubbo/admin/service/RegistryCache.java  |  48 ++++
 .../dubbo/admin/service/RegistryServerSync.java    |  29 ++-
 .../dubbo/admin/service/impl/AbstractService.java  |   7 +-
 .../admin/service/impl/ConsumerServiceImpl.java    |   8 +-
 .../admin/service/impl/InstanceRegistryCache.java  |  55 +++++
 .../service/impl/InstanceRegistryQueryHelper.java  | 155 +++++++++++++
 ...actService.java => InterfaceRegistryCache.java} |  42 ++--
 .../admin/service/impl/ProviderServiceImpl.java    | 252 ++++-----------------
 ...che.dubbo.admin.registry.mapping.ServiceMapping |   1 +
 .../dubbo/admin/AbstractSpringIntegrationTest.java |   2 +-
 .../admin/controller/MeshRouteControllerTest.java  |   7 +
 .../admin/service/RegistryServerSyncTest.java      |  35 ++-
 dubbo-admin-ui/src/components/ServiceDetail.vue    |  14 ++
 dubbo-admin-ui/src/components/ServiceSearch.vue    |  22 +-
 .../src/components/governance/MeshRule.vue         |   2 +-
 dubbo-admin-ui/src/lang/en.js                      |   3 +
 dubbo-admin-ui/src/lang/zh.js                      |   3 +
 dubbo-admin-ui/src/store/index.js                  |  12 +
 pom.xml                                            |  23 +-
 43 files changed, 1471 insertions(+), 363 deletions(-)

diff --git a/dubbo-admin-server/pom.xml b/dubbo-admin-server/pom.xml
index e13d213..9a5df72 100644
--- a/dubbo-admin-server/pom.xml
+++ b/dubbo-admin-server/pom.xml
@@ -124,6 +124,11 @@
             <artifactId>curator-recipes</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-x-discovery</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>
         </dependency>
@@ -168,11 +173,6 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.dubbo</groupId>
-            <artifactId>dubbo-serialization-kryo</artifactId>
-        </dependency>
-
-        <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
             <version>${mockito-version}</version>
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/Constants.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/Constants.java
index 96e3f24..aa694b7 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/Constants.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/Constants.java
@@ -80,6 +80,7 @@ public class Constants {
     public static final Set<String> CONFIGS = new HashSet<>();
     public static final String COLON = ":";
     public static final String MESH_RULE_SUFFIX = ".MESHAPPRULE";
+    public static final String DEFAULT_MAPPING_GROUP = "mapping";
     static {
         CONFIGS.add(WEIGHT);
         CONFIGS.add(BALANCING);
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java
index fa568ff..b9b6bde 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java
@@ -19,10 +19,10 @@ package org.apache.dubbo.admin.common.util;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.dubbo.admin.model.domain.MethodMetadata;
-import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
-import org.apache.dubbo.metadata.definition.model.MethodDefinition;
-import org.apache.dubbo.metadata.definition.model.ServiceDefinition;
-import org.apache.dubbo.metadata.definition.model.TypeDefinition;
+import org.apache.dubbo.admin.model.domain.FullServiceDefinition;
+import org.apache.dubbo.admin.model.domain.MethodDefinition;
+import org.apache.dubbo.admin.model.domain.ServiceDefinition;
+import org.apache.dubbo.admin.model.domain.TypeDefinition;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -180,10 +180,7 @@ public class ServiceTestUtil {
         keyType = StringUtils.strip(keyType);
 
         Map<Object, Object> map = new HashMap<>();
-        // 生成 key 默认值
         Object key = generateType(sd, keyType);
-
-        // 生成 value 默认值
         String valueType = StringUtils.substringAfter(td.getType(), ",");
         valueType = StringUtils.substringBefore(valueType, ">");
         valueType = StringUtils.strip(valueType);
@@ -197,7 +194,7 @@ public class ServiceTestUtil {
         String type = StringUtils.substringAfter(td.getType(), "<");
         type = StringUtils.substringBefore(type, ">");
         if (StringUtils.isEmpty(type)) {
-            // 如果 collection 类型未声明,则生成空 collection
+            // if type is null return empty collection
             return new Object[] {};
         }
         return new Object[]{generateType(sd, type)};
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestV3Util.java
similarity index 88%
copy from dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java
copy to dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestV3Util.java
index fa568ff..63e294f 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestV3Util.java
@@ -17,13 +17,14 @@
 
 package org.apache.dubbo.admin.common.util;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.dubbo.admin.model.domain.MethodMetadata;
 import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
 import org.apache.dubbo.metadata.definition.model.MethodDefinition;
 import org.apache.dubbo.metadata.definition.model.ServiceDefinition;
 import org.apache.dubbo.metadata.definition.model.TypeDefinition;
 
+import org.apache.commons.lang3.StringUtils;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -32,7 +33,7 @@ import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class ServiceTestUtil {
+public class ServiceTestV3Util {
     private static Pattern COLLECTION_PATTERN = Pattern.compile("^java\\.util\\..*(Set|List|Queue|Collection|Deque)(<.*>)*$");
     private static Pattern MAP_PATTERN = Pattern.compile("^java\\.util\\..*Map.*(<.*>)*$");
 
@@ -62,6 +63,10 @@ public class ServiceTestUtil {
 
     private static boolean isPrimitiveType(TypeDefinition td) {
         String type = td.getType();
+        return isPrimitiveType(type);
+    }
+
+    private static boolean isPrimitiveType(String type) {
         return type.equals("byte") || type.equals("java.lang.Byte") ||
                 type.equals("short") || type.equals("java.lang.Short") ||
                 type.equals("int") || type.equals("java.lang.Integer") ||
@@ -91,14 +96,15 @@ public class ServiceTestUtil {
     }
 
     private static void generateComplexType(ServiceDefinition sd, TypeDefinition td, Map<String, Object> holder) {
-        for (Map.Entry<String, TypeDefinition> entry : td.getProperties().entrySet()) {
-            if (isPrimitiveType(td)) {
-                holder.put(entry.getKey(), generatePrimitiveType(td));
+        td.getProperties().forEach((name, type) -> {
+            if (isPrimitiveType(type)) {
+                holder.put(name, generatePrimitiveType(type));
             } else {
-                generateEnclosedType(holder, entry.getKey(), sd, entry.getValue());
+                generateEnclosedType(holder, name, sd, type);
             }
-        }
+        });
     }
+
     private static Object generateComplexType(ServiceDefinition sd, TypeDefinition td) {
         Map<String, Object> holder = new HashMap<>();
         generateComplexType(sd, td, holder);
@@ -122,7 +128,10 @@ public class ServiceTestUtil {
     }
 
     private static Object generatePrimitiveType(TypeDefinition td) {
-        String type = td.getType();
+        return generatePrimitiveType(td.getType());
+    }
+
+    private static Object generatePrimitiveType(String type) {
         switch (type) {
             case "byte":
             case "java.lang.Byte":
@@ -180,10 +189,7 @@ public class ServiceTestUtil {
         keyType = StringUtils.strip(keyType);
 
         Map<Object, Object> map = new HashMap<>();
-        // 生成 key 默认值
         Object key = generateType(sd, keyType);
-
-        // 生成 value 默认值
         String valueType = StringUtils.substringAfter(td.getType(), ",");
         valueType = StringUtils.substringBefore(valueType, ">");
         valueType = StringUtils.strip(valueType);
@@ -197,24 +203,31 @@ public class ServiceTestUtil {
         String type = StringUtils.substringAfter(td.getType(), "<");
         type = StringUtils.substringBefore(type, ">");
         if (StringUtils.isEmpty(type)) {
-            // 如果 collection 类型未声明,则生成空 collection
-            return new Object[] {};
+            // if type is null return empty collection
+            return new Object[]{};
         }
         return new Object[]{generateType(sd, type)};
 
     }
+
     private static Object generateArrayType(ServiceDefinition sd, TypeDefinition td) {
         String type = StringUtils.substringBeforeLast(td.getType(), "[]");
         return new Object[]{generateType(sd, type)};
     }
 
-    private static void generateEnclosedType(Map<String, Object> holder, String key, ServiceDefinition sd, TypeDefinition td) {
-        if (td.getProperties() == null || td.getProperties().size() == 0 || isPrimitiveType(td)) {
-            holder.put(key, generateType(sd, td));
+    private static void generateEnclosedType(Map<String, Object> holder, String key, ServiceDefinition sd, String type) {
+        if (isPrimitiveType(type)) {
+            holder.put(key, generateType(sd, type));
         } else {
-            Map<String, Object> enclosedMap = new HashMap<>();
-            holder.put(key, enclosedMap);
-            generateComplexType(sd, td, enclosedMap);
+            TypeDefinition td = findTypeDefinition(sd, type);
+            if (td.getProperties() == null || td.getProperties().size() == 0) {
+                holder.put(key, generateType(sd, td));
+            } else {
+                Map<String, Object> enclosedMap = new HashMap<>();
+                holder.put(key, enclosedMap);
+                generateComplexType(sd, td, enclosedMap);
+            }
+
         }
     }
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java
index b548d91..88e9e73 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java
@@ -18,6 +18,8 @@ package org.apache.dubbo.admin.common.util;
 
 import org.apache.dubbo.admin.model.domain.Consumer;
 import org.apache.dubbo.admin.model.domain.Provider;
+import org.apache.dubbo.admin.model.domain.RegistrySource;
+import org.apache.dubbo.common.BaseServiceMetadata;
 import org.apache.dubbo.common.URL;
 
 import java.util.ArrayList;
@@ -48,7 +50,10 @@ public class SyncUtils {
 
         Provider p = new Provider();
         p.setHash(id);
-        p.setService(url.getServiceKey());
+        String group = url.getUrlParam().getParameter(Constants.GROUP_KEY);
+        String version = url.getUrlParam().getParameter(Constants.VERSION_KEY);
+        String service = BaseServiceMetadata.buildServiceKey(url.getServiceInterface(), group, version);
+        p.setService(service);
         p.setAddress(url.getAddress());
         p.setApplication(url.getParameter(Constants.APPLICATION_KEY));
         p.setUrl(url.toIdentityString());
@@ -58,6 +63,7 @@ public class SyncUtils {
         p.setEnabled(url.getParameter(Constants.ENABLED_KEY, true));
         p.setWeight(url.getParameter(Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT));
         p.setUsername(url.getParameter("owner"));
+        p.setRegistrySource(RegistrySource.INTERFACE);
 
         return p;
     }
@@ -83,7 +89,10 @@ public class SyncUtils {
 
         Consumer c = new Consumer();
         c.setHash(id);
-        c.setService(url.getServiceKey());
+        String group = url.getUrlParam().getParameter(Constants.GROUP_KEY);
+        String version = url.getUrlParam().getParameter(Constants.VERSION_KEY);
+        String service = BaseServiceMetadata.buildServiceKey(url.getServiceInterface(), group, version);
+        c.setService(service);
         c.setAddress(url.getHost());
         c.setApplication(url.getParameter(Constants.APPLICATION_KEY));
         c.setParameters(url.toParameterString());
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
index bedd84d..7e35761 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
@@ -21,14 +21,21 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.dubbo.admin.common.exception.ConfigurationException;
 import org.apache.dubbo.admin.common.util.Constants;
 import org.apache.dubbo.admin.registry.config.GovernanceConfiguration;
+import org.apache.dubbo.admin.registry.mapping.ServiceMapping;
+import org.apache.dubbo.admin.registry.mapping.impl.NoOpServiceMapping;
 import org.apache.dubbo.admin.registry.metadata.MetaDataCollector;
 import org.apache.dubbo.admin.registry.metadata.impl.NoOpMetadataCollector;
 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.metadata.MappingListener;
 import org.apache.dubbo.registry.Registry;
 import org.apache.dubbo.registry.RegistryFactory;
+import org.apache.dubbo.registry.RegistryService;
+import org.apache.dubbo.registry.client.ServiceDiscovery;
+import org.apache.dubbo.registry.client.ServiceDiscoveryFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -37,6 +44,7 @@ import org.springframework.context.annotation.DependsOn;
 import java.util.Arrays;
 
 import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
+import static org.apache.dubbo.registry.client.ServiceDiscoveryFactory.getExtension;
 
 @Configuration
 public class ConfigCenter {
@@ -85,7 +93,8 @@ public class ConfigCenter {
     private URL registryUrl;
     private URL metadataUrl;
 
-
+    @Autowired
+    private MappingListener mappingListener;
 
     /*
      * generate dynamic configuration client
@@ -130,7 +139,7 @@ public class ConfigCenter {
     /*
      * generate registry client
      */
-    @Bean
+    @Bean("dubboRegistry")
     @DependsOn("governanceConfiguration")
     Registry getRegistry() {
         Registry registry = null;
@@ -148,7 +157,7 @@ public class ConfigCenter {
     /*
      * generate metadata client
      */
-    @Bean
+    @Bean("metaDataCollector")
     @DependsOn("governanceConfiguration")
     MetaDataCollector getMetadataCollector() {
         MetaDataCollector metaDataCollector = new NoOpMetadataCollector();
@@ -168,6 +177,29 @@ public class ConfigCenter {
         return metaDataCollector;
     }
 
+    @Bean(destroyMethod = "destroy")
+    @DependsOn("dubboRegistry")
+    ServiceDiscovery getServiceDiscoveryRegistry() throws Exception {
+        URL registryURL = registryUrl.setPath(RegistryService.class.getName());
+        ServiceDiscoveryFactory factory = getExtension(registryURL);
+        ServiceDiscovery serviceDiscovery = factory.getServiceDiscovery(registryURL);
+        serviceDiscovery.initialize(registryURL);
+        return serviceDiscovery;
+    }
+
+    @Bean
+    @DependsOn("metaDataCollector")
+    ServiceMapping getServiceMapping() {
+        ServiceMapping serviceMapping = new NoOpServiceMapping();
+        if (metadataUrl == null) {
+            return serviceMapping;
+        }
+        serviceMapping = ExtensionLoader.getExtensionLoader(ServiceMapping.class).getExtension(metadataUrl.getProtocol());
+        serviceMapping.addMappingListener(mappingListener);
+        serviceMapping.init(metadataUrl);
+        return serviceMapping;
+    }
+
     private URL formUrl(String config, String group, String nameSpace, String username, String password) {
         URL url = URL.valueOf(config);
         if (StringUtils.isEmpty(url.getParameter(Constants.GROUP_KEY)) && StringUtils.isNotEmpty(group)) {
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MeshRouteController.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MeshRouteController.java
index 537ca0c..9f3136c 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MeshRouteController.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MeshRouteController.java
@@ -20,12 +20,13 @@ package org.apache.dubbo.admin.controller;
 import org.apache.dubbo.admin.annotation.Authority;
 import org.apache.dubbo.admin.common.exception.ParamValidationException;
 import org.apache.dubbo.admin.common.exception.ResourceNotFoundException;
+import org.apache.dubbo.admin.common.exception.VersionValidationException;
 import org.apache.dubbo.admin.common.util.Constants;
 import org.apache.dubbo.admin.model.dto.MeshRouteDTO;
 import org.apache.dubbo.admin.service.MeshRouteService;
+import org.apache.dubbo.admin.service.ProviderService;
 
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -45,9 +46,11 @@ public class MeshRouteController {
 
     private final MeshRouteService meshRouteService;
 
-    @Autowired
-    public MeshRouteController(MeshRouteService meshRouteService) {
+    private final ProviderService providerService;
+
+    public MeshRouteController(MeshRouteService meshRouteService, ProviderService providerService) {
         this.meshRouteService = meshRouteService;
+        this.providerService = providerService;
     }
 
     @RequestMapping(method = RequestMethod.POST)
@@ -57,7 +60,9 @@ public class MeshRouteController {
         if (StringUtils.isEmpty(app)) {
             throw new ParamValidationException("app is Empty!");
         }
-        // todo check appName
+        if (providerService.findVersionInApplication(app).startsWith("2")) {
+            throw new VersionValidationException("dubbo 2.x does not support mesh route");
+        }
 
         return meshRouteService.createMeshRule(meshRoute);
     }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
index 4a9df1a..bfd801a 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
@@ -103,9 +103,16 @@ public class ServiceController {
         if (metadata != null) {
             try {
                 // for dubbo version under 2.7, this metadata will represent as IP address, like 10.0.0.1.
-                // So the json conversion will fail. 
-                FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class);
-                serviceDetailDTO.setMetadata(serviceDefinition);
+                // So the json conversion will fail.
+                String release = providerService.findVersionInApplication(application);
+                // serialization compatible 2.x version
+                if (release.startsWith("2")) {
+                    org.apache.dubbo.admin.model.domain.FullServiceDefinition serviceDefinition = gson.fromJson(metadata, org.apache.dubbo.admin.model.domain.FullServiceDefinition.class);
+                    serviceDetailDTO.setMetadata(serviceDefinition);
+                } else {
+                    FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class);
+                    serviceDetailDTO.setMetadata(serviceDefinition);
+                }
             } catch (JsonParseException e) {
                 throw new VersionValidationException("dubbo 2.6 does not support metadata");
             }
@@ -122,6 +129,11 @@ public class ServiceController {
         return new HashSet<>(providerService.findServices());
     }
 
+    @RequestMapping(value = "/applications/instance", method = RequestMethod.GET)
+    public Set<String> allInstanceServices(@PathVariable String env) {
+        return new HashSet<>(providerService.findInstanceApplications());
+    }
+
     @RequestMapping(value = "/applications", method = RequestMethod.GET)
     public Set<String> allApplications(@PathVariable String env) {
         return providerService.findApplications();
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java
index cea1708..ca3ad49 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java
@@ -23,6 +23,7 @@ import org.apache.dubbo.admin.common.util.Constants;
 import org.apache.dubbo.admin.annotation.Authority;
 import org.apache.dubbo.admin.common.util.ConvertUtil;
 import org.apache.dubbo.admin.common.util.ServiceTestUtil;
+import org.apache.dubbo.admin.common.util.ServiceTestV3Util;
 import org.apache.dubbo.admin.model.domain.MethodMetadata;
 import org.apache.dubbo.admin.model.dto.ServiceTestDTO;
 import org.apache.dubbo.admin.service.ProviderService;
@@ -71,13 +72,29 @@ public class ServiceTestController {
         MethodMetadata methodMetadata = null;
         if (metadata != null) {
             Gson gson = new Gson();
-            FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class);
-            List<MethodDefinition> methods = serviceDefinition.getMethods();
-            if (methods != null) {
-                for (MethodDefinition m : methods) {
-                    if (ServiceTestUtil.sameMethod(m, method)) {
-                        methodMetadata = ServiceTestUtil.generateMethodMeta(serviceDefinition, m);
-                        break;
+            String release = providerService.findVersionInApplication(application);
+            if (release.startsWith("2.")) {
+                org.apache.dubbo.admin.model.domain.FullServiceDefinition serviceDefinition = gson.fromJson(metadata,
+                        org.apache.dubbo.admin.model.domain.FullServiceDefinition.class);
+                List<org.apache.dubbo.admin.model.domain.MethodDefinition> methods = serviceDefinition.getMethods();
+                if (methods != null) {
+                    for (org.apache.dubbo.admin.model.domain.MethodDefinition m : methods) {
+                        if (ServiceTestUtil.sameMethod(m, method)) {
+                            methodMetadata = ServiceTestUtil.generateMethodMeta(serviceDefinition, m);
+                            break;
+                        }
+                    }
+                }
+            } else {
+                FullServiceDefinition serviceDefinition = gson.fromJson(metadata,
+                        FullServiceDefinition.class);
+                List<MethodDefinition> methods = serviceDefinition.getMethods();
+                if (methods != null) {
+                    for (MethodDefinition m : methods) {
+                        if (ServiceTestV3Util.sameMethod(m, method)) {
+                            methodMetadata = ServiceTestV3Util.generateMethodMeta(serviceDefinition, m);
+                            break;
+                        }
                     }
                 }
             }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/FullServiceDefinition.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/FullServiceDefinition.java
new file mode 100644
index 0000000..54dc59b
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/FullServiceDefinition.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.model.domain;
+
+import java.util.Map;
+
+/**
+ * copy from {@link org.apache.dubbo.metadata.definition.model.FullServiceDefinition} compatible 2.x version
+ */
+public class FullServiceDefinition extends ServiceDefinition {
+    private Map<String, String> parameters;
+
+    public Map<String, String> getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(Map<String, String> parameters) {
+        this.parameters = parameters;
+    }
+
+    public String toString() {
+        return "FullServiceDefinition{" +
+                "parameters=" + parameters +
+                "} " + super.toString();
+    }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/MethodDefinition.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/MethodDefinition.java
new file mode 100644
index 0000000..1c0b8fe
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/MethodDefinition.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.model.domain;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * copy from {@link org.apache.dubbo.metadata.definition.model.MethodDefinition} compatible 2.x version
+ */
+public class MethodDefinition {
+
+    private String name;
+    private String[] parameterTypes;
+    private String returnType;
+    private List<TypeDefinition> parameters;
+    private List<String> annotations;
+
+    public MethodDefinition() {
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public List<TypeDefinition> getParameters() {
+        if (this.parameters == null) {
+            this.parameters = new ArrayList();
+        }
+
+        return this.parameters;
+    }
+
+    public String[] getParameterTypes() {
+        return this.parameterTypes;
+    }
+
+    public String getReturnType() {
+        return this.returnType;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setParameters(List<TypeDefinition> parameters) {
+        this.parameters = parameters;
+    }
+
+    public void setParameterTypes(String[] parameterTypes) {
+        this.parameterTypes = TypeDefinition.formatTypes(parameterTypes);
+    }
+
+    public void setReturnType(String returnType) {
+        this.returnType = TypeDefinition.formatType(returnType);
+    }
+
+    public List<String> getAnnotations() {
+        if (this.annotations == null) {
+            this.annotations = Collections.emptyList();
+        }
+
+        return this.annotations;
+    }
+
+    public void setAnnotations(List<String> annotations) {
+        this.annotations = annotations;
+    }
+
+    public String toString() {
+        return "MethodDefinition [name=" + this.name + ", parameterTypes=" + Arrays.toString(this.parameterTypes) + ", returnType=" + this.returnType + "]";
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        } else if (!(o instanceof MethodDefinition)) {
+            return false;
+        } else {
+            MethodDefinition that = (MethodDefinition) o;
+            return Objects.equals(this.getName(), that.getName()) && Arrays.equals(this.getParameterTypes(), that.getParameterTypes()) && Objects.equals(this.getReturnType(), that.getReturnType()) && Objects.equals(this.getParameters(), that.getParameters());
+        }
+    }
+
+    public int hashCode() {
+        int result = Objects.hash(new Object[]{this.getName(), this.getReturnType(), this.getParameters()});
+        result = 31 * result + Arrays.hashCode(this.getParameterTypes());
+        return result;
+    }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java
index 363872b..2de0ad0 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java
@@ -60,6 +60,8 @@ public class Provider extends Entity {
 
     private List<Override> overrides;
 
+    private RegistrySource registrySource;
+
     public Provider() {
     }
 
@@ -181,6 +183,14 @@ public class Provider extends Entity {
         this.overrides = overrides;
     }
 
+    public RegistrySource getRegistrySource() {
+        return registrySource;
+    }
+
+    public void setRegistrySource(RegistrySource registrySource) {
+        this.registrySource = registrySource;
+    }
+
     public URL toUrl() {
         Map<String, String> serviceName2Map = ConvertUtil.serviceName2Map(getService());
         /*if(!serviceName2Map.containsKey(Constants.INTERFACE_KEY)) {
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/RegistrySource.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/RegistrySource.java
new file mode 100644
index 0000000..e54644c
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/RegistrySource.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.model.domain;
+
+public enum RegistrySource {
+
+    INTERFACE,
+
+    INSTANCE
+
+}
\ No newline at end of file
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/ServiceDefinition.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/ServiceDefinition.java
new file mode 100644
index 0000000..9205ac7
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/ServiceDefinition.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.model.domain;
+
+import org.apache.dubbo.metadata.definition.util.ClassUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * copy from {@link org.apache.dubbo.metadata.definition.model.ServiceDefinition} compatible 2.x version
+ */
+public class ServiceDefinition {
+
+    /**
+     * the canonical name of interface
+     *
+     * @see Class#getCanonicalName()
+     */
+    private String canonicalName;
+
+    /**
+     * the location of class file
+     *
+     * @see ClassUtils#getCodeSource(Class)
+     */
+    private String codeSource;
+
+    private List<MethodDefinition> methods;
+
+    /**
+     * the definitions of type
+     */
+    private List<TypeDefinition> types;
+
+    /**
+     * the definitions of annotations
+     */
+    private List<String> annotations;
+
+    public String getCanonicalName() {
+        return canonicalName;
+    }
+
+    public String getCodeSource() {
+        return codeSource;
+    }
+
+    public List<MethodDefinition> getMethods() {
+        if (methods == null) {
+            methods = new ArrayList<>();
+        }
+        return methods;
+    }
+
+    public List<TypeDefinition> getTypes() {
+        if (types == null) {
+            types = new ArrayList<>();
+        }
+        return types;
+    }
+
+    public String getUniqueId() {
+        return canonicalName + "@" + codeSource;
+    }
+
+    public void setCanonicalName(String canonicalName) {
+        this.canonicalName = canonicalName;
+    }
+
+    public void setCodeSource(String codeSource) {
+        this.codeSource = codeSource;
+    }
+
+    public void setMethods(List<MethodDefinition> methods) {
+        this.methods = methods;
+    }
+
+    public void setTypes(List<TypeDefinition> types) {
+        this.types = types;
+    }
+
+    public List<String> getAnnotations() {
+        if (annotations == null) {
+            annotations = Collections.emptyList();
+        }
+        return annotations;
+    }
+
+    public void setAnnotations(List<String> annotations) {
+        this.annotations = annotations;
+    }
+
+    public String toString() {
+        return "ServiceDefinition [canonicalName=" + canonicalName + ", codeSource=" + codeSource + ", methods="
+                + methods + "]";
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof ServiceDefinition)) {
+            return false;
+        }
+        ServiceDefinition that = (ServiceDefinition) o;
+        return Objects.equals(getCanonicalName(), that.getCanonicalName()) &&
+                Objects.equals(getCodeSource(), that.getCodeSource()) &&
+                Objects.equals(getMethods(), that.getMethods()) &&
+                Objects.equals(getTypes(), that.getTypes());
+    }
+
+    public int hashCode() {
+        return Objects.hash(getCanonicalName(), getCodeSource(), getMethods(), getTypes());
+    }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/TypeDefinition.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/TypeDefinition.java
new file mode 100644
index 0000000..71ed8fa
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/TypeDefinition.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.model.domain;
+
+import org.apache.dubbo.common.utils.StringUtils;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+
+/**
+ * copy from {@link org.apache.dubbo.metadata.definition.model.TypeDefinition} compatible 2.x version
+ */
+public class TypeDefinition implements Serializable {
+    private String id;
+    private String type;
+    @SerializedName("items")
+    private List<TypeDefinition> items;
+    @SerializedName("enum")
+    private List<String> enums;
+    private String $ref;
+    private Map<String, TypeDefinition> properties;
+    private String typeBuilderName;
+
+    public TypeDefinition() {
+    }
+
+    public TypeDefinition(String type) {
+        this.setType(type);
+    }
+
+    public static String[] formatTypes(String[] types) {
+        String[] newTypes = new String[types.length];
+
+        for (int i = 0; i < types.length; ++i) {
+            newTypes[i] = formatType(types[i]);
+        }
+
+        return newTypes;
+    }
+
+    public static String formatType(String type) {
+        return isGenericType(type) ? formatGenericType(type) : type;
+    }
+
+    private static String formatGenericType(String type) {
+        return StringUtils.replace(type, ", ", ",");
+    }
+
+    private static boolean isGenericType(String type) {
+        return type.contains("<") && type.contains(">");
+    }
+
+    public String get$ref() {
+        return this.$ref;
+    }
+
+    public List<String> getEnums() {
+        if (this.enums == null) {
+            this.enums = new ArrayList();
+        }
+
+        return this.enums;
+    }
+
+    public String getId() {
+        return this.id;
+    }
+
+    public List<TypeDefinition> getItems() {
+        if (this.items == null) {
+            this.items = new ArrayList();
+        }
+
+        return this.items;
+    }
+
+    public Map<String, TypeDefinition> getProperties() {
+        if (this.properties == null) {
+            this.properties = new HashMap();
+        }
+
+        return this.properties;
+    }
+
+    public String getType() {
+        return this.type;
+    }
+
+    public String getTypeBuilderName() {
+        return this.typeBuilderName;
+    }
+
+    public void set$ref(String $ref) {
+        this.$ref = $ref;
+    }
+
+    public void setEnums(List<String> enums) {
+        this.enums = enums;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setItems(List<TypeDefinition> items) {
+        this.items = items;
+    }
+
+    public void setProperties(Map<String, TypeDefinition> properties) {
+        this.properties = properties;
+    }
+
+    public void setType(String type) {
+        this.type = formatType(type);
+    }
+
+    public void setTypeBuilderName(String typeBuilderName) {
+        this.typeBuilderName = typeBuilderName;
+    }
+
+    public String toString() {
+        return "TypeDefinition [id=" + this.id + ", type=" + this.type + ", properties=" + this.properties + ", $ref=" + this.$ref + "]";
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        } else if (!(o instanceof TypeDefinition)) {
+            return false;
+        } else {
+            TypeDefinition that = (TypeDefinition) o;
+            return Objects.equals(this.getId(), that.getId()) && Objects.equals(this.getType(), that.getType()) && Objects.equals(this.getItems(), that.getItems()) && Objects.equals(this.getEnums(), that.getEnums()) && Objects.equals(this.get$ref(), that.get$ref()) && Objects.equals(this.getProperties(), that.getProperties());
+        }
+    }
+
+    public int hashCode() {
+        return Objects.hash(new Object[]{this.getId(), this.getType(), this.getItems(), this.getEnums(), this.get$ref(), this.getProperties()});
+    }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java
index 0202526..cd15916 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java
@@ -17,15 +17,17 @@
 
 package org.apache.dubbo.admin.model.dto;
 
+import org.apache.dubbo.admin.model.domain.RegistrySource;
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.Objects;
 
-public class ServiceDTO implements Comparable<ServiceDTO>{
+public class ServiceDTO implements Comparable<ServiceDTO> {
     private String service;
     private String appName;
     private String group;
     private String version;
+    private RegistrySource registrySource;
 
     public String getService() {
         return service;
@@ -59,6 +61,14 @@ public class ServiceDTO implements Comparable<ServiceDTO>{
         this.version = version;
     }
 
+    public RegistrySource getRegistrySource() {
+        return registrySource;
+    }
+
+    public void setRegistrySource(RegistrySource registrySource) {
+        this.registrySource = registrySource;
+    }
+
     @Override
     public int compareTo(ServiceDTO o) {
         int result = StringUtils.trimToEmpty(appName).compareTo(StringUtils.trimToEmpty(o.getAppName()));
@@ -70,6 +80,9 @@ public class ServiceDTO implements Comparable<ServiceDTO>{
             if (result == 0) {
                 result = StringUtils.trimToEmpty(version).compareTo(StringUtils.trimToEmpty(o.getVersion()));
             }
+            if (result == 0) {
+                result = registrySource.compareTo(o.registrySource);
+            }
         }
         return result;
     }
@@ -84,11 +97,11 @@ public class ServiceDTO implements Comparable<ServiceDTO>{
         }
         ServiceDTO that = (ServiceDTO) o;
         return Objects.equals(service, that.service) && Objects.equals(appName, that.appName) && Objects
-            .equals(group, that.group) && Objects.equals(version, that.version);
+                .equals(group, that.group) && Objects.equals(version, that.version) && Objects.equals(registrySource, that.registrySource);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(service, appName, group, version);
+        return Objects.hash(service, appName, group, version, registrySource);
     }
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java
index 1ef4beb..d15a7bf 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java
@@ -19,7 +19,6 @@ package org.apache.dubbo.admin.model.dto;
 
 import org.apache.dubbo.admin.model.domain.Consumer;
 import org.apache.dubbo.admin.model.domain.Provider;
-import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
 
 import java.util.List;
 
@@ -30,7 +29,7 @@ public class ServiceDetailDTO {
     private String service;
     private String application;
 
-    FullServiceDefinition metadata;
+    Object metadata;
 
     public String getService() {
         return service;
@@ -64,11 +63,11 @@ public class ServiceDetailDTO {
         this.consumers = consumers;
     }
 
-    public FullServiceDefinition getMetadata() {
+    public Object getMetadata() {
         return metadata;
     }
 
-    public void setMetadata(FullServiceDefinition metadata) {
+    public void setMetadata(Object metadata) {
         this.metadata = metadata;
     }
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AddressChangeListener.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AddressChangeListener.java
new file mode 100644
index 0000000..076bb56
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AddressChangeListener.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.registry.mapping;
+
+import org.apache.dubbo.common.URL;
+
+import java.util.List;
+
+public interface AddressChangeListener {
+
+    /**
+     * notify instance address url change
+     * @param protocolServiceKey {group}/{path/interfaceName}:{version}:protocol
+     * @param urls               instance address url
+     */
+    void notifyAddressChanged(String protocolServiceKey, List<URL> urls);
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminMappingListener.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminMappingListener.java
new file mode 100644
index 0000000..56db6e3
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminMappingListener.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.registry.mapping;
+
+import org.apache.dubbo.admin.common.util.Constants;
+import org.apache.dubbo.admin.service.impl.InstanceRegistryCache;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.metadata.MappingChangedEvent;
+import org.apache.dubbo.metadata.MappingListener;
+import org.apache.dubbo.registry.client.InstanceAddressURL;
+import org.apache.dubbo.registry.client.ServiceDiscovery;
+import org.apache.dubbo.registry.client.ServiceInstance;
+import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;
+import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
+
+import com.google.common.collect.Sets;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
+
+@Component
+public class AdminMappingListener implements MappingListener {
+
+    private static final URL CONSUMER_URL = new URL(Constants.ADMIN_PROTOCOL, NetUtils.getLocalHost(), 0, "",
+            Constants.INTERFACE_KEY, Constants.ANY_VALUE,
+            Constants.GROUP_KEY, Constants.ANY_VALUE,
+            Constants.VERSION_KEY, Constants.ANY_VALUE,
+            Constants.CLASSIFIER_KEY, Constants.ANY_VALUE,
+            Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY + ","
+            + Constants.CONSUMERS_CATEGORY + ","
+            + Constants.ROUTERS_CATEGORY + ","
+            + Constants.CONFIGURATORS_CATEGORY,
+            Constants.ENABLED_KEY, Constants.ANY_VALUE,
+            Constants.CHECK_KEY, String.valueOf(false));
+
+    /* app - listener */
+    private final Map<String, ServiceInstancesChangedListener> serviceListeners = new ConcurrentHashMap<>();
+
+    private final ServiceDiscovery serviceDiscovery;
+
+    private final InstanceRegistryCache instanceRegistryCache;
+
+    public AdminMappingListener(ServiceDiscovery serviceDiscovery, InstanceRegistryCache instanceRegistryCache) {
+        this.serviceDiscovery = serviceDiscovery;
+        this.instanceRegistryCache = instanceRegistryCache;
+    }
+
+    @Override
+    public void onEvent(MappingChangedEvent event) {
+        Set<String> apps = event.getApps();
+        if (CollectionUtils.isEmpty(apps)) {
+            return;
+        }
+        for (String serviceName : apps) {
+            ServiceInstancesChangedListener serviceInstancesChangedListener = serviceListeners.get(serviceName);
+            if (serviceInstancesChangedListener == null) {
+                synchronized (this) {
+                    serviceInstancesChangedListener = serviceListeners.get(serviceName);
+                    if (serviceInstancesChangedListener == null) {
+                        AddressChangeListener addressChangeListener = new DefaultAddressChangeListener(serviceName, instanceRegistryCache);
+                        serviceInstancesChangedListener = new AdminServiceInstancesChangedListener(Sets.newHashSet(serviceName), serviceDiscovery, addressChangeListener);
+                        serviceInstancesChangedListener.setUrl(CONSUMER_URL);
+                        List<ServiceInstance> serviceInstances = serviceDiscovery.getInstances(serviceName);
+                        if (CollectionUtils.isNotEmpty(serviceInstances)) {
+                            serviceInstancesChangedListener.onEvent(new ServiceInstancesChangedEvent(serviceName, serviceInstances));
+                        }
+                        serviceListeners.put(serviceName, serviceInstancesChangedListener);
+                        serviceInstancesChangedListener.setUrl(CONSUMER_URL);
+                        serviceDiscovery.addServiceInstancesChangedListener(serviceInstancesChangedListener);
+                    }
+                }
+            }
+        }
+    }
+
+    private static class DefaultAddressChangeListener implements AddressChangeListener {
+
+        private String serviceName;
+
+        private InstanceRegistryCache instanceRegistryCache;
+
+        public DefaultAddressChangeListener(String serviceName, InstanceRegistryCache instanceRegistryCache) {
+            this.serviceName = serviceName;
+            this.instanceRegistryCache = instanceRegistryCache;
+        }
+
+        @Override
+        public void notifyAddressChanged(String protocolServiceKey, List<URL> urls) {
+            String serviceKey = removeProtocol(protocolServiceKey);
+            ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> appServiceMap = instanceRegistryCache.computeIfAbsent(Constants.PROVIDERS_CATEGORY, key -> new ConcurrentHashMap<>());
+            Map<String, List<InstanceAddressURL>> serviceMap = appServiceMap.computeIfAbsent(serviceName, key -> new ConcurrentHashMap<>());
+            if (CollectionUtils.isEmpty(urls)) {
+                serviceMap.remove(serviceKey);
+            } else {
+                List<InstanceAddressURL> instanceAddressUrls = urls.stream().map(url -> (InstanceAddressURL) url).collect(Collectors.toList());
+                serviceMap.put(serviceKey, instanceAddressUrls);
+            }
+        }
+
+        private String removeProtocol(String protocolServiceKey) {
+            int index = protocolServiceKey.lastIndexOf(":");
+            if (index == -1) {
+                return protocolServiceKey;
+            }
+            return protocolServiceKey.substring(0, index);
+        }
+    }
+
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminServiceInstancesChangedListener.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminServiceInstancesChangedListener.java
new file mode 100644
index 0000000..1afde55
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminServiceInstancesChangedListener.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.registry.mapping;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.registry.client.ServiceDiscovery;
+import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class AdminServiceInstancesChangedListener extends ServiceInstancesChangedListener {
+
+    private AddressChangeListener addressChangeListener;
+
+    private Map<String, Object> oldServiceUrls;
+
+    public AdminServiceInstancesChangedListener(Set<String> serviceNames, ServiceDiscovery serviceDiscovery, AddressChangeListener addressChangeListener) {
+        super(serviceNames, serviceDiscovery);
+        this.addressChangeListener = addressChangeListener;
+        oldServiceUrls = new HashMap<>();
+    }
+
+    protected void notifyAddressChanged() {
+        oldServiceUrls.keySet().stream()
+                .filter(protocolServiceKey -> !serviceUrls.containsKey(protocolServiceKey))
+                .forEach(protocolServiceKey -> addressChangeListener.notifyAddressChanged(protocolServiceKey, new ArrayList<>()));
+        serviceUrls.forEach((protocolServiceKey, urls) -> addressChangeListener.notifyAddressChanged(protocolServiceKey, (List<URL>) urls));
+
+        oldServiceUrls = serviceUrls;
+    }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/ServiceMapping.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/ServiceMapping.java
new file mode 100644
index 0000000..6559a29
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/ServiceMapping.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.registry.mapping;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.metadata.MappingListener;
+
+/**
+ * listen all mapping group service
+ */
+@SPI("zookeeper")
+public interface ServiceMapping {
+
+    void init(URL url);
+
+    void listenerAll();
+
+    void addMappingListener(MappingListener listener);
+
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/NoOpServiceMapping.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/NoOpServiceMapping.java
new file mode 100644
index 0000000..845efa2
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/NoOpServiceMapping.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.registry.mapping.impl;
+
+import org.apache.dubbo.admin.registry.mapping.ServiceMapping;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.metadata.MappingListener;
+
+public class NoOpServiceMapping implements ServiceMapping {
+
+    @Override
+    public void init(URL url) {
+
+    }
+
+    @Override
+    public void listenerAll() {
+
+    }
+
+    @Override
+    public void addMappingListener(MappingListener listener) {
+
+    }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/ZookeeperServiceMapping.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/ZookeeperServiceMapping.java
new file mode 100644
index 0000000..799c040
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/ZookeeperServiceMapping.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.registry.mapping.impl;
+
+import org.apache.dubbo.admin.common.util.Constants;
+import org.apache.dubbo.admin.registry.mapping.ServiceMapping;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.ConcurrentHashSet;
+import org.apache.dubbo.metadata.MappingChangedEvent;
+import org.apache.dubbo.metadata.MappingListener;
+import org.apache.dubbo.remoting.zookeeper.ZookeeperClient;
+import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
+
+import java.util.List;
+import java.util.Set;
+
+import static org.apache.dubbo.metadata.ServiceNameMapping.getAppNames;
+
+
+public class ZookeeperServiceMapping implements ServiceMapping {
+
+    private ZookeeperClient zkClient;
+
+    private final static String MAPPING_PATH = Constants.PATH_SEPARATOR + Constants.DEFAULT_ROOT + Constants.PATH_SEPARATOR + Constants.DEFAULT_MAPPING_GROUP;
+
+    private final Set<MappingListener> listeners = new ConcurrentHashSet<>();
+
+    private final Set<String> anyServices = new ConcurrentHashSet<>();
+
+    @Override
+    public void init(URL url) {
+        ZookeeperTransporter zookeeperTransporter = ZookeeperTransporter.getExtension();
+        zkClient = zookeeperTransporter.connect(url);
+        listenerAll();
+    }
+
+    @Override
+    public void listenerAll() {
+        zkClient.create(MAPPING_PATH, false);
+        List<String> services = zkClient.addChildListener(MAPPING_PATH, (path, currentChildList) -> {
+            for (String child : currentChildList) {
+                if (anyServices.add(child)) {
+                    notifyMappingChangedEvent(child);
+                }
+            }
+        });
+        if (CollectionUtils.isNotEmpty(services)) {
+            for (String service : services) {
+                if (anyServices.add(service)) {
+                    notifyMappingChangedEvent(service);
+                }
+            }
+        }
+    }
+
+    private void notifyMappingChangedEvent(String service) {
+        if (service.equals(Constants.CONFIGURATORS_CATEGORY) || service.equals(Constants.CONSUMERS_CATEGORY)
+                || service.equals(Constants.PROVIDERS_CATEGORY) || service.equals(Constants.ROUTERS_CATEGORY)) {
+            return;
+        }
+        String servicePath = MAPPING_PATH + Constants.PATH_SEPARATOR + service;
+        String content = zkClient.getContent(servicePath);
+        if (content != null) {
+            Set<String> apps = getAppNames(content);
+            MappingChangedEvent event = new MappingChangedEvent(service, apps);
+            for (MappingListener listener : listeners) {
+                listener.onEvent(event);
+            }
+        }
+    }
+
+    @Override
+    public void addMappingListener(MappingListener listener) {
+        listeners.add(listener);
+    }
+
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/ProviderService.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/ProviderService.java
index 95d46f8..5417d30 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/ProviderService.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/ProviderService.java
@@ -25,26 +25,11 @@ import java.util.Set;
 
 /**
  * ProviderService
- *
  */
 public interface ProviderService {
 
     void create(Provider provider);
 
-//    void enableProvider(String id);
-
-//    void disableProvider(String id);
-
-//    void doublingProvider(String id);
-
-//    void halvingProvider(String id);
-
-    void deleteStaticProvider(String id);
-
-    void updateProvider(Provider provider);
-
-    Provider findProvider(String id);
-
     String getProviderMetaData(MetadataIdentifier providerIdentifier);
 
     /**
@@ -54,18 +39,20 @@ public interface ProviderService {
      */
     Set<String> findServices();
 
+    /**
+     * Get all instance registry provider's service name
+     *
+     * @return list of all provider's service name
+     */
+    Set<String> findInstanceApplications();
+
+
     String findServiceVersion(String serviceName, String application);
 
     String findVersionInApplication(String application);
 
     List<String> findAddresses();
 
-    List<String> findAddressesByApplication(String application);
-
-    List<String> findAddressesByService(String serviceName);
-
-    List<String> findApplicationsByServiceName(String serviceName);
-
     /**
      * Get provider list with specific service name.
      *
@@ -74,8 +61,6 @@ public interface ProviderService {
      */
     List<Provider> findByService(String serviceName);
 
-    List<Provider> findByAppandService(String app, String serviceName);
-
     List<Provider> findAll();
 
     /**
@@ -86,8 +71,6 @@ public interface ProviderService {
      */
     List<Provider> findByAddress(String providerAddress);
 
-    List<String> findServicesByAddress(String providerAddress);
-
     Set<String> findApplications();
 
     /**
@@ -100,13 +83,9 @@ public interface ProviderService {
 
     List<String> findServicesByApplication(String application);
 
-    List<String> findMethodsByService(String serviceName);
-
-    Provider findByServiceAndAddress(String service, String address);
-
     /**
      * Get a set of service data object.
-     *
+     * <p>
      * ServiceDTO object contains base information include
      * service name , application, group and version.
      *
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryCache.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryCache.java
new file mode 100644
index 0000000..0335909
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryCache.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.service;
+
+import java.util.function.Function;
+
+/**
+ * cache registry url
+ */
+public interface RegistryCache<K, V> {
+
+    /**
+     * put cache
+     *
+     * @param key   key
+     * @param value value
+     */
+    void put(K key, V value);
+
+    /**
+     * get cache
+     *
+     * @param key key
+     * @return value
+     */
+    V get(K key);
+
+
+    default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+        return null;
+    }
+
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
index f57cdb3..dab1a43 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
@@ -19,6 +19,8 @@ package org.apache.dubbo.admin.service;
 import org.apache.dubbo.admin.common.util.CoderUtil;
 import org.apache.dubbo.admin.common.util.Constants;
 import org.apache.dubbo.admin.common.util.Tool;
+import org.apache.dubbo.admin.service.impl.InterfaceRegistryCache;
+import org.apache.dubbo.common.BaseServiceMetadata;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
@@ -69,13 +71,11 @@ public class RegistryServerSync implements DisposableBean, NotifyListener {
      * ConcurrentMap<category, ConcurrentMap<servicename, Map<MD5, URL>>>
      * registryCache
      */
-    private final ConcurrentMap<String, ConcurrentMap<String, Map<String, URL>>> registryCache = new ConcurrentHashMap<>();
     @Autowired
     private Registry registry;
 
-    public ConcurrentMap<String, ConcurrentMap<String, Map<String, URL>>> getRegistryCache() {
-        return registryCache;
-    }
+    @Autowired
+    private InterfaceRegistryCache interfaceRegistryCache;
 
     @EventListener(classes = ApplicationReadyEvent.class)
     public void startSubscribe() {
@@ -98,16 +98,19 @@ public class RegistryServerSync implements DisposableBean, NotifyListener {
         final Map<String, Map<String, Map<String, URL>>> categories = new HashMap<>();
         String interfaceName = null;
         for (URL url : urls) {
-            String category = url.getParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY);
+            String category = url.getUrlParam().getParameter(Constants.CATEGORY_KEY);
+            if (category == null) {
+                category = Constants.PROVIDERS_CATEGORY;
+            }
             // NOTE: group and version in empty protocol is *
             if (Constants.EMPTY_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
-                ConcurrentMap<String, Map<String, URL>> services = registryCache.get(category);
+                ConcurrentMap<String, Map<String, URL>> services = interfaceRegistryCache.get(category);
                 if (services != null) {
-                    String group = url.getParameter(Constants.GROUP_KEY);
-                    String version = url.getParameter(Constants.VERSION_KEY);
+                    String group = url.getUrlParam().getParameter(Constants.GROUP_KEY);
+                    String version = url.getUrlParam().getParameter(Constants.VERSION_KEY);
                     // NOTE: group and version in empty protocol is *
                     if (!Constants.ANY_VALUE.equals(group) && !Constants.ANY_VALUE.equals(version)) {
-                        services.remove(url.getServiceKey());
+                        services.remove(url.getServiceInterface());
                     } else {
                         for (Map.Entry<String, Map<String, URL>> serviceEntry : services.entrySet()) {
                             String service = serviceEntry.getKey();
@@ -128,7 +131,9 @@ public class RegistryServerSync implements DisposableBean, NotifyListener {
                     services = new HashMap<>();
                     categories.put(category, services);
                 }
-                String service = url.getServiceKey();
+                String group = url.getUrlParam().getParameter(Constants.GROUP_KEY);
+                String version = url.getUrlParam().getParameter(Constants.VERSION_KEY);
+                String service = BaseServiceMetadata.buildServiceKey(url.getServiceInterface(), group, version);
                 Map<String, URL> ids = services.get(service);
                 if (ids == null) {
                     ids = new HashMap<>();
@@ -150,10 +155,10 @@ public class RegistryServerSync implements DisposableBean, NotifyListener {
         }
         for (Map.Entry<String, Map<String, Map<String, URL>>> categoryEntry : categories.entrySet()) {
             String category = categoryEntry.getKey();
-            ConcurrentMap<String, Map<String, URL>> services = registryCache.get(category);
+            ConcurrentMap<String, Map<String, URL>> services = interfaceRegistryCache.get(category);
             if (services == null) {
                 services = new ConcurrentHashMap<String, Map<String, URL>>();
-                registryCache.put(category, services);
+                interfaceRegistryCache.put(category, services);
             } else {// Fix map can not be cleared when service is unregistered: when a unique “group/service:version” service is unregistered, but we still have the same services with different version or group, so empty protocols can not be invoked.
                 Set<String> keys = new HashSet<String>(services.keySet());
                 for (String key : keys) {
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/AbstractService.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/AbstractService.java
index f7bae0d..501b13e 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/AbstractService.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/AbstractService.java
@@ -18,7 +18,6 @@ package org.apache.dubbo.admin.service.impl;
 
 import org.apache.dubbo.admin.registry.config.GovernanceConfiguration;
 import org.apache.dubbo.admin.registry.metadata.MetaDataCollector;
-import org.apache.dubbo.admin.service.RegistryServerSync;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
@@ -42,10 +41,10 @@ public class AbstractService {
     protected MetaDataCollector metaDataCollector;
 
     @Autowired
-    private RegistryServerSync sync;
+    private InterfaceRegistryCache interfaceRegistryCache;
 
-    public ConcurrentMap<String, ConcurrentMap<String, Map<String, URL>>> getRegistryCache() {
-        return sync.getRegistryCache();
+    public ConcurrentMap<String, ConcurrentMap<String, Map<String, URL>>> getInterfaceRegistryCache() {
+        return interfaceRegistryCache.getRegistryCache();
     }
 
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java
index 4a803ed..0d0f2e5 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java
@@ -52,7 +52,7 @@ public class ConsumerServiceImpl extends AbstractService implements ConsumerServ
     private Map<String, URL> findAllConsumerUrl() {
         Map<String, String> filter = new HashMap<String, String>();
         filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY);
-        return SyncUtils.filterFromCategory(getRegistryCache(), filter);
+        return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter);
     }
 
 
@@ -69,7 +69,7 @@ public class ConsumerServiceImpl extends AbstractService implements ConsumerServ
         filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY);
         filter.put(SyncUtils.ADDRESS_FILTER_KEY, address);
 
-        return SyncUtils.filterFromCategory(getRegistryCache(), filter);
+        return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter);
     }
 
     public Map<String, URL> findConsumerUrlByService(String service) {
@@ -77,7 +77,7 @@ public class ConsumerServiceImpl extends AbstractService implements ConsumerServ
         filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY);
         filter.put(SyncUtils.SERVICE_FILTER_KEY, service);
 
-        return SyncUtils.filterFromCategory(getRegistryCache(), filter);
+        return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter);
     }
 
     @Override
@@ -85,7 +85,7 @@ public class ConsumerServiceImpl extends AbstractService implements ConsumerServ
         Map<String, String> filter = new HashMap<>();
         filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY);
         filter.put(Constants.APPLICATION_KEY, application);
-        Map<String, URL> stringURLMap = SyncUtils.filterFromCategory(getRegistryCache(), filter);
+        Map<String, URL> stringURLMap = SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter);
         if (stringURLMap == null || stringURLMap.isEmpty()) {
             throw new ParamValidationException("there is no consumer for application: " + application);
         }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryCache.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryCache.java
new file mode 100644
index 0000000..9f1b5ac
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryCache.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.service.impl;
+
+import org.apache.dubbo.admin.service.RegistryCache;
+import org.apache.dubbo.registry.client.InstanceAddressURL;
+
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.Function;
+
+/**
+ * instance registry url {@link InstanceAddressURL} cache
+ * key --> category,value --> ConcurrentMap<appName, Map<serviceKey, List<InstanceAddressURL>>>
+ */
+@Component
+public class InstanceRegistryCache implements RegistryCache<String, ConcurrentMap<String, Map<String, List<InstanceAddressURL>>>> {
+
+    private final ConcurrentMap<String, ConcurrentMap<String, Map<String, List<InstanceAddressURL>>>> registryCache = new ConcurrentHashMap<>();
+
+    @Override
+    public void put(String key, ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> value) {
+        registryCache.put(key, value);
+    }
+
+    @Override
+    public ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> get(String key) {
+        return registryCache.get(key);
+    }
+
+    @Override
+    public ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> computeIfAbsent(String key,
+                                                                                        Function<? super String, ? extends ConcurrentMap<String, Map<String, List<InstanceAddressURL>>>> mappingFunction) {
+        return registryCache.computeIfAbsent(key, mappingFunction);
+    }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryQueryHelper.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryQueryHelper.java
new file mode 100644
index 0000000..aae6e65
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryQueryHelper.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.service.impl;
+
+import org.apache.dubbo.admin.common.util.Constants;
+import org.apache.dubbo.admin.model.domain.Provider;
+import org.apache.dubbo.admin.model.domain.RegistrySource;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.metadata.MetadataInfo;
+import org.apache.dubbo.registry.client.InstanceAddressURL;
+import org.apache.dubbo.registry.client.ServiceInstance;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
+
+@Component
+public class InstanceRegistryQueryHelper {
+
+    private final InstanceRegistryCache instanceRegistryCache;
+
+    public InstanceRegistryQueryHelper(InstanceRegistryCache instanceRegistryCache) {
+        this.instanceRegistryCache = instanceRegistryCache;
+    }
+
+
+    public Set<String> findServices() {
+        Set<String> services = Sets.newHashSet();
+        ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY);
+        if (appInterfaceMap == null) {
+            return services;
+        }
+        appInterfaceMap.values().forEach(serviceUrlMap ->
+                serviceUrlMap.forEach((service, urls) -> {
+                    if (CollectionUtils.isNotEmpty(urls)) {
+                        services.add(service);
+                    }
+                }));
+        return services;
+    }
+
+    public Set<String> findApplications() {
+        ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY);
+        if (appInterfaceMap == null) {
+            return Sets.newHashSet();
+        }
+        return Sets.newHashSet(appInterfaceMap.keySet());
+    }
+
+    public List<Provider> findByService(String serviceName) {
+        ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY);
+        if (appInterfaceMap == null) {
+            return Lists.newArrayList();
+        }
+        List<InstanceAddressURL> providerUrls = Lists.newArrayList();
+        appInterfaceMap.values().forEach(serviceUrlMap ->
+                serviceUrlMap.forEach((service, urls) -> {
+                    if (CollectionUtils.isNotEmpty(urls) && service.equals(serviceName)) {
+                        providerUrls.addAll(urls);
+                    }
+                }));
+        return urlsToProviderList(providerUrls).stream()
+                .filter(provider -> provider.getService().equals(serviceName))
+                .collect(Collectors.toList());
+    }
+
+    public List<Provider> findByAddress(String providerAddress) {
+        ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY);
+        if (appInterfaceMap == null) {
+            return Lists.newArrayList();
+        }
+        List<InstanceAddressURL> providerUrls = Lists.newArrayList();
+        appInterfaceMap.values().forEach(serviceUrlMap ->
+                serviceUrlMap.forEach((service, urls) -> {
+                    if (CollectionUtils.isNotEmpty(urls)) {
+                        urls.forEach(url -> {
+                            if ((url.getInstance().getHost().equals(providerAddress))) {
+                                providerUrls.add(url);
+                            }
+                        });
+                    }
+                }));
+        return urlsToProviderList(providerUrls);
+    }
+
+    public List<Provider> findByApplication(String application) {
+        ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY);
+        if (appInterfaceMap == null || appInterfaceMap.get(application) == null) {
+            return Lists.newArrayList();
+        }
+        List<InstanceAddressURL> providerUrls = Lists.newArrayList();
+        appInterfaceMap.get(application).forEach((service, urls) -> providerUrls.addAll(urls));
+        return urlsToProviderList(providerUrls);
+    }
+
+    public String findVersionInApplication(String application) {
+        ConcurrentMap<String, Map<String, List<InstanceAddressURL>>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY);
+        if (appInterfaceMap == null || appInterfaceMap.get(application) == null) {
+            return null;
+        }
+        Map<String, List<InstanceAddressURL>> urlsMap = appInterfaceMap.get(application);
+        for (Map.Entry<String, List<InstanceAddressURL>> entry : urlsMap.entrySet()) {
+            List<InstanceAddressURL> urls = entry.getValue();
+            if (CollectionUtils.isNotEmpty(urls)) {
+                return urls.get(0).getParameter(Constants.SPECIFICATION_VERSION_KEY, "3.0.0");
+            }
+        }
+        return null;
+    }
+
+    private List<Provider> urlsToProviderList(List<InstanceAddressURL> urls) {
+        List<Provider> providers = Lists.newArrayList();
+        urls.stream().distinct().forEach(url -> {
+            ServiceInstance instance = url.getInstance();
+            MetadataInfo metadataInfo = url.getMetadataInfo();
+
+            metadataInfo.getServices().forEach((serviceKey, serviceInfo) -> {
+                Provider p = new Provider();
+                String service = serviceInfo.getServiceKey();
+                p.setService(service);
+                p.setAddress(url.getAddress());
+                p.setApplication(instance.getServiceName());
+                p.setUrl(url.toParameterString());
+                p.setDynamic(url.getParameter("dynamic", true));
+                p.setEnabled(url.getParameter(Constants.ENABLED_KEY, true));
+                p.setWeight(url.getParameter(Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT));
+                p.setUsername(url.getParameter("owner"));
+                p.setRegistrySource(RegistrySource.INSTANCE);
+                providers.add(p);
+            });
+        });
+        return providers;
+    }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/AbstractService.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InterfaceRegistryCache.java
similarity index 56%
copy from dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/AbstractService.java
copy to dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InterfaceRegistryCache.java
index f7bae0d..ab5b3be 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/AbstractService.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InterfaceRegistryCache.java
@@ -14,38 +14,38 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.apache.dubbo.admin.service.impl;
 
-import org.apache.dubbo.admin.registry.config.GovernanceConfiguration;
-import org.apache.dubbo.admin.registry.metadata.MetaDataCollector;
-import org.apache.dubbo.admin.service.RegistryServerSync;
+import org.apache.dubbo.admin.service.RegistryCache;
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.registry.Registry;
-import org.springframework.beans.factory.annotation.Autowired;
+
+import org.springframework.stereotype.Component;
 
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
-public class AbstractService {
-
-    protected static final Logger logger = LoggerFactory.getLogger(AbstractService.class);
-
-    @Autowired
-    protected Registry registry;
+/**
+ * interface registry url cache
+ * key --> category,value --> ConcurrentMap<serviceKey, Map<hash, URL>>
+ */
+@Component
+public class InterfaceRegistryCache implements RegistryCache<String, ConcurrentMap<String, Map<String, URL>>> {
 
-    @Autowired
-    protected GovernanceConfiguration dynamicConfiguration;
+    private final ConcurrentMap<String, ConcurrentMap<String, Map<String, URL>>> registryCache = new ConcurrentHashMap<>();
 
-    @Autowired
-    protected MetaDataCollector metaDataCollector;
+    @Override
+    public void put(String key, ConcurrentMap<String, Map<String, URL>> value) {
+        registryCache.put(key, value);
+    }
 
-    @Autowired
-    private RegistryServerSync sync;
+    @Override
+    public ConcurrentMap<String, Map<String, URL>> get(String key) {
+        return registryCache.get(key);
+    }
 
     public ConcurrentMap<String, ConcurrentMap<String, Map<String, URL>>> getRegistryCache() {
-        return sync.getRegistryCache();
+        return registryCache;
     }
-
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
index 0d83081..1defce7 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
@@ -18,16 +18,14 @@ package org.apache.dubbo.admin.service.impl;
 
 import org.apache.dubbo.admin.common.exception.ParamValidationException;
 import org.apache.dubbo.admin.common.util.Constants;
-import org.apache.dubbo.admin.common.util.Pair;
-import org.apache.dubbo.admin.common.util.ParseUtils;
 import org.apache.dubbo.admin.common.util.SyncUtils;
 import org.apache.dubbo.admin.common.util.Tool;
 import org.apache.dubbo.admin.model.domain.Provider;
 import org.apache.dubbo.admin.model.dto.ServiceDTO;
-import org.apache.dubbo.admin.service.OverrideService;
 import org.apache.dubbo.admin.service.ProviderService;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -37,7 +35,6 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.ConcurrentMap;
@@ -49,7 +46,7 @@ import java.util.stream.Collectors;
 public class ProviderServiceImpl extends AbstractService implements ProviderService {
 
     @Autowired
-    OverrideService overrideService;
+    private InstanceRegistryQueryHelper instanceRegistryQueryHelper;
 
     @Override
     public void create(Provider provider) {
@@ -63,57 +60,27 @@ public class ProviderServiceImpl extends AbstractService implements ProviderServ
         return metaDataCollector.getProviderMetaData(providerIdentifier);
     }
 
-
-    @Override
-    public void deleteStaticProvider(String id) {
-        URL oldProvider = findProviderUrl(id);
-        if (oldProvider == null) {
-            throw new IllegalStateException("Provider was changed!");
-        }
-        registry.unregister(oldProvider);
-    }
-
-    @Override
-    public void updateProvider(Provider provider) {
-        String hash = provider.getHash();
-        if (hash == null) {
-            throw new IllegalStateException("no provider id");
-        }
-
-        URL oldProvider = findProviderUrl(hash);
-        if (oldProvider == null) {
-            throw new IllegalStateException("Provider was changed!");
-        }
-        URL newProvider = provider.toUrl();
-
-        registry.unregister(oldProvider);
-        registry.register(newProvider);
-    }
-
-    @Override
-    public Provider findProvider(String id) {
-        return SyncUtils.url2Provider(findProviderUrlPair(id));
-    }
-
-    public Pair<String, URL> findProviderUrlPair(String id) {
-        return SyncUtils.filterFromCategory(getRegistryCache(), Constants.PROVIDERS_CATEGORY, id);
-    }
-
     @Override
     public Set<String> findServices() {
         Set<String> ret = new HashSet<>();
-        ConcurrentMap<String, Map<String, URL>> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY);
-        if (providerUrls != null){
+        ConcurrentMap<String, Map<String, URL>> providerUrls = getInterfaceRegistryCache().get(Constants.PROVIDERS_CATEGORY);
+        if (providerUrls != null) {
             ret.addAll(providerUrls.keySet());
         }
+        ret.addAll(instanceRegistryQueryHelper.findServices());
         return ret;
     }
 
     @Override
+    public Set<String> findInstanceApplications() {
+        return instanceRegistryQueryHelper.findApplications();
+    }
+
+    @Override
     public List<String> findAddresses() {
         List<String> ret = new ArrayList<String>();
 
-        ConcurrentMap<String, Map<String, URL>> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY);
+        ConcurrentMap<String, Map<String, URL>> providerUrls = getInterfaceRegistryCache().get(Constants.PROVIDERS_CATEGORY);
         if (null == providerUrls) {
             return ret;
         }
@@ -128,80 +95,15 @@ public class ProviderServiceImpl extends AbstractService implements ProviderServ
                 }
             }
         }
-
-        return ret;
-    }
-
-    @Override
-    public List<String> findAddressesByApplication(String application) {
-        List<String> ret = new ArrayList<String>();
-        ConcurrentMap<String, Map<String, URL>> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY);
-        for (Map.Entry<String, Map<String, URL>> e1 : providerUrls.entrySet()) {
-            Map<String, URL> value = e1.getValue();
-            for (Map.Entry<String, URL> e2 : value.entrySet()) {
-                URL u = e2.getValue();
-                if (application.equals(u.getParameter(Constants.APPLICATION))) {
-                    String addr = u.getAddress();
-                    if (addr != null) {
-                        ret.add(addr);
-                    }
-                }
-            }
-        }
-
-        return ret;
-    }
-
-    @Override
-    public List<String> findAddressesByService(String service) {
-        List<String> ret = new ArrayList<String>();
-        ConcurrentMap<String, Map<String, URL>> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY);
-        if (null == providerUrls) {
-            return ret;
-        }
-
-        for (Map.Entry<String, URL> e2 : providerUrls.get(service).entrySet()) {
-            URL u = e2.getValue();
-            String app = u.getAddress();
-            if (app != null) {
-                ret.add(app);
-            }
-        }
-
-        return ret;
-    }
-
-    @Override
-    public List<String> findApplicationsByServiceName(String service) {
-        List<String> ret = new ArrayList<String>();
-        ConcurrentMap<String, Map<String, URL>> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY);
-        if (null == providerUrls) {
-            return ret;
-        }
-
-        Map<String, URL> value = providerUrls.get(service);
-        if (value == null) {
-            return ret;
-        }
-        for (Map.Entry<String, URL> e2 : value.entrySet()) {
-            URL u = e2.getValue();
-            String app = u.getParameter(Constants.APPLICATION);
-            if (app != null){
-                ret.add(app);
-            }
-        }
-
         return ret;
     }
 
     @Override
     public List<Provider> findByService(String serviceName) {
-        return SyncUtils.url2ProviderList(findProviderUrlByService(serviceName));
-    }
-
-    @Override
-    public List<Provider> findByAppandService(String app, String serviceName) {
-        return SyncUtils.url2ProviderList(findProviderUrlByAppandService(app, serviceName));
+        List<Provider> instanceProviders = instanceRegistryQueryHelper.findByService(serviceName);
+        List<Provider> interfaceProviders = SyncUtils.url2ProviderList(findProviderUrlByService(serviceName));
+        instanceProviders.addAll(interfaceProviders);
+        return instanceProviders;
     }
 
     private Map<String, URL> findProviderUrlByService(String service) {
@@ -209,7 +111,7 @@ public class ProviderServiceImpl extends AbstractService implements ProviderServ
         filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY);
         filter.put(SyncUtils.SERVICE_FILTER_KEY, service);
 
-        return SyncUtils.filterFromCategory(getRegistryCache(), filter);
+        return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter);
     }
 
     @Override
@@ -220,12 +122,15 @@ public class ProviderServiceImpl extends AbstractService implements ProviderServ
     private Map<String, URL> findAllProviderUrl() {
         Map<String, String> filter = new HashMap<String, String>();
         filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY);
-        return SyncUtils.filterFromCategory(getRegistryCache(), filter);
+        return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter);
     }
 
     @Override
     public List<Provider> findByAddress(String providerAddress) {
-        return SyncUtils.url2ProviderList(findProviderUrlByAddress(providerAddress));
+        List<Provider> instanceProviders = instanceRegistryQueryHelper.findByAddress(providerAddress);
+        List<Provider> interfaceProviders = SyncUtils.url2ProviderList(findProviderUrlByAddress(providerAddress));
+        instanceProviders.addAll(interfaceProviders);
+        return instanceProviders;
     }
 
     public Map<String, URL> findProviderUrlByAddress(String address) {
@@ -233,37 +138,14 @@ public class ProviderServiceImpl extends AbstractService implements ProviderServ
         filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY);
         filter.put(SyncUtils.ADDRESS_FILTER_KEY, address);
 
-        return SyncUtils.filterFromCategory(getRegistryCache(), filter);
-    }
-
-    @Override
-    public List<String> findServicesByAddress(String address) {
-        List<String> ret = new ArrayList<String>();
-
-        ConcurrentMap<String, Map<String, URL>> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY);
-        if (providerUrls == null || address == null || address.length() == 0) {
-            return ret;
-        }
-
-        for (Map.Entry<String, Map<String, URL>> e1 : providerUrls.entrySet()) {
-            Map<String, URL> value = e1.getValue();
-            for (Map.Entry<String, URL> e2 : value.entrySet()) {
-                URL u = e2.getValue();
-                if (address.equals(u.getAddress())) {
-                    ret.add(e1.getKey());
-                    break;
-                }
-            }
-        }
-
-        return ret;
+        return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter);
     }
 
     @Override
     public Set<String> findApplications() {
-        Set<String> ret = new HashSet<>();
-        ConcurrentMap<String, Map<String, URL>> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY);
-        if (providerUrls == null){
+        Set<String> ret = instanceRegistryQueryHelper.findApplications();
+        ConcurrentMap<String, Map<String, URL>> providerUrls = getInterfaceRegistryCache().get(Constants.PROVIDERS_CATEGORY);
+        if (providerUrls == null) {
             return ret;
         }
 
@@ -283,11 +165,18 @@ public class ProviderServiceImpl extends AbstractService implements ProviderServ
 
     @Override
     public List<Provider> findByApplication(String application) {
-        return SyncUtils.url2ProviderList(findProviderUrlByApplication(application));
+        List<Provider> instanceProviders = instanceRegistryQueryHelper.findByApplication(application);
+        List<Provider> interfaceProviders = SyncUtils.url2ProviderList(findProviderUrlByApplication(application));
+        instanceProviders.addAll(interfaceProviders);
+        return instanceProviders;
     }
 
     @Override
     public String findVersionInApplication(String application) {
+        String version = instanceRegistryQueryHelper.findVersionInApplication(application);
+        if (StringUtils.isNotBlank(version)){
+            return version;
+        }
         List<String> services = findServicesByApplication(application);
         if (services == null || services.size() == 0) {
             throw new ParamValidationException("there is no service for application: " + application);
@@ -313,23 +202,22 @@ public class ProviderServiceImpl extends AbstractService implements ProviderServ
         filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY);
         filter.put(Constants.APPLICATION, app);
         filter.put(SyncUtils.SERVICE_FILTER_KEY, service);
-        return SyncUtils.filterFromCategory(getRegistryCache(), filter);
+        return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter);
     }
 
 
-
     private Map<String, URL> findProviderUrlByApplication(String application) {
         Map<String, String> filter = new HashMap<>();
         filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY);
         filter.put(Constants.APPLICATION, application);
-        return SyncUtils.filterFromCategory(getRegistryCache(), filter);
+        return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter);
     }
 
     @Override
     public List<String> findServicesByApplication(String application) {
         List<String> ret = new ArrayList<String>();
 
-        ConcurrentMap<String, Map<String, URL>> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY);
+        ConcurrentMap<String, Map<String, URL>> providerUrls = getInterfaceRegistryCache().get(Constants.PROVIDERS_CATEGORY);
         if (providerUrls == null || application == null || application.length() == 0) {
             return ret;
         }
@@ -349,59 +237,6 @@ public class ProviderServiceImpl extends AbstractService implements ProviderServ
     }
 
     @Override
-    public List<String> findMethodsByService(String service) {
-        List<String> ret = new ArrayList<String>();
-
-        ConcurrentMap<String, Map<String, URL>> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY);
-        if (providerUrls == null || service == null || service.length() == 0){
-            return ret;
-        }
-
-        Map<String, URL> providers = providerUrls.get(service);
-        if (null == providers || providers.isEmpty()) {
-            return ret;
-        }
-
-        Entry<String, URL> p = providers.entrySet().iterator().next();
-        String value = p.getValue().getParameter("methods");
-        if (value == null || value.length() == 0) {
-            return ret;
-        }
-        String[] methods = value.split(ParseUtils.METHOD_SPLIT);
-        if (methods == null || methods.length == 0) {
-            return ret;
-        }
-
-        for (String m : methods) {
-            ret.add(m);
-        }
-        return ret;
-    }
-
-    private URL findProviderUrl(String id) {
-        return findProvider(id).toUrl();
-    }
-
-    @Override
-    public Provider findByServiceAndAddress(String service, String address) {
-        return SyncUtils.url2Provider(findProviderUrl(service, address));
-    }
-
-    private Pair<String, URL> findProviderUrl(String service, String address) {
-        Map<String, String> filter = new HashMap<String, String>();
-        filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY);
-        filter.put(SyncUtils.ADDRESS_FILTER_KEY, address);
-
-        Map<String, URL> ret = SyncUtils.filterFromCategory(getRegistryCache(), filter);
-        if (ret.isEmpty()) {
-            return null;
-        } else {
-            String key = ret.entrySet().iterator().next().getKey();
-            return new Pair<String, URL>(key, ret.get(key));
-        }
-    }
-
-    @Override
     public Set<ServiceDTO> getServiceDTOS(String pattern, String filter, String env) {
         List<Provider> providers = new ArrayList<>();
         if (!filter.contains(Constants.ANY_VALUE) && !filter.contains(Constants.INTERROGATION_POINT)) {
@@ -420,15 +255,14 @@ public class ProviderServiceImpl extends AbstractService implements ProviderServ
                 candidates = findServices();
             } else if (Constants.APPLICATION.equals(pattern)) {
                 candidates = findApplications();
-            }
-            else if (Constants.IP.equals(pattern)) {
+            } else if (Constants.IP.equals(pattern)) {
                 candidates = findAddresses().stream().collect(Collectors.toSet());
             }
             // replace dot symbol and asterisk symbol to java-based regex pattern
             filter = filter.toLowerCase().replace(Constants.PUNCTUATION_POINT, Constants.PUNCTUATION_SEPARATOR_POINT);
             // filter start with [* 、? 、+] will triggering PatternSyntaxException
             if (filter.startsWith(Constants.ANY_VALUE)
-                || filter.startsWith(Constants.INTERROGATION_POINT) || filter.startsWith(Constants.PLUS_SIGNS)) {
+                    || filter.startsWith(Constants.INTERROGATION_POINT) || filter.startsWith(Constants.PLUS_SIGNS)) {
                 filter = Constants.PUNCTUATION_POINT + filter;
             }
             // search with no case insensitive
@@ -438,19 +272,16 @@ public class ProviderServiceImpl extends AbstractService implements ProviderServ
                 if (matcher.matches() || matcher.lookingAt()) {
                     if (Constants.SERVICE.equals(pattern)) {
                         providers.addAll(findByService(candidate));
-                    }
-                    else if (Constants.IP.equals(pattern)) {
+                    } else if (Constants.IP.equals(pattern)) {
                         providers.addAll(findByAddress(candidate));
-                    }
-                    else {
+                    } else {
                         providers.addAll(findByApplication(candidate));
                     }
                 }
             }
         }
 
-        Set<ServiceDTO> result = convertProviders2DTO(providers);
-        return result;
+        return convertProviders2DTO(providers);
     }
 
     /**
@@ -472,6 +303,7 @@ public class ProviderServiceImpl extends AbstractService implements ProviderServ
             s.setService(interfaze);
             s.setGroup(group);
             s.setVersion(version);
+            s.setRegistrySource(provider.getRegistrySource());
             result.add(s);
         }
         return result;
diff --git a/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.mapping.ServiceMapping b/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.mapping.ServiceMapping
new file mode 100644
index 0000000..83709e7
--- /dev/null
+++ b/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.mapping.ServiceMapping
@@ -0,0 +1 @@
+zookeeper=org.apache.dubbo.admin.registry.mapping.impl.ZookeeperServiceMapping
\ No newline at end of file
diff --git a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java
index 9448a93..0626da2 100644
--- a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java
+++ b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java
@@ -73,7 +73,7 @@ public abstract class AbstractSpringIntegrationTest {
             TestPropertySourceUtils.addInlinedPropertiesToEnvironment(configurableApplicationContext,
                     "admin.registry.address=zookeeper://" + zkServer.getConnectString());
             TestPropertySourceUtils.addInlinedPropertiesToEnvironment(configurableApplicationContext,
-                    "admin.metadata.address=zookeeper://" + zkServer.getConnectString());
+                    "admin.metadata-report.address=zookeeper://" + zkServer.getConnectString());
             TestPropertySourceUtils.addInlinedPropertiesToEnvironment(configurableApplicationContext,
                     "admin.config-center=zookeeper://" + zkServer.getConnectString());
         }
diff --git a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/controller/MeshRouteControllerTest.java b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/controller/MeshRouteControllerTest.java
index 9cf6146..8cfdd9f 100644
--- a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/controller/MeshRouteControllerTest.java
+++ b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/controller/MeshRouteControllerTest.java
@@ -20,11 +20,13 @@ package org.apache.dubbo.admin.controller;
 import org.apache.dubbo.admin.AbstractSpringIntegrationTest;
 import org.apache.dubbo.admin.common.util.Constants;
 import org.apache.dubbo.admin.model.dto.MeshRouteDTO;
+import org.apache.dubbo.admin.service.ProviderService;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.After;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
@@ -40,6 +42,7 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
 
 
 public class MeshRouteControllerTest extends AbstractSpringIntegrationTest {
@@ -49,6 +52,9 @@ public class MeshRouteControllerTest extends AbstractSpringIntegrationTest {
     @Autowired
     private ObjectMapper objectMapper;
 
+    @MockBean
+    private ProviderService providerService;
+
     @After
     public void tearDown() throws Exception {
         if (zkClient.checkExists().forPath("/dubbo") != null) {
@@ -77,6 +83,7 @@ public class MeshRouteControllerTest extends AbstractSpringIntegrationTest {
         // valid mesh rule
         meshRoute.setApplication(application);
         meshRoute.setMeshRule(getFileContent("/MeshRoute.yml"));
+        when(providerService.findVersionInApplication(application)).thenReturn("3.0.0");
         response = restTemplate.postForEntity(url("/api/{env}/rules/route/mesh"), meshRoute, String.class, env);
         assertEquals(HttpStatus.CREATED, response.getStatusCode());
         assertTrue(Boolean.valueOf(response.getBody()));
diff --git a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/service/RegistryServerSyncTest.java b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/service/RegistryServerSyncTest.java
index a8ecc7c..1be485d 100644
--- a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/service/RegistryServerSyncTest.java
+++ b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/service/RegistryServerSyncTest.java
@@ -18,16 +18,22 @@
 package org.apache.dubbo.admin.service;
 
 import org.apache.dubbo.admin.common.util.Constants;
+import org.apache.dubbo.admin.service.impl.InterfaceRegistryCache;
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.url.component.URLParam;
 import org.apache.dubbo.registry.Registry;
+
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentMap;
 
@@ -46,9 +52,11 @@ public class RegistryServerSyncTest {
     @InjectMocks
     private RegistryServerSync registryServerSync;
 
-    @Test
-    public void testGetRegistryCache() {
-        registryServerSync.getRegistryCache();
+    private InterfaceRegistryCache interfaceRegistryCache = new InterfaceRegistryCache();
+
+    @Before
+    public void setUp() throws Exception {
+        ReflectionTestUtils.setField(registryServerSync, "interfaceRegistryCache", interfaceRegistryCache);
     }
 
     @Test
@@ -71,27 +79,32 @@ public class RegistryServerSyncTest {
         // when url.getProtocol is not empty protocol
         URL consumerUrl = mock(URL.class);
         URL providerUrl = mock(URL.class);
-
-        when(consumerUrl.getParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY)).thenReturn(Constants.CONSUMER_PROTOCOL);
+        HashMap<String, String> consumerUrlParam = new HashMap<>();
+        consumerUrlParam.put(Constants.CATEGORY_KEY,Constants.CONSUMER_PROTOCOL);
+        HashMap<String, String> providerUrlParam = new HashMap<>();
+        providerUrlParam.put(Constants.CATEGORY_KEY,Constants.PROVIDER_PROTOCOL);
+        when(consumerUrl.getUrlParam()).thenReturn(URLParam.parse(consumerUrlParam));
         when(consumerUrl.getServiceInterface()).thenReturn("org.apache.dubbo.consumer");
-        when(consumerUrl.getServiceKey()).thenReturn("org.apache.dubbo.consumer");
         when(consumerUrl.toFullString()).thenReturn("consumer://192.168.1.10/sunbufu.dubbo.consumer?application=dubbo&category=consumer&check=false&dubbo=2.7.0&interface=sunbufu.dubbo.consumer&loadbalabce=roundrobin&mehods=sayHi,sayGoodBye&owner=sunbufu&pid=18&protocol=dubbo&side=consumer&timeout=3000&timestamp=1548127407769");
+        when(providerUrl.getUrlParam()).thenReturn(URLParam.parse(providerUrlParam));
         when(providerUrl.getParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY)).thenReturn(Constants.PROVIDER_PROTOCOL);
         when(providerUrl.getServiceInterface()).thenReturn("org.apache.dubbo.provider");
-        when(providerUrl.getServiceKey()).thenReturn("org.apache.dubbo.provider");
         when(providerUrl.toFullString()).thenReturn("consumer://192.168.1.10/sunbufu.dubbo.consumer?application=dubbo&category=consumer&check=false&dubbo=2.6.2&interface=sunbufu.dubbo.consumer&loadbalabce=roundrobin&mehods=sayHi,sayGoodBye&owner=sunbufu&pid=18&protocol=dubbo&side=consumer&timeout=3000&timestamp=1548127407769");
 
         registryServerSync.notify(Arrays.asList(consumerUrl, consumerUrl, providerUrl));
 
-        ConcurrentMap<String, Map<String, URL>> consumerMap = registryServerSync.getRegistryCache().get(Constants.CONSUMER_PROTOCOL);
+        ConcurrentMap<String, Map<String, URL>> consumerMap = interfaceRegistryCache.get(Constants.CONSUMER_PROTOCOL);
         assertTrue(consumerMap.keySet().contains("org.apache.dubbo.consumer"));
-        ConcurrentMap<String, Map<String, URL>> providerMap = registryServerSync.getRegistryCache().get(Constants.PROVIDER_PROTOCOL);
+        ConcurrentMap<String, Map<String, URL>> providerMap = interfaceRegistryCache.get(Constants.PROVIDER_PROTOCOL);
         assertTrue(providerMap.keySet().contains("org.apache.dubbo.provider"));
 
         // when url.getProtocol is empty protocol
         when(consumerUrl.getProtocol()).thenReturn(Constants.EMPTY_PROTOCOL);
-        when(consumerUrl.getParameter(Constants.GROUP_KEY)).thenReturn("dubbo");
-        when(consumerUrl.getParameter(Constants.VERSION_KEY)).thenReturn("2.7.0");
+        consumerUrlParam = new HashMap<>();
+        consumerUrlParam.put(Constants.CATEGORY_KEY,Constants.CONSUMER_PROTOCOL);
+        consumerUrlParam.put(Constants.GROUP_KEY,"dubbo");
+        consumerUrlParam.put(Constants.VERSION_KEY,"2.7.0");
+        when(consumerUrl.getUrlParam()).thenReturn(URLParam.parse(consumerUrlParam));
         registryServerSync.notify(Collections.singletonList(consumerUrl));
 
         assertTrue(!consumerMap.keySet().contains("org.apache.dubbo.consumer"));
diff --git a/dubbo-admin-ui/src/components/ServiceDetail.vue b/dubbo-admin-ui/src/components/ServiceDetail.vue
index 366b5ff..79fa779 100644
--- a/dubbo-admin-ui/src/components/ServiceDetail.vue
+++ b/dubbo-admin-ui/src/components/ServiceDetail.vue
@@ -54,6 +54,7 @@
               <template slot="items" slot-scope="props">
                 <td>{{getIp(props.item.address)}}</td>
                 <td>{{getPort(props.item.address)}}</td>
+                <td>{{props.item.registrySource}}</td>
                 <td></td>
                 <td></td>
                 <td>{{props.item.weight}}</td>
@@ -167,6 +168,10 @@
               value: 'port'
             },
             {
+              text: this.$t('registrySource'),
+              value: 'registrySource'
+            },
+            {
               text: this.$t('timeout'),
               value: 'timeout'
             },
@@ -204,7 +209,16 @@
         this.$axios.get('/service/' + service)
             .then(response => {
               this.providerDetails = response.data.providers
+              const instanceRegistry = this.$t('instanceRegistry')
+              const interfaceRegistry = this.$t('interfaceRegistry')
               for (let i = 0; i < this.providerDetails.length; i++) {
+                if (this.providerDetails[i].registrySource === 'INSTANCE') {
+                  this.providerDetails[i].registrySource = instanceRegistry
+                }
+                if (this.providerDetails[i].registrySource === 'INTERFACE') {
+                  this.providerDetails[i].registrySource = interfaceRegistry
+                }
+                console.log(this.providerDetails[i])
                 this.$set(this.providerDetails[i], 'hint', 'url')
               }
               this.consumerDetails = response.data.consumers
diff --git a/dubbo-admin-ui/src/components/ServiceSearch.vue b/dubbo-admin-ui/src/components/ServiceSearch.vue
index c7fa2c8..c5ce4fb 100644
--- a/dubbo-admin-ui/src/components/ServiceSearch.vue
+++ b/dubbo-admin-ui/src/components/ServiceSearch.vue
@@ -81,11 +81,12 @@
                 <td>{{props.item.group}}</td>
                 <td>{{props.item.version}}</td>
                 <td>{{props.item.appName}}</td>
+                <td>{{props.item.registrySource}}</td>
                 <td class="text-xs-center px-0" nowrap>
                   <v-btn
                     class="tiny"
                     color='success'
-                    :href='getHref(props.item.service, props.item.appName, props.item.group, props.item.version)'
+                    :href='getHref(props.item.service, props.item.appName, props.item.group, props.item.version,props.item.registrySource)'
                   >
                    {{ $t('detail') }}
                   </v-btn>
@@ -112,7 +113,7 @@
                       <v-list-tile
                         v-for="(item, i) in options"
                         :key="i"
-                        :href='governanceHref(item.value, props.item.service, props.item.appName, props.item.group, props.item.version)'
+                        :href='governanceHref(item.value, props.item.service, props.item.appName, props.item.group, props.item.version,props.item.registrySource)'
                       >
                         <v-list-tile-title class="small-list">{{ $t(item.title) }}</v-list-tile-title>
                       </v-list-tile>
@@ -198,7 +199,17 @@ export default {
       if (!this.resultPage || !this.resultPage.content) {
         return []
       }
-      return this.resultPage.content
+      const instanceRegistry = this.$t('instanceRegistry')
+      const interfaceRegistry = this.$t('interfaceRegistry')
+      return this.resultPage.content.filter(function (item) {
+        if (item.registrySource === 'INSTANCE') {
+          item.registrySource = instanceRegistry
+        }
+        if (item.registrySource === 'INTERFACE') {
+          item.registrySource = interfaceRegistry
+        }
+        return item
+      })
     }
   },
   watch: {
@@ -244,6 +255,11 @@ export default {
           align: 'left'
         },
         {
+          text: this.$t('registrySource'),
+          value: 'registry',
+          align: 'left'
+        },
+        {
           text: this.$t('operation'),
           value: 'operation',
           sortable: false,
diff --git a/dubbo-admin-ui/src/components/governance/MeshRule.vue b/dubbo-admin-ui/src/components/governance/MeshRule.vue
index f29b5a4..d55fd5b 100644
--- a/dubbo-admin-ui/src/components/governance/MeshRule.vue
+++ b/dubbo-admin-ui/src/components/governance/MeshRule.vue
@@ -403,7 +403,7 @@
     },
     mounted: function () {
       this.setHeaders()
-      this.$store.dispatch('loadAppItems')
+      this.$store.dispatch('loadInstanceAppItems')
       this.ruleText = this.template
       let query = this.$route.query
       let filter = null
diff --git a/dubbo-admin-ui/src/lang/en.js b/dubbo-admin-ui/src/lang/en.js
index c239380..f047218 100644
--- a/dubbo-admin-ui/src/lang/en.js
+++ b/dubbo-admin-ui/src/lang/en.js
@@ -46,6 +46,9 @@ export default {
   serialization: 'serialization',
   appName: 'Application Name',
   serviceName: 'Service Name',
+  registrySource: 'Registry Source',
+  instanceRegistry: 'Instance Registry',
+  interfaceRegistry: 'Interface Registry',
   operation: 'Operation',
   searchResult: 'Search Result',
   search: 'Search',
diff --git a/dubbo-admin-ui/src/lang/zh.js b/dubbo-admin-ui/src/lang/zh.js
index 1116702..084a129 100644
--- a/dubbo-admin-ui/src/lang/zh.js
+++ b/dubbo-admin-ui/src/lang/zh.js
@@ -46,6 +46,9 @@ export default {
   serialization: '序列化',
   appName: '应用名',
   serviceName: '服务名',
+  registrySource: '注册来源',
+  instanceRegistry: '应用级',
+  interfaceRegistry: '接口级',
   operation: '操作',
   searchResult: '查询结果',
   search: '搜索',
diff --git a/dubbo-admin-ui/src/store/index.js b/dubbo-admin-ui/src/store/index.js
index d553ce8..57484ba 100644
--- a/dubbo-admin-ui/src/store/index.js
+++ b/dubbo-admin-ui/src/store/index.js
@@ -71,6 +71,18 @@ export const store = new Vuex.Store({
         })
     },
     /**
+     * Load instance registry application items from server, put results into storage.
+     */
+    loadInstanceAppItems ({commit}) {
+      Vue.prototype.$axios.get('/applications/instance')
+        .then(response => {
+          if (response.status === 200) {
+            const appItems = response.data
+            commit('setAppItems', appItems)
+          }
+        })
+    },
+    /**
      * Load application items from consumer, put results into storage.
      */
     loadConsumerItems ({commit}) {
diff --git a/pom.xml b/pom.xml
index f832147..736bc6f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,8 +56,8 @@
 		<revision>0.3.0-SNAPSHOT</revision>
 		<main.basedir>${project.basedir}</main.basedir>
 		<commons-lang3-version>3.7</commons-lang3-version>
-		<dubbo-version>2.7.12</dubbo-version>
-		<curator-version>2.12.0</curator-version>
+		<dubbo-version>3.0.2</dubbo-version>
+		<curator-version>4.0.1</curator-version>
 		<curator-test-version>4.1.0</curator-test-version>
 		<fastjson-version>1.2.67</fastjson-version>
 		<springfox-swagger-version>2.9.2</springfox-swagger-version>
@@ -126,12 +126,6 @@
 			</dependency>
 
 			<dependency>
-				<groupId>org.apache.dubbo</groupId>
-				<artifactId>dubbo-serialization-kryo</artifactId>
-				<version>${dubbo-version}</version>
-			</dependency>
-
-			<dependency>
 				<groupId>org.apache.curator</groupId>
 				<artifactId>curator-framework</artifactId>
 				<version>${curator-version}</version>
@@ -154,6 +148,19 @@
 					</exclusion>
 				</exclusions>
 			</dependency>
+
+			<dependency>
+				<groupId>org.apache.curator</groupId>
+				<artifactId>curator-x-discovery</artifactId>
+				<version>${curator-version}</version>
+				<exclusions>
+					<exclusion>
+						<groupId>org.apache.zookeeper</groupId>
+						<artifactId>zookeeper</artifactId>
+					</exclusion>
+				</exclusions>
+			</dependency>
+
 			<dependency>
 				<groupId>com.alibaba</groupId>
 				<artifactId>fastjson</artifactId>