Merge branch 'metadata' into service-test
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/exception/ConfigurationException.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/exception/ConfigurationException.java
new file mode 100644
index 0000000..89fbb0b
--- /dev/null
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/exception/ConfigurationException.java
@@ -0,0 +1,25 @@
+/*
+ * 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.common.exception;
+
+public class ConfigurationException extends RuntimeException{
+
+    public ConfigurationException(String message) {
+        super(message);
+    }
+}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/OverrideUtils.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/OverrideUtils.java
index 3c003e1..dccf1b9 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/OverrideUtils.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/OverrideUtils.java
@@ -19,7 +19,6 @@
 import org.apache.dubbo.admin.model.domain.*;
 import org.apache.dubbo.admin.model.domain.Override;
 import org.apache.dubbo.admin.model.dto.BalancingDTO;
-import org.apache.dubbo.admin.model.dto.Config;
 import org.apache.dubbo.admin.model.dto.DynamicConfigDTO;
 import org.apache.dubbo.admin.model.dto.WeightDTO;
 import org.apache.dubbo.admin.model.store.OverrideConfig;
@@ -72,19 +71,24 @@
 
     public static DynamicConfigDTO createFromOverride(OverrideDTO overrideDTO) {
         DynamicConfigDTO dynamicConfigDTO = new DynamicConfigDTO();
-        dynamicConfigDTO.setApiVersion(overrideDTO.getApiVersion());
+        dynamicConfigDTO.setConfigVersion(overrideDTO.getConfigVersion());
         List<OverrideConfig> configs = new ArrayList<>();
         for (OverrideConfig overrideConfig : overrideDTO.getConfigs()) {
             if (overrideConfig.getType() == null) {
                 configs.add(overrideConfig);
             }
         }
+        if (configs.size() == 0) {
+            return null;
+        }
         dynamicConfigDTO.setConfigs(configs);
         if (overrideDTO.getScope().equals(Constants.APPLICATION)) {
             dynamicConfigDTO.setApplication(overrideDTO.getKey());
         } else {
             dynamicConfigDTO.setService(overrideDTO.getKey());
         }
+        dynamicConfigDTO.setRuntime(overrideDTO.isRuntime());
+        dynamicConfigDTO.setEnabled(overrideDTO.isEnabled());
         return dynamicConfigDTO;
     }
     public static OverrideDTO createFromDynamicConfig(DynamicConfigDTO dynamicConfigDTO) {
@@ -96,7 +100,7 @@
             overrideDTO.setScope(Constants.SERVICE);
             overrideDTO.setKey(dynamicConfigDTO.getService());
         }
-        overrideDTO.setApiVersion(dynamicConfigDTO.getApiVersion());
+        overrideDTO.setConfigVersion(dynamicConfigDTO.getConfigVersion());
         overrideDTO.setConfigs(dynamicConfigDTO.getConfigs());
         return overrideDTO;
     }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/RouteRule.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/RouteRule.java
index c583252..6ff7b61 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/RouteRule.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/RouteRule.java
@@ -205,7 +205,6 @@
             }
         }
         existRule.setConditions(conditionRoute.getConditions());
-        existRule.setDynamic(conditionRoute.isDynamic());
         existRule.setEnabled(conditionRoute.isEnabled());
         existRule.setForce(conditionRoute.isForce());
         existRule.setRuntime(conditionRoute.isRuntime());
@@ -312,7 +311,6 @@
         conditionRouteDTO.setEnabled(routingRuleDTO.isEnabled());
         conditionRouteDTO.setForce(routingRuleDTO.isForce());
         conditionRouteDTO.setRuntime(routingRuleDTO.isRuntime());
-        conditionRouteDTO.setDynamic(routingRuleDTO.isDynamic());
         return conditionRouteDTO;
     }
 
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
index 6f6f13f..31af96f 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
@@ -18,9 +18,12 @@
 package org.apache.dubbo.admin.config;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.admin.common.exception.ConfigurationException;
+import org.apache.dubbo.admin.common.exception.ParamValidationException;
 import org.apache.dubbo.admin.common.util.Constants;
 import org.apache.dubbo.admin.data.config.GovernanceConfiguration;
 import org.apache.dubbo.admin.data.metadata.MetaDataCollector;
+import org.apache.dubbo.admin.data.metadata.impl.NoOpMetadataCollector;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.registry.Registry;
@@ -59,7 +62,8 @@
      */
     @Bean("governanceConfiguration")
     GovernanceConfiguration getDynamicConfiguration() {
-        GovernanceConfiguration dynamicConfiguration = ExtensionLoader.getExtensionLoader(GovernanceConfiguration.class).getDefaultExtension();
+        GovernanceConfiguration dynamicConfiguration = null;
+
         if (StringUtils.isNotEmpty(configCenter)) {
             configCenterUrl = formUrl(configCenter, group);
             dynamicConfiguration = ExtensionLoader.getExtensionLoader(GovernanceConfiguration.class).getExtension(configCenterUrl.getProtocol());
@@ -77,6 +81,17 @@
                 });
             }
         }
+        if (dynamicConfiguration == null) {
+            if (StringUtils.isNotEmpty(registryAddress)) {
+                registryUrl = formUrl(registryAddress, group);
+                dynamicConfiguration = ExtensionLoader.getExtensionLoader(GovernanceConfiguration.class).getExtension(registryUrl.getProtocol());
+                dynamicConfiguration.setUrl(registryUrl);
+                dynamicConfiguration.init();
+            } else {
+                throw new ConfigurationException("Either configcenter or registry address is needed");
+                //throw exception
+            }
+        }
         return dynamicConfiguration;
     }
 
@@ -88,6 +103,9 @@
     Registry getRegistry() {
         Registry registry = null;
         if (registryUrl == null) {
+            if (StringUtils.isNotEmpty(registryAddress)) {
+                throw new ConfigurationException("Either configcenter or registry address is needed");
+            }
             registryUrl = formUrl(registryAddress, group);
         }
         RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
@@ -101,7 +119,7 @@
     @Bean
     @DependsOn("governanceConfiguration")
     MetaDataCollector getMetadataCollector() {
-        MetaDataCollector metaDataCollector = ExtensionLoader.getExtensionLoader(MetaDataCollector.class).getDefaultExtension();
+        MetaDataCollector metaDataCollector = new NoOpMetadataCollector();
         if (metadataUrl != null) {
             metaDataCollector = ExtensionLoader.getExtensionLoader(MetaDataCollector.class).getExtension(metadataUrl.getProtocol());
             metaDataCollector.setUrl(metadataUrl);
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/AccessesController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/AccessesController.java
index 25ca33f..e815669 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/AccessesController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/AccessesController.java
@@ -45,10 +45,10 @@
     }
 
     @RequestMapping(method = RequestMethod.GET)
-    public List<AccessDTO> searchAccess(@RequestParam(required = false) String serviceName,
+    public List<AccessDTO> searchAccess(@RequestParam(required = false) String service,
                                         @RequestParam(required = false) String application,
                                         @PathVariable String env) throws ParseException {
-        if (StringUtils.isBlank(serviceName) && StringUtils.isBlank(application)) {
+        if (StringUtils.isBlank(service) && StringUtils.isBlank(application)) {
             throw new ParamValidationException("Either service or application is required");
         }
         List<AccessDTO> accessDTOS = new ArrayList<>();
@@ -56,7 +56,7 @@
         if (StringUtils.isNotBlank(application)) {
             accessDTO = routeService.findAccess(application);
         } else {
-            accessDTO = routeService.findAccess(serviceName);
+            accessDTO = routeService.findAccess(service);
         }
         if (accessDTO != null) {
             accessDTO.setEnabled(true);
@@ -67,12 +67,14 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.GET)
     public AccessDTO detailAccess(@PathVariable String id, @PathVariable String env) throws ParseException {
+        id = id.replace("*", "/");
         AccessDTO accessDTO = routeService.findAccess(id);
         return accessDTO;
     }
 
     @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
     public void deleteAccess(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         routeService.deleteAccess(id);
     }
 
@@ -91,6 +93,7 @@
     @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
     public void updateAccess(@PathVariable String id, @RequestBody AccessDTO accessDTO, @PathVariable String env) {
 
+        id = id.replace("*", "/");
         ConditionRouteDTO route = routeService.findConditionRoute(id);
         if (Objects.isNull(route)) {
             throw new ResourceNotFoundException("Unknown ID!");
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ConditionRoutesController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ConditionRoutesController.java
index 5038ed0..a5849e0 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ConditionRoutesController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ConditionRoutesController.java
@@ -61,6 +61,7 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
     public boolean updateRule(@PathVariable String id, @RequestBody ConditionRouteDTO newConditionRoute, @PathVariable String env) {
+        id = id.replace("*", "/");
         ConditionRouteDTO oldConditionRoute = routeService.findConditionRoute(id);
         if (oldConditionRoute == null) {
             throw new ResourceNotFoundException("can not find route rule for: " + id);
@@ -71,14 +72,14 @@
 
     @RequestMapping(method = RequestMethod.GET)
     public List<ConditionRouteDTO> searchRoutes(@RequestParam(required = false) String application,
-                                                @RequestParam(required = false) String serviceName, @PathVariable String env) {
+                                                @RequestParam(required = false) String service, @PathVariable String env) {
         ConditionRouteDTO conditionRoute = null;
         List<ConditionRouteDTO> result = new ArrayList<>();
         if (StringUtils.isNotEmpty(application)) {
             conditionRoute = routeService.findConditionRoute(application);
         }
-        if (StringUtils.isNotEmpty(serviceName)) {
-            conditionRoute = routeService.findConditionRoute(serviceName);
+        if (StringUtils.isNotEmpty(service)) {
+            conditionRoute = routeService.findConditionRoute(service);
         }
         if (conditionRoute != null && conditionRoute.getConditions() != null) {
             result.add(conditionRoute);
@@ -88,6 +89,7 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.GET)
     public ConditionRouteDTO detailRoute(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         ConditionRouteDTO conditionRoute = routeService.findConditionRoute(id);
         if (conditionRoute == null || conditionRoute.getConditions() == null) {
             throw new ResourceNotFoundException("Unknown ID!");
@@ -97,18 +99,21 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
     public boolean deleteRoute(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         routeService.deleteConditionRoute(id);
         return true;
     }
 
     @RequestMapping(value = "/enable/{id}", method = RequestMethod.PUT)
     public boolean enableRoute(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         routeService.enableConditionRoute(id);
         return true;
     }
 
     @RequestMapping(value = "/disable/{id}", method = RequestMethod.PUT)
     public boolean disableRoute(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         routeService.disableConditionRoute(id);
         return true;
     }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/LoadBalanceController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/LoadBalanceController.java
index bc130e5..146b604 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/LoadBalanceController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/LoadBalanceController.java
@@ -65,6 +65,7 @@
         if (id == null) {
             throw new ParamValidationException("Unknown ID!");
         }
+        id = id.replace("*", "/");
         BalancingDTO balancing = overrideService.findBalance(id);
         if (balancing == null) {
             throw new ResourceNotFoundException("Unknown ID!");
@@ -85,18 +86,18 @@
     }
 
     @RequestMapping(method = RequestMethod.GET)
-    public List<BalancingDTO> searchLoadbalances(@RequestParam(required = false) String serviceName,
+    public List<BalancingDTO> searchLoadbalances(@RequestParam(required = false) String service,
                                                  @RequestParam(required = false) String application,
                                                  @PathVariable String env) {
 
-        if (StringUtils.isBlank(serviceName) && StringUtils.isBlank(application)) {
+        if (StringUtils.isBlank(service) && StringUtils.isBlank(application)) {
             throw new ParamValidationException("Either service or application is required");
         }
         BalancingDTO balancingDTO;
         if (StringUtils.isNotBlank(application)) {
             balancingDTO = overrideService.findBalance(application);
         } else {
-            balancingDTO = overrideService.findBalance(serviceName);
+            balancingDTO = overrideService.findBalance(service);
         }
         List<BalancingDTO> balancingDTOS = new ArrayList<>();
         if (balancingDTO != null) {
@@ -107,6 +108,7 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.GET)
     public BalancingDTO detailLoadBalance(@PathVariable String id, @PathVariable String env) throws ParamValidationException {
+        id = id.replace("*", "/");
         BalancingDTO balancingDTO = overrideService.findBalance(id);
         if (balancingDTO == null) {
             throw new ResourceNotFoundException("Unknown ID!");
@@ -122,6 +124,7 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
     public boolean deleteLoadBalance(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         if (id == null) {
             throw new IllegalArgumentException("Argument of id is null!");
         }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/OverridesController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/OverridesController.java
index b94d659..96cb8dd 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/OverridesController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/OverridesController.java
@@ -61,6 +61,7 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
     public boolean updateOverride(@PathVariable String id, @RequestBody DynamicConfigDTO overrideDTO, @PathVariable String env) {
+        id = id.replace("*", "/");
         DynamicConfigDTO old = overrideService.findOverride(id);
         if (old == null) {
             throw new ResourceNotFoundException("Unknown ID!");
@@ -70,13 +71,13 @@
     }
 
     @RequestMapping(method = RequestMethod.GET)
-    public List<DynamicConfigDTO> searchOverride(@RequestParam(required = false) String serviceName,
+    public List<DynamicConfigDTO> searchOverride(@RequestParam(required = false) String service,
                                                  @RequestParam(required = false) String application,
                                                  @PathVariable String env) {
         DynamicConfigDTO override = null;
         List<DynamicConfigDTO> result = new ArrayList<>();
-        if (StringUtils.isNotEmpty(serviceName)) {
-            override = overrideService.findOverride(serviceName);
+        if (StringUtils.isNotEmpty(service)) {
+            override = overrideService.findOverride(service);
         } else if(StringUtils.isNotEmpty(application)){
             override = overrideService.findOverride(application);
         }
@@ -88,6 +89,7 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.GET)
     public DynamicConfigDTO detailOverride(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         DynamicConfigDTO override = overrideService.findOverride(id);
         if (override == null) {
             throw new ResourceNotFoundException("Unknown ID!");
@@ -98,6 +100,7 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
     public boolean deleteOverride(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         overrideService.deleteOverride(id);
         return true;
     }
@@ -105,12 +108,14 @@
     @RequestMapping(value = "/enable/{id}", method = RequestMethod.PUT)
     public boolean enableRoute(@PathVariable String id, @PathVariable String env) {
 
+        id = id.replace("*", "/");
         overrideService.enableOverride(id);
         return true;
     }
 
     @RequestMapping(value = "/disable/{id}", method = RequestMethod.PUT)
     public boolean disableRoute(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
 
         overrideService.disableOverride(id);
         return true;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
index d29fef1..d080f2e 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
@@ -28,7 +28,7 @@
 import org.apache.dubbo.common.Constants;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
-import org.apache.dubbo.metadata.identifier.ProviderMetadataIdentifier;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
@@ -58,14 +58,14 @@
         if (!filter.contains("*") && !filter.contains("?")) {
             if (pattern.equals("ip")) {
                 providers = providerService.findByAddress(filter);
-            } else if (pattern.equals("serviceName")) {
+            } else if (pattern.equals("service")) {
                 providers = providerService.findByService(filter);
             } else if (pattern.equals("application")) {
                 providers = providerService.findByApplication(filter);
             }
         } else {
             List<String> candidates = Collections.emptyList();
-            if (pattern.equals("serviceName")) {
+            if (pattern.equals("service")) {
                candidates = providerService.findServices();
             } else if (pattern.equals("application")) {
                 candidates = providerService.findApplications();
@@ -78,7 +78,7 @@
             for (String candidate : candidates) {
                 Matcher matcher = regex.matcher(candidate);
                 if (matcher.matches() || matcher.lookingAt()) {
-                    if (pattern.equals("serviceName")) {
+                    if (pattern.equals("service")) {
                         providers.addAll(providerService.findByService(candidate));
                     } else {
                         providers.addAll(providerService.findByApplication(candidate));
@@ -112,16 +112,22 @@
         List<Consumer> consumers = consumerService.findByService(service);
 
         Map<String, String> info = ConvertUtil.serviceName2Map(service);
-        ProviderMetadataIdentifier p = new ProviderMetadataIdentifier(info.get(Constants.INTERFACE_KEY),
+        String application = null;
+        if (providers != null && providers.size() > 0) {
+            application = providers.get(0).getApplication();
+        }
+        MetadataIdentifier identifier = new MetadataIdentifier(info.get(Constants.INTERFACE_KEY),
                                                                       info.get(Constants.VERSION_KEY),
-                                                                      info.get(Constants.GROUP_KEY));
-        String metadata = providerService.getProviderMetaData(p);
-        Gson gson = new Gson();
-        FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class);
+                                                                      info.get(Constants.GROUP_KEY), Constants.PROVIDER_SIDE, application);
+        String metadata = providerService.getProviderMetaData(identifier);
         ServiceDetailDTO serviceDetailDTO = new ServiceDetailDTO();
-        serviceDetailDTO.setConsumers(consumers);
-        serviceDetailDTO.setProviders(providers);
-        serviceDetailDTO.setMetadata(serviceDefinition);
+        if (metadata != null) {
+            Gson gson = new Gson();
+            FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class);
+            serviceDetailDTO.setConsumers(consumers);
+            serviceDetailDTO.setProviders(providers);
+            serviceDetailDTO.setMetadata(serviceDefinition);
+        }
         return serviceDetailDTO;
     }
 }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/TagRoutesController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/TagRoutesController.java
index 37d2e69..25522eb 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/TagRoutesController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/TagRoutesController.java
@@ -62,6 +62,7 @@
     @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
     public boolean updateRule(@PathVariable String id, @RequestBody TagRouteDTO routeDTO, @PathVariable String env) {
 
+        id = id.replace("*", "/");
         String app = routeDTO.getApplication();
         if (providerService.findVersionInApplication(app).equals("2.6")) {
             throw new VersionValidationException("dubbo 2.6 does not support tag route");
@@ -76,10 +77,17 @@
 
     @RequestMapping(method = RequestMethod.GET)
     public List<TagRouteDTO> searchRoutes(@RequestParam String application, @PathVariable String env) {
-        if (providerService.findVersionInApplication(application).equals("2.6")) {
-            throw new VersionValidationException("dubbo 2.6 does not support tag route");
-        }
         List<TagRouteDTO> result = new ArrayList<>();
+        String version = "2.6";
+        try {
+            version = providerService.findVersionInApplication(application);
+        } catch (ParamValidationException e) {
+            //ignore
+        }
+        if (version.equals("2.6")) {
+            return result;
+        }
+
         TagRouteDTO tagRoute = null;
         if (StringUtils.isNotEmpty(application)) {
             tagRoute = routeService.findTagRoute(application);
@@ -93,6 +101,7 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.GET)
     public TagRouteDTO detailRoute(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         TagRouteDTO tagRoute = routeService.findTagRoute(id);
         if (tagRoute == null) {
             throw new ResourceNotFoundException("Unknown ID!");
@@ -103,18 +112,21 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
     public boolean deleteRoute(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         routeService.deleteTagRoute(id);
         return true;
     }
 
     @RequestMapping(value = "/enable/{id}", method = RequestMethod.PUT)
     public boolean enableRoute(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         routeService.enableTagRoute(id);
         return true;
     }
 
     @RequestMapping(value = "/disable/{id}", method = RequestMethod.PUT)
     public boolean disableRoute(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         routeService.disableTagRoute(id);
         return true;
     }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/WeightController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/WeightController.java
index 2a987f9..11ce807 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/WeightController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/WeightController.java
@@ -68,6 +68,7 @@
         if (id == null) {
             throw new ParamValidationException("Unknown ID!");
         }
+        id = id.replace("*", "/");
         WeightDTO weight = overrideService.findWeight(id);
         if (weight == null) {
             throw new ResourceNotFoundException("Unknown ID!");
@@ -83,17 +84,17 @@
     }
 
     @RequestMapping(method = RequestMethod.GET)
-    public List<WeightDTO> searchWeight(@RequestParam(required = false) String serviceName,
+    public List<WeightDTO> searchWeight(@RequestParam(required = false) String service,
                                         @RequestParam(required = false) String application,
                                         @PathVariable String env) {
-        if (StringUtils.isBlank(serviceName) && StringUtils.isBlank(application)) {
+        if (StringUtils.isBlank(service) && StringUtils.isBlank(application)) {
             throw new ParamValidationException("Either service or application is required");
         }
         WeightDTO weightDTO;
         if (StringUtils.isNotBlank(application)) {
             weightDTO = overrideService.findWeight(application);
         } else {
-            weightDTO = overrideService.findWeight(serviceName);
+            weightDTO = overrideService.findWeight(service);
         }
         List<WeightDTO> weightDTOS = new ArrayList<>();
         if (weightDTO != null) {
@@ -122,6 +123,7 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.GET)
     public WeightDTO detailWeight(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         WeightDTO weightDTO = overrideService.findWeight(id);
         if (weightDTO == null) {
             throw new ResourceNotFoundException("Unknown ID!");
@@ -131,6 +133,7 @@
 
     @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
     public boolean deleteWeight(@PathVariable String id, @PathVariable String env) {
+        id = id.replace("*", "/");
         overrideService.deleteWeight(id);
         return true;
     }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/GovernanceConfiguration.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/GovernanceConfiguration.java
index 5f86357..8fb75ab 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/GovernanceConfiguration.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/GovernanceConfiguration.java
@@ -34,4 +34,10 @@
 
     boolean deleteConfig(String key);
 
+    String setConfig(String group, String key, String value);
+
+    String getConfig(String group, String key);
+
+    boolean deleteConfig(String group, String key);
+
 }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/ApolloConfiguration.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/ApolloConfiguration.java
index cb05e6a..2bc0f90 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/ApolloConfiguration.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/ApolloConfiguration.java
@@ -18,14 +18,30 @@
 package org.apache.dubbo.admin.data.config.impl;
 
 import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient;
+import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
 import org.apache.dubbo.admin.data.config.GovernanceConfiguration;
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.SPI;
 import org.springframework.beans.factory.annotation.Value;
 
+@SPI("apollo")
 public class ApolloConfiguration implements GovernanceConfiguration {
 
     @Value("${dubbo.apollo.token}")
     private String token;
+
+    @Value("${dubbo.apollo.cluster}")
+    private String cluster;
+
+    @Value("${dubbo.apollo.namespace}")
+    private String namespace;
+
+    @Value("${dubbo.apollo.env}")
+    private String env;
+
+    @Value("${dubbo.apollo.appId}")
+    private String appId;
+
     private URL url;
     private ApolloOpenApiClient client;
 
@@ -47,16 +63,50 @@
 
     @Override
     public String setConfig(String key, String value) {
-        return null;
+        return setConfig(null, key, value);
     }
 
     @Override
     public String getConfig(String key) {
-        return null;
+        return getConfig(null, key);
     }
 
     @Override
     public boolean deleteConfig(String key) {
-        return false;
+        return deleteConfig(null, key);
+    }
+
+    @Override
+    public String setConfig(String group, String key, String value) {
+        if (group == null) {
+            group = namespace;
+        }
+        OpenItemDTO openItemDTO = new OpenItemDTO();
+        openItemDTO.setKey(key);
+        openItemDTO.setValue(value);
+        client.createItem(appId, env, cluster, group, openItemDTO);
+        return value;
+    }
+
+    @Override
+    public String getConfig(String group, String key) {
+        if (group == null) {
+            group = namespace;
+        }
+        OpenItemDTO openItemDTO =  client.getItem(appId, env, cluster, group, key);
+        if (openItemDTO != null) {
+            return openItemDTO.getValue();
+        }
+        return null;
+    }
+
+    @Override
+    public boolean deleteConfig(String group, String key) {
+        if (group == null) {
+            group = namespace;
+        }
+        //TODO user login user name as the operator
+        client.removeItem(appId, env, cluster, group, key, "admin");
+        return true;
     }
 }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/NoOpConfiguration.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/NoOpConfiguration.java
index 324bf8f..08cb489 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/NoOpConfiguration.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/NoOpConfiguration.java
@@ -51,4 +51,19 @@
     public boolean deleteConfig(String key) {
         return false;
     }
+
+    @Override
+    public String setConfig(String group, String key, String value) {
+        return null;
+    }
+
+    @Override
+    public String getConfig(String group, String key) {
+        return null;
+    }
+
+    @Override
+    public boolean deleteConfig(String group, String key) {
+        return false;
+    }
 }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/ZookeeperConfiguration.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/ZookeeperConfiguration.java
index 06770fb..95e7988 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/ZookeeperConfiguration.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/config/impl/ZookeeperConfiguration.java
@@ -24,6 +24,8 @@
 import org.apache.dubbo.admin.data.config.GovernanceConfiguration;
 import org.apache.dubbo.common.URL;
 
+import javax.swing.*;
+
 public class ZookeeperConfiguration implements GovernanceConfiguration {
     private CuratorFramework zkClient;
     private URL url;
@@ -52,7 +54,22 @@
 
     @Override
     public String setConfig(String key, String value) {
-        String path = getNodePath(key);
+        return setConfig(null, key, value);
+    }
+
+    @Override
+    public String getConfig(String key) {
+        return getConfig(null, key);
+    }
+
+    @Override
+    public boolean deleteConfig(String key) {
+        return deleteConfig(null, key);
+    }
+
+    @Override
+    public String setConfig(String group, String key, String value) {
+        String path = getNodePath(key, group);
         try {
             if (zkClient.checkExists().forPath(path) == null) {
                 zkClient.create().creatingParentsIfNeeded().forPath(path);
@@ -66,8 +83,8 @@
     }
 
     @Override
-    public String getConfig(String key) {
-        String path = getNodePath(key);
+    public String getConfig(String group, String key) {
+        String path = getNodePath(key, group);
 
         try {
             if (zkClient.checkExists().forPath(path) == null) {
@@ -81,8 +98,8 @@
     }
 
     @Override
-    public boolean deleteConfig(String key) {
-        String path = getNodePath(key);
+    public boolean deleteConfig(String group, String key) {
+        String path = getNodePath(key, group);
         try {
             zkClient.delete().forPath(path);
         } catch (Exception e) {
@@ -91,11 +108,18 @@
         return true;
     }
 
-    private String getNodePath(String path) {
-        return toRootDir() + path;
+    private String getNodePath(String path, String group) {
+        return toRootDir(group) + path;
     }
 
-    private String toRootDir() {
+    private String toRootDir(String group) {
+        if (group != null) {
+            if (!group.startsWith(Constants.PATH_SEPARATOR)) {
+                root = Constants.PATH_SEPARATOR + group;
+            } else {
+                root = group;
+            }
+        }
         if (root.equals(Constants.PATH_SEPARATOR)) {
             return root;
         }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/MetaDataCollector.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/MetaDataCollector.java
index 1bb5038..5b5e802 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/MetaDataCollector.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/MetaDataCollector.java
@@ -19,8 +19,7 @@
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.extension.SPI;
-import org.apache.dubbo.metadata.identifier.ConsumerMetadataIdentifier;
-import org.apache.dubbo.metadata.identifier.ProviderMetadataIdentifier;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
 
 @SPI("zookeeper")
 public interface MetaDataCollector {
@@ -31,7 +30,7 @@
 
     void init();
 
-    String getProviderMetaData(ProviderMetadataIdentifier key);
+    String getProviderMetaData(MetadataIdentifier key);
 
-    String getConsumerMetaData(ConsumerMetadataIdentifier key);
+    String getConsumerMetaData(MetadataIdentifier key);
 }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/NoOpMetadataCollector.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/NoOpMetadataCollector.java
index 1152041..8e561a6 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/NoOpMetadataCollector.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/NoOpMetadataCollector.java
@@ -19,8 +19,7 @@
 
 import org.apache.dubbo.admin.data.metadata.MetaDataCollector;
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.metadata.identifier.ConsumerMetadataIdentifier;
-import org.apache.dubbo.metadata.identifier.ProviderMetadataIdentifier;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
 
 public class NoOpMetadataCollector implements MetaDataCollector {
 
@@ -40,12 +39,12 @@
     }
 
     @Override
-    public String getProviderMetaData(ProviderMetadataIdentifier key) {
+    public String getProviderMetaData(MetadataIdentifier key) {
         return null;
     }
 
     @Override
-    public String getConsumerMetaData(ConsumerMetadataIdentifier key) {
+    public String getConsumerMetaData(MetadataIdentifier key) {
         return null;
     }
 }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/RedisMetaDataCollector.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/RedisMetaDataCollector.java
index 29b7396..b00238a 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/RedisMetaDataCollector.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/RedisMetaDataCollector.java
@@ -20,9 +20,7 @@
 
 import org.apache.dubbo.admin.data.metadata.MetaDataCollector;
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.metadata.identifier.ConsumerMetadataIdentifier;
 import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
-import org.apache.dubbo.metadata.identifier.ProviderMetadataIdentifier;
 import redis.clients.jedis.Jedis;
 import redis.clients.jedis.JedisPool;
 import redis.clients.jedis.JedisPoolConfig;
@@ -48,12 +46,12 @@
     }
 
     @Override
-    public String getProviderMetaData(ProviderMetadataIdentifier key) {
+    public String getProviderMetaData(MetadataIdentifier key) {
         return doGetMetaData(key);
     }
 
     @Override
-    public String getConsumerMetaData(ConsumerMetadataIdentifier key) {
+    public String getConsumerMetaData(MetadataIdentifier key) {
         return doGetMetaData(key);
     }
 
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/ZookeeperMetaDataCollector.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/ZookeeperMetaDataCollector.java
index 06d5e4a..0ecab02 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/ZookeeperMetaDataCollector.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/data/metadata/impl/ZookeeperMetaDataCollector.java
@@ -23,9 +23,7 @@
 import org.apache.dubbo.admin.common.util.Constants;
 import org.apache.dubbo.admin.data.metadata.MetaDataCollector;
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.metadata.identifier.ConsumerMetadataIdentifier;
 import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
-import org.apache.dubbo.metadata.identifier.ProviderMetadataIdentifier;
 
 public class ZookeeperMetaDataCollector implements MetaDataCollector {
 
@@ -58,12 +56,12 @@
 
 
     @Override
-    public String getProviderMetaData(ProviderMetadataIdentifier key) {
+    public String getProviderMetaData(MetadataIdentifier key) {
         return doGetMetadata(key);
     }
 
     @Override
-    public String getConsumerMetaData(ConsumerMetadataIdentifier key) {
+    public String getConsumerMetaData(MetadataIdentifier key) {
         return doGetMetadata(key);
     }
 
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/DynamicConfigDTO.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/DynamicConfigDTO.java
index f44afa7..6bc0719 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/DynamicConfigDTO.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/DynamicConfigDTO.java
@@ -23,12 +23,11 @@
 
 public class DynamicConfigDTO extends BaseDTO {
 
-    private String apiVersion;
-    private boolean dynamic;
+    private String configVersion;
+    private boolean runtime;
     private boolean enabled;
     private List<OverrideConfig> configs;
 
-
     public List<OverrideConfig> getConfigs() {
         return configs;
     }
@@ -37,20 +36,20 @@
         this.configs = configs;
     }
 
-    public String getApiVersion() {
-        return apiVersion;
+    public String getConfigVersion() {
+        return configVersion;
     }
 
-    public void setApiVersion(String apiVersion) {
-        this.apiVersion = apiVersion;
+    public void setConfigVersion(String configVersion) {
+        this.configVersion = configVersion;
     }
 
-    public boolean isDynamic() {
-        return dynamic;
+    public boolean isRuntime() {
+        return runtime;
     }
 
-    public void setDynamic(boolean dynamic) {
-        this.dynamic = dynamic;
+    public void setRuntime(boolean runtime) {
+        this.runtime = runtime;
     }
 
     public boolean isEnabled() {
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/RouteDTO.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/RouteDTO.java
index 38ab4e8..0503660 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/RouteDTO.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/RouteDTO.java
@@ -18,20 +18,11 @@
 package org.apache.dubbo.admin.model.dto;
 
 public abstract class RouteDTO extends BaseDTO{
-    private boolean dynamic;
     private int priority;
     private boolean enabled;
     private boolean force;
     private boolean runtime;
 
-    public boolean isDynamic() {
-        return dynamic;
-    }
-
-    public void setDynamic(boolean dynamic) {
-        this.dynamic = dynamic;
-    }
-
     public int getPriority() {
         return priority;
     }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/store/OverrideDTO.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/store/OverrideDTO.java
index 7c929d8..a917815 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/store/OverrideDTO.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/store/OverrideDTO.java
@@ -17,15 +17,13 @@
 
 package org.apache.dubbo.admin.model.store;
 
-import org.apache.dubbo.admin.model.dto.Config;
-
 import java.util.List;
 
 public class OverrideDTO {
     private String key;
     private String scope;
-    private String apiVersion;
-    private boolean dynamic;
+    private String configVersion;
+    private boolean runtime;
     private boolean enabled;
     private List<OverrideConfig> configs;
 
@@ -45,20 +43,20 @@
         this.scope = scope;
     }
 
-    public String getApiVersion() {
-        return apiVersion;
+    public String getConfigVersion() {
+        return configVersion;
     }
 
-    public void setApiVersion(String apiVersion) {
-        this.apiVersion = apiVersion;
+    public void setConfigVersion(String configVersion) {
+        this.configVersion = configVersion;
     }
 
-    public boolean isDynamic() {
-        return dynamic;
+    public boolean isRuntime() {
+        return runtime;
     }
 
-    public void setDynamic(boolean dynamic) {
-        this.dynamic = dynamic;
+    public void setRuntime(boolean runtime) {
+        this.runtime = runtime;
     }
 
     public boolean isEnabled() {
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/store/RoutingRuleDTO.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/store/RoutingRuleDTO.java
index 5498a56..70ba2ac 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/store/RoutingRuleDTO.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/store/RoutingRuleDTO.java
@@ -23,7 +23,6 @@
 
     private String key;
     private String scope;
-    private boolean dynamic;
     private int priority;
     private boolean enabled;
     private boolean force;
@@ -48,14 +47,6 @@
         this.scope = scope;
     }
 
-    public boolean isDynamic() {
-        return dynamic;
-    }
-
-    public void setDynamic(boolean dynamic) {
-        this.dynamic = dynamic;
-    }
-
     public int getPriority() {
         return priority;
     }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ConsumerService.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ConsumerService.java
index da518f9..0cd5238 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ConsumerService.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ConsumerService.java
@@ -17,7 +17,7 @@
 package org.apache.dubbo.admin.service;
 
 import org.apache.dubbo.admin.model.domain.Consumer;
-import org.apache.dubbo.metadata.identifier.ConsumerMetadataIdentifier;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
 
 import java.util.List;
 
@@ -31,7 +31,7 @@
 
     Consumer findConsumer(String id);
 
-    String getConsumerMetadata(ConsumerMetadataIdentifier consumerIdentifier);
+    String getConsumerMetadata(MetadataIdentifier consumerIdentifier);
 
     List<Consumer> findAll();
 
@@ -60,4 +60,4 @@
 
     List<String> findServices();
 
-}
\ No newline at end of file
+}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ProviderService.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ProviderService.java
index d90a265..eafb6d0 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ProviderService.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ProviderService.java
@@ -17,7 +17,7 @@
 package org.apache.dubbo.admin.service;
 
 import org.apache.dubbo.admin.model.domain.Provider;
-import org.apache.dubbo.metadata.identifier.ProviderMetadataIdentifier;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
 
 import java.util.List;
 
@@ -43,11 +43,11 @@
 
     Provider findProvider(String id);
 
-    String getProviderMetaData(ProviderMetadataIdentifier providerIdentifier);
+    String getProviderMetaData(MetadataIdentifier providerIdentifier);
 
     List<String> findServices();
 
-    String findServiceVersion(String serviceName);
+    String findServiceVersion(String serviceName, String application);
 
     String findVersionInApplication(String application);
 
@@ -79,4 +79,4 @@
 
     Provider findByServiceAndAddress(String service, String address);
 
-}
\ No newline at end of file
+}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java
index 128c3d3..c719389 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java
@@ -22,7 +22,7 @@
 import org.apache.dubbo.admin.service.ConsumerService;
 import org.apache.dubbo.common.Constants;
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.metadata.identifier.ConsumerMetadataIdentifier;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
 import org.springframework.stereotype.Component;
 
 import java.util.ArrayList;
@@ -51,7 +51,7 @@
     }
 
     @Override
-    public String getConsumerMetadata(ConsumerMetadataIdentifier consumerIdentifier) {
+    public String getConsumerMetadata(MetadataIdentifier consumerIdentifier) {
         return metaDataCollector.getConsumerMetaData(consumerIdentifier);
     }
 
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/OverrideServiceImpl.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/OverrideServiceImpl.java
index dc4eef6..a7774a2 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/OverrideServiceImpl.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/OverrideServiceImpl.java
@@ -23,7 +23,6 @@
 import org.apache.dubbo.admin.common.util.YamlParser;
 import org.apache.dubbo.admin.model.domain.LoadBalance;
 import org.apache.dubbo.admin.model.domain.Override;
-import org.apache.dubbo.admin.model.dto.Config;
 import org.apache.dubbo.admin.model.domain.Weight;
 import org.apache.dubbo.admin.model.dto.BalancingDTO;
 import org.apache.dubbo.admin.model.dto.DynamicConfigDTO;
@@ -64,6 +63,8 @@
             }
         }
         configs.addAll(override.getConfigs());
+        existOverride.setEnabled(override.isEnabled());
+        existOverride.setRuntime(override.isRuntime());
         existOverride.setConfigs(configs);
         dynamicConfiguration.setConfig(path, YamlParser.dumpObject(existOverride));
 
@@ -97,7 +98,9 @@
         }
         configs.addAll(update.getConfigs());
         overrideDTO.setConfigs(configs);
-        dynamicConfiguration.setConfig(path, YamlParser.dumpObject(update));
+        overrideDTO.setRuntime(update.isRuntime());
+        overrideDTO.setEnabled(update.isEnabled());
+        dynamicConfiguration.setConfig(path, YamlParser.dumpObject(overrideDTO));
 
         //for 2.6
         if (StringUtils.isNotEmpty(update.getService())) {
@@ -225,7 +228,7 @@
         String path = getPath(id);
         String config = dynamicConfiguration.getConfig(path);
         OverrideConfig overrideConfig = OverrideUtils.weightDTOtoConfig(weightDTO);
-        OverrideDTO overrideDTO = insertConfig(config, overrideConfig, id, scope);
+        OverrideDTO overrideDTO = insertConfig(config, overrideConfig, id, scope, Constants.WEIGHT);
         dynamicConfiguration.setConfig(path, YamlParser.dumpObject(overrideDTO));
 
         //for 2.6
@@ -335,7 +338,7 @@
         String path = getPath(id);
         String config = dynamicConfiguration.getConfig(path);
         OverrideConfig overrideConfig = OverrideUtils.balanceDTOtoConfig(balancingDTO);
-        OverrideDTO overrideDTO = insertConfig(config, overrideConfig, id, scope);
+        OverrideDTO overrideDTO = insertConfig(config, overrideConfig, id, scope, Constants.BALANCING);
         dynamicConfiguration.setConfig(path, YamlParser.dumpObject(overrideDTO));
 
         //for 2.6
@@ -434,7 +437,7 @@
         return null;
     }
 
-    private OverrideDTO insertConfig(String config, OverrideConfig overrideConfig, String key, String scope) {
+    private OverrideDTO insertConfig(String config, OverrideConfig overrideConfig, String key, String scope, String configType) {
         OverrideDTO overrideDTO = null;
         if(config == null) {
             overrideDTO = new OverrideDTO();
@@ -447,6 +450,12 @@
             overrideDTO = YamlParser.loadObject(config, OverrideDTO.class);
             List<OverrideConfig> configs = overrideDTO.getConfigs();
             if (configs != null) {
+                for (OverrideConfig o : configs) {
+                    if (configType.equals(o.getType())) {
+                        configs.remove(o);
+                        break;
+                    }
+                }
                 configs.add(overrideConfig);
             } else {
                 configs = new ArrayList<>();
@@ -511,13 +520,6 @@
         return prefix + Constants.PATH_SEPARATOR + key + Constants.PATH_SEPARATOR + Constants.CONFIGURATOR;
     }
 
-    private String formatMethodName(String method) {
-        if (method.equals("0")) {
-            return "*";
-        }
-        return method;
-    }
-
     private void unregisterWeight(WeightDTO weightDTO) {
         List<String> addresses = weightDTO.getAddresses();
         if (addresses != null) {
@@ -550,7 +552,7 @@
     private void unregisterBalancing(BalancingDTO balancingDTO) {
         LoadBalance loadBalance = new LoadBalance();
         loadBalance.setService(balancingDTO.getService());
-        loadBalance.setMethod(formatMethodName(balancingDTO.getMethodName()));
+        loadBalance.setMethod(balancingDTO.getMethodName());
         loadBalance.setStrategy(balancingDTO.getStrategy());
         registry.unregister(OverrideUtils.loadBalanceToOverride(loadBalance).toUrl());
     }
@@ -558,7 +560,7 @@
     private void registerBalancing(BalancingDTO balancingDTO) {
         LoadBalance loadBalance = new LoadBalance();
         loadBalance.setService(balancingDTO.getService());
-        loadBalance.setMethod(formatMethodName(balancingDTO.getMethodName()));
+        loadBalance.setMethod(balancingDTO.getMethodName());
         loadBalance.setStrategy(balancingDTO.getStrategy());
         registry.register(OverrideUtils.loadBalanceToOverride(loadBalance).toUrl());
     }
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
index fe532c5..09670c8 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
@@ -16,7 +16,9 @@
  */
 package org.apache.dubbo.admin.service.impl;
 
+import com.google.common.collect.Iterables;
 import com.google.gson.Gson;
+import org.apache.dubbo.admin.common.exception.ParamValidationException;
 import org.apache.dubbo.admin.common.util.ConvertUtil;
 import org.apache.dubbo.admin.common.util.Pair;
 import org.apache.dubbo.admin.common.util.ParseUtils;
@@ -28,9 +30,10 @@
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
-import org.apache.dubbo.metadata.identifier.ProviderMetadataIdentifier;
+import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
+import org.yaml.snakeyaml.events.Event;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -39,6 +42,8 @@
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentMap;
 
+import static org.apache.dubbo.common.Constants.SPECIFICATION_VERSION_KEY;
+
 /**
  * IbatisProviderService
  *
@@ -92,7 +97,7 @@
 //    }
 
     @java.lang.Override
-    public String getProviderMetaData(ProviderMetadataIdentifier providerIdentifier) {
+    public String getProviderMetaData(MetadataIdentifier providerIdentifier) {
         return metaDataCollector.getProviderMetaData(providerIdentifier);
     }
 
@@ -398,22 +403,21 @@
     @Override
     public String findVersionInApplication(String application) {
         List<String> services = findServicesByApplication(application);
-        return findServiceVersion(services.get(0));
+        if (services == null || services.size() == 0) {
+            throw new ParamValidationException("there is no service for application: " + application);
+        }
+        return findServiceVersion(services.get(0), application);
     }
 
     @Override
-    public String findServiceVersion(String serviceName) {
+    public String findServiceVersion(String serviceName, String application) {
         String version = "2.6";
-        serviceName = serviceName.replace("*", "/");
-        Map<String, String> info = ConvertUtil.serviceName2Map(serviceName);
-        ProviderMetadataIdentifier p = new ProviderMetadataIdentifier(info.get(Constants.INTERFACE_KEY),
-                info.get(Constants.VERSION_KEY),
-                info.get(Constants.GROUP_KEY));
-        String metadata = getProviderMetaData(p);
-        Gson gson = new Gson();
-        if (StringUtils.isNoneEmpty(metadata)) {
-            FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class);
-            version = serviceDefinition.getParameters().get("specVersion");
+        Map<String, URL> result = findProviderUrlByAppandService(application, serviceName);
+        if (result != null && result.size() > 0) {
+            URL url = result.values().stream().findFirst().get();
+            if (url.getParameter(Constants.SPECIFICATION_VERSION_KEY) != null) {
+                version = url.getParameter(Constants.SPECIFICATION_VERSION_KEY);
+            }
         }
         return version;
     }
diff --git a/dubbo-admin-backend/src/main/resources/application.properties b/dubbo-admin-backend/src/main/resources/application.properties
index 294b80e..892d167 100644
--- a/dubbo-admin-backend/src/main/resources/application.properties
+++ b/dubbo-admin-backend/src/main/resources/application.properties
@@ -17,4 +17,8 @@
 
 dubbo.registry.group=dubbo
 dubbo.configcenter=zookeeper://127.0.0.1:2181
-dubbo.apollo.token=xxxxx
\ No newline at end of file
+dubbo.apollo.token=e16e5cd903fd0c97a116c873b448544b9d086de9
+dubbo.apollo.appId=test
+dubbo.apollo.env=dev
+dubbo.apollo.cluster=default
+dubbo.apollo.namespace=dubbo
diff --git a/dubbo-admin-frontend/src/components/ServiceSearch.vue b/dubbo-admin-frontend/src/components/ServiceSearch.vue
index 02c0a8a..5003a78 100644
--- a/dubbo-admin-frontend/src/components/ServiceSearch.vue
+++ b/dubbo-admin-frontend/src/components/ServiceSearch.vue
@@ -79,8 +79,36 @@
                 <td>{{props.item.group}}</td>
                 <td>{{props.item.version}}</td>
                 <td>{{props.item.appName}}</td>
-                <td class="text-xs-center px-0"><v-btn small color='primary' :href='getHref(props.item.service, props.item.appName,
-                                                                                            props.item.group, props.item.version)'>Detail</v-btn></td>
+                <td class="text-xs-center px-0" nowrap>
+                  <v-btn
+                    small
+                    color='primary'
+                    :href='getHref(props.item.service, props.item.appName, props.item.group, props.item.version)'
+                  >
+                    Detail
+                  </v-btn>
+                  <v-menu
+                  >
+                    <v-btn
+                      slot="activator"
+                      color="primary"
+                      small
+                      dark
+                    >
+                      More
+                      <v-icon>expand_more</v-icon>
+                    </v-btn>
+                    <v-list>
+                      <v-list-tile
+                        v-for="(item, i) in options"
+                        :key="i"
+                        :href='governanceHref(item.value, props.item.service, props.item.group, props.item.version)'
+                      >
+                        <v-list-tile-title>{{ item.title }}</v-list-tile-title>
+                      </v-list-tile>
+                    </v-list>
+                  </v-menu>
+                </td>
               </template>
             </v-data-table>
           </template>
@@ -94,10 +122,30 @@
   export default {
     data: () => ({
       items: [
-        {id: 0, title: 'service name', value: 'serviceName'},
+        {id: 0, title: 'service name', value: 'service'},
         {id: 1, title: 'IP', value: 'ip'},
         {id: 2, title: 'application', value: 'application'}
       ],
+      options: [
+        { title: 'Routing Rule',
+          value: 'routingRule'
+        },
+        { title: 'Tag Rule',
+          value: 'tagRule'
+        },
+        { title: 'Dynamic Config',
+          value: 'config'
+        },
+        { title: 'Access Control',
+          value: 'access'
+        },
+        { title: 'Weight Adjust',
+          value: 'weight'
+        },
+        { title: 'Load Balance',
+          value: 'loadbalance'
+        }
+      ],
       timerID: null,
       loading: false,
       selected: 0,
@@ -190,6 +238,20 @@
         }
         return '/#/serviceDetail?' + query
       },
+      governanceHref: function (type, service, group, version) {
+        let base = '/#/governance/' + type
+        let query = service
+        if (group !== null) {
+          query = group + '/' + query
+        }
+        if (version !== null) {
+          query = query + ':' + version
+        }
+        if (type === 'tagRule') {
+          return base + '?application=' + query
+        }
+        return base + '?service=' + query
+      },
       submit () {
         this.filter = document.querySelector('#serviceSearch').value.trim()
         if (this.filter) {
@@ -228,7 +290,7 @@
       })
       if (filter != null && pattern != null) {
         this.filter = filter
-        if (pattern === 'serviceName') {
+        if (pattern === 'service') {
           this.selected = 0
         } else if (pattern === 'application') {
           this.selected = 2
@@ -236,10 +298,16 @@
           this.selected = 1
         }
         this.search(filter, pattern, false)
+      } else {
+        // display all existing services by default
+        this.filter = '*'
+        this.selected = 0
+        pattern = 'service'
+        this.search(this.filter, pattern, true)
       }
       this.$axios.get('/service', {
         params: {
-          pattern: 'serviceName',
+          pattern: 'service',
           filter: '*'
         }
       }).then(response => {
diff --git a/dubbo-admin-frontend/src/components/governance/AccessControl.vue b/dubbo-admin-frontend/src/components/governance/AccessControl.vue
index baa7422..5e5397c 100644
--- a/dubbo-admin-frontend/src/components/governance/AccessControl.vue
+++ b/dubbo-admin-frontend/src/components/governance/AccessControl.vue
@@ -146,7 +146,6 @@
           <v-form ref="modalForm">
             <v-text-field label="Service Unique ID"
                           hint="A service ID in form of group/service:version, group and version are optional"
-                          :rules="[required]"
                           :readonly="modal.id != null"
                           v-model="modal.service" />
             <v-text-field
@@ -200,7 +199,7 @@
   name: 'AccessControl',
   data: () => ({
     items: [
-      {id: 0, title: 'service name', value: 'serviceName'},
+      {id: 0, title: 'service name', value: 'service'},
       {id: 1, title: 'application', value: 'application'}
     ],
     selected: 0,
@@ -233,7 +232,6 @@
       }
     ],
     accesses: [],
-    required: value => !!value || 'Service ID is required, in form of group/service:version, group and version are optional',
     modal: {
       enable: false,
       title: 'Create New',
@@ -265,7 +263,7 @@
   }),
   methods: {
     search () {
-      if (this.filter == null) {
+      if (!this.filter) {
         return
       }
       let type = this.items[this.selected].value
@@ -308,10 +306,11 @@
     createItem () {
       let doc = yaml.load(this.modal.content)
       this.filter = ''
-      if (this.modal.service === '' && this.modal.service === null) {
+      if (!this.modal.service && !this.modal.application) {
+        this.$notify.error('Either service or application is needed')
         return
       }
-      var vm = this
+      let vm = this
       this.$axios.post('/rules/access', {
         service: this.modal.service,
         application: this.modal.application,
@@ -319,7 +318,7 @@
         blacklist: doc.blacklist
       }).then(response => {
         if (response.status === 201) {
-          if (vm.modal.service !== null) {
+          if (vm.modal.service) {
             vm.selected = 0
             vm.filter = vm.modal.service
           } else {
@@ -339,6 +338,9 @@
       } else {
         itemId = item.application
       }
+      if (itemId.includes('/')) {
+        itemId = itemId.replace('/', '*')
+      }
       Object.assign(this.modal, {
         enable: true,
         title: 'Edit',
@@ -361,7 +363,7 @@
 
       }).then(response => {
         if (response.status === 200) {
-          if (vm.modal.service !== null) {
+          if (vm.modal.service) {
             vm.selected = 0
             vm.filter = vm.modal.service
           } else {
diff --git a/dubbo-admin-frontend/src/components/governance/LoadBalance.vue b/dubbo-admin-frontend/src/components/governance/LoadBalance.vue
index db0e1ee..4d62e77 100644
--- a/dubbo-admin-frontend/src/components/governance/LoadBalance.vue
+++ b/dubbo-admin-frontend/src/components/governance/LoadBalance.vue
@@ -118,7 +118,6 @@
           <v-text-field
             label="Service Unique ID"
             hint="A service ID in form of group/service:version, group and version are optional"
-            :rules="[required]"
             v-model="service"
           ></v-text-field>
           <v-text-field
@@ -164,7 +163,7 @@
     },
     data: () => ({
       items: [
-        {id: 0, title: 'service name', value: 'serviceName'},
+        {id: 0, title: 'service name', value: 'service'},
         {id: 1, title: 'application', value: 'application'}
       ],
       selected: 0,
@@ -188,9 +187,8 @@
       ],
       loadBalances: [
       ],
-      required: value => !!value || 'Service ID is required, in form of group/service:version, group and version are optional',
       template:
-        'methodName: sayHello  # 0 for all methods\n' +
+        'methodName: sayHello  # * for all methods\n' +
         'strategy:  # leastactive, random, roundrobin',
       ruleText: '',
       readonly: false,
@@ -244,7 +242,11 @@
           .then(response => {
             this.loadBalances = response.data
             if (rewrite) {
-              this.$router.push({path: 'loadbalance', query: {service: filter}})
+              if (this.selected === 0) {
+                this.$router.push({path: 'loadbalance', query: {service: filter}})
+              } else if (this.selected === 1) {
+                this.$router.push({path: 'loadbalance', query: {application: filter}})
+              }
             }
           })
       },
@@ -271,12 +273,14 @@
       saveItem: function () {
         this.ruleText = this.verifyRuleText(this.ruleText)
         let balancing = yaml.safeLoad(this.ruleText)
-        if (this.service === '' && this.application === '') {
+        if (!this.service && !this.application) {
+          this.$notify.error('Either service or application is needed')
           return
         }
+        let vm = this
         balancing.service = this.service
         balancing.application = this.application
-        if (this.updateId !== '') {
+        if (this.updateId) {
           if (this.updateId === 'close') {
             this.closeDialog()
           } else {
@@ -284,14 +288,14 @@
             this.$axios.put('/rules/balancing/' + balancing.id, balancing)
               .then(response => {
                 if (response.status === 200) {
-                  if (this.service !== '') {
-                    this.selected = 0
-                    this.search(this.service, true)
-                    this.filter = this.service
+                  if (vm.service) {
+                    vm.selected = 0
+                    vm.search(vm.service, true)
+                    vm.filter = vm.service
                   } else {
-                    this.selected = 1
-                    this.search(this.application, true)
-                    this.filter = this.application
+                    vm.selected = 1
+                    vm.search(vm.application, true)
+                    vm.filter = vm.application
                   }
                   this.closeDialog()
                   this.$notify.success('Update success')
@@ -302,14 +306,14 @@
           this.$axios.post('/rules/balancing', balancing)
             .then(response => {
               if (response.status === 201) {
-                if (this.service !== '') {
-                  this.selected = 0
-                  this.search(this.service, true)
-                  this.filter = this.service
+                if (vm.service) {
+                  vm.selected = 0
+                  vm.search(vm.service, true)
+                  vm.filter = vm.service
                 } else {
-                  this.selected = 1
-                  this.search(this.application, true)
-                  this.filter = this.application
+                  vm.selected = 1
+                  vm.search(vm.application, true)
+                  vm.filter = vm.application
                 }
                 this.closeDialog()
                 this.$notify.success('Create success')
@@ -324,6 +328,9 @@
         } else {
           itemId = item.application
         }
+        if (itemId.includes('/')) {
+          itemId = itemId.replace('/', '*')
+        }
         switch (icon) {
           case 'visibility':
             this.$axios.get('/rules/balancing/' + itemId)
@@ -392,15 +399,21 @@
     mounted: function () {
       this.ruleText = this.template
       let query = this.$route.query
-      let service = null
+      let filter = null
+      let vm = this
       Object.keys(query).forEach(function (key) {
         if (key === 'service') {
-          service = query[key]
+          filter = query[key]
+          vm.selected = 0
+        }
+        if (key === 'application') {
+          filter = query[key]
+          vm.selected = 1
         }
       })
-      if (service !== null) {
-        this.filter = service
-        this.search(service, false)
+      if (filter !== null) {
+        this.filter = filter
+        this.search(filter, false)
       }
     }
 
diff --git a/dubbo-admin-frontend/src/components/governance/Overrides.vue b/dubbo-admin-frontend/src/components/governance/Overrides.vue
index 4c1cb0e..9da0b7f 100644
--- a/dubbo-admin-frontend/src/components/governance/Overrides.vue
+++ b/dubbo-admin-frontend/src/components/governance/Overrides.vue
@@ -163,7 +163,7 @@
     },
     data: () => ({
       items: [
-        {id: 0, title: 'service name', value: 'serviceName'},
+        {id: 0, title: 'service name', value: 'service'},
         {id: 1, title: 'application', value: 'application'}
       ],
       selected: 0,
@@ -184,13 +184,11 @@
       ],
       appConfigs: [
       ],
-      required: value => !!value || 'Service ID is required, in form of group/service:version, group and version are optional',
       template:
 
-        'apiVersion: v2.7\n' +
+        'configVersion: v2.7\n' +
         'enabled: true\n' +
         'runtime: true\n' +
-        'force: true\n' +
         'configs: \n' +
         '  - addresses: [0.0.0.0]  # 0.0.0.0 for all addresses\n' +
         '    side: consumer        # effective side, consumer or addresses\n' +
@@ -241,7 +239,7 @@
             }
             if (rewrite) {
               if (this.selected === 0) {
-                this.$router.push({path: 'config', query: {serviceName: filter}})
+                this.$router.push({path: 'config', query: {service: filter}})
               } else if (this.selected === 1) {
                 this.$router.push({path: 'config', query: {application: filter}})
               }
@@ -270,26 +268,28 @@
       },
       saveItem: function () {
         let override = yaml.safeLoad(this.ruleText)
-        if (this.service === '' && this.application === '') {
+        if (!this.service && !this.application) {
+          this.$notify.error('Either service or application is needed')
           return
         }
         override.service = this.service
         override.application = this.application
-        if (this.updateId !== '') {
+        let vm = this
+        if (this.updateId) {
           if (this.updateId === 'close') {
             this.closeDialog()
           } else {
             this.$axios.put('/rules/override/' + this.updateId, override)
               .then(response => {
                 if (response.status === 200) {
-                  if (this.service !== '') {
-                    this.selected = 0
-                    this.search(this.service, true)
-                    this.filter = this.service
+                  if (vm.service) {
+                    vm.selected = 0
+                    vm.search(this.service, true)
+                    vm.filter = vm.service
                   } else {
-                    this.selected = 1
-                    this.search(this.application, true)
-                    this.filter = this.application
+                    vm.selected = 1
+                    vm.search(vm.application, true)
+                    vm.filter = vm.application
                   }
                   this.$notify.success('Update success')
                   this.closeDialog()
@@ -300,14 +300,14 @@
           this.$axios.post('/rules/override', override)
             .then(response => {
               if (response.status === 201) {
-                if (this.service !== '') {
-                  this.selected = 0
-                  this.search(this.service, true)
-                  this.filter = this.service
+                if (this.service) {
+                  vm.selected = 0
+                  vm.search(vm.service, true)
+                  vm.filter = vm.service
                 } else {
-                  this.selected = 1
-                  this.search(this.application, true)
-                  this.filter = this.application
+                  vm.selected = 1
+                  vm.search(vm.application, true)
+                  vm.filter = vm.application
                 }
                 this.$notify.success('Create success')
                 this.closeDialog()
@@ -322,6 +322,9 @@
         } else {
           itemId = item.application
         }
+        if (itemId.includes('/')) {
+          itemId = itemId.replace('/', '*')
+        }
         switch (icon) {
           case 'visibility':
             this.$axios.get('/rules/override/' + itemId)
@@ -361,6 +364,7 @@
         delete config.service
         delete config.application
         delete config.id
+        this.removeEmpty(config)
         this.ruleText = yaml.safeDump(config)
         this.readonly = readonly
         this.dialog = true
@@ -368,6 +372,15 @@
       setHeight: function () {
         this.height = window.innerHeight * 0.5
       },
+      removeEmpty: function (obj) {
+        Object.keys(obj).forEach(key => {
+          if (obj[key] && typeof obj[key] === 'object') {
+            this.removeEmpty(obj[key])
+          } else if (obj[key] == null) {
+            delete obj[key]
+          }
+        })
+      },
       deleteItem: function (warnStatus) {
         let id = warnStatus.id
         let operation = warnStatus.operation
@@ -415,7 +428,7 @@
       let filter = null
       let vm = this
       Object.keys(query).forEach(function (key) {
-        if (key === 'serviceName') {
+        if (key === 'service') {
           filter = query[key]
           vm.selected = 0
         }
diff --git a/dubbo-admin-frontend/src/components/governance/RoutingRule.vue b/dubbo-admin-frontend/src/components/governance/RoutingRule.vue
index 23103a6..9ca652a 100644
--- a/dubbo-admin-frontend/src/components/governance/RoutingRule.vue
+++ b/dubbo-admin-frontend/src/components/governance/RoutingRule.vue
@@ -164,12 +164,12 @@
     },
     data: () => ({
       items: [
-        {id: 0, title: 'service name', value: 'serviceName'},
+        {id: 0, title: 'service name', value: 'service'},
         {id: 1, title: 'application', value: 'application'}
       ],
       selected: 0,
       dropdown_font: [ 'Service', 'App', 'IP' ],
-      ruleKeys: ['enabled', 'force', 'dynamic', 'runtime', 'group', 'version', 'rule', 'priority'],
+      ruleKeys: ['enabled', 'force', 'runtime', 'group', 'version', 'rule', 'priority'],
       pattern: 'Service',
       filter: '',
       dialog: false,
@@ -186,7 +186,6 @@
       ],
       appRoutingRules: [
       ],
-      required: value => !!value || 'Service ID is required, in form of group/service:version, group and version are optional',
       template:
         'enabled: true\n' +
         'priority: 100\n' +
@@ -265,7 +264,7 @@
             }
             if (rewrite) {
               if (this.selected === 0) {
-                this.$router.push({path: 'routingRule', query: {serviceName: filter}})
+                this.$router.push({path: 'routingRule', query: {service: filter}})
               } else if (this.selected === 1) {
                 this.$router.push({path: 'routingRule', query: {application: filter}})
               }
@@ -295,9 +294,11 @@
       },
       saveItem: function () {
         let rule = yaml.safeLoad(this.ruleText)
-        if (this.service === '' && this.application === '') {
+        if (!this.service && !this.application) {
+          this.$notify.error('Either service or application is needed')
           return
         }
+        let vm = this
         rule.service = this.service
         rule.application = this.application
         if (this.updateId !== '') {
@@ -308,14 +309,14 @@
             this.$axios.put('/rules/route/condition/' + rule.id, rule)
               .then(response => {
                 if (response.status === 200) {
-                  if (this.service !== '') {
-                    this.selected = 0
-                    this.search(this.service, true)
-                    this.filter = this.service
+                  if (vm.service) {
+                    vm.selected = 0
+                    vm.search(vm.service, true)
+                    vm.filter = vm.service
                   } else {
-                    this.selected = 1
-                    this.search(this.application, true)
-                    this.filter = this.application
+                    vm.selected = 1
+                    vm.search(vm.application, true)
+                    vm.filter = vm.application
                   }
                   this.closeDialog()
                   this.$notify.success('Update success')
@@ -326,14 +327,14 @@
           this.$axios.post('/rules/route/condition/', rule)
             .then(response => {
               if (response.status === 201) {
-                if (this.service !== '') {
-                  this.selected = 0
-                  this.search(this.service, true)
-                  this.filter = this.service
+                if (vm.service) {
+                  vm.selected = 0
+                  vm.search(vm.service, true)
+                  vm.filter = vm.service
                 } else {
-                  this.selected = 1
-                  this.search(this.application, true)
-                  this.filter = this.application
+                  vm.selected = 1
+                  vm.search(vm.application, true)
+                  vm.filter = vm.application
                 }
                 this.closeDialog()
                 this.$notify.success('Create success')
@@ -351,6 +352,9 @@
         } else {
           itemId = item.application
         }
+        if (itemId.includes('/')) {
+          itemId = itemId.replace('/', '*')
+        }
         switch (icon) {
           case 'visibility':
             this.$axios.get('/rules/route/condition/' + itemId)
@@ -446,7 +450,7 @@
       let filter = null
       let vm = this
       Object.keys(query).forEach(function (key) {
-        if (key === 'serviceName') {
+        if (key === 'service') {
           filter = query[key]
           vm.selected = 0
         }
diff --git a/dubbo-admin-frontend/src/components/governance/TagRule.vue b/dubbo-admin-frontend/src/components/governance/TagRule.vue
index 6cf38ec..dce9724 100644
--- a/dubbo-admin-frontend/src/components/governance/TagRule.vue
+++ b/dubbo-admin-frontend/src/components/governance/TagRule.vue
@@ -121,7 +121,6 @@
       operations: operations,
       tagRoutingRules: [
       ],
-      required: value => !!value || 'Service ID is required, in form of group/service:version, group and version are optional',
       template:
         'force: false\n' +
         'enabled: true\n' +
@@ -194,11 +193,13 @@
       },
       saveItem: function () {
         let rule = yaml.safeLoad(this.ruleText)
-        if (this.application === '') {
+        if (!this.application) {
+          this.$notify.error('application is required')
           return
         }
         rule.application = this.application
-        if (this.updateId !== '') {
+        let vm = this
+        if (this.updateId) {
           if (this.updateId === 'close') {
             this.closeDialog()
           } else {
@@ -206,9 +207,9 @@
             this.$axios.put('/rules/route/tag/' + rule.id, rule)
               .then(response => {
                 if (response.status === 200) {
-                  this.search(this.application, true)
-                  this.closeDialog()
-                  this.$notify.success('Update success')
+                  vm.search(vm.application, true)
+                  vm.closeDialog()
+                  vm.$notify.success('Update success')
                 }
               })
           }
@@ -216,10 +217,10 @@
           this.$axios.post('/rules/route/tag/', rule)
             .then(response => {
               if (response.status === 201) {
-                this.search(this.application, true)
-                this.filter = this.application
-                this.closeDialog()
-                this.$notify.success('Create success')
+                vm.search(vm.application, true)
+                vm.filter = vm.application
+                vm.closeDialog()
+                vm.$notify.success('Create success')
               }
             })
             .catch(error => {
diff --git a/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue b/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue
index f1514a9..7cd057b 100644
--- a/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue
+++ b/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue
@@ -72,7 +72,7 @@
           >
             <template slot="items" slot-scope="props">
               <td class="text-xs-left">{{ props.item.service }}</td>
-              <td class="text-xs-left">{{ props.item.method }}</td>
+              <td class="text-xs-left">{{ props.item.weight }}</td>
               <td class="text-xs-center px-0">
                 <v-tooltip bottom v-for="op in operations" :key="op.id">
                   <v-icon small class="mr-2" slot="activator" @click="itemOperation(op.icon, props.item)">
@@ -93,7 +93,7 @@
           >
             <template slot="items" slot-scope="props">
               <td class="text-xs-left">{{ props.item.application }}</td>
-              <td class="text-xs-left">{{ props.item.method }}</td>
+              <td class="text-xs-left">{{ props.item.weight }}</td>
               <td class="text-xs-center px-0">
                 <v-tooltip bottom v-for="op in operations" :key="op.id">
                   <v-icon small class="mr-2" slot="activator" @click="itemOperation(op.icon, props.item)">
@@ -117,7 +117,6 @@
           <v-text-field
             label="Service Unique ID"
             hint="A service ID in form of group/service:version, group and version are optional"
-            :rules="[required]"
             v-model="service"
           ></v-text-field>
           <v-text-field
@@ -164,7 +163,7 @@
     },
     data: () => ({
       items: [
-        {id: 0, title: 'service name', value: 'serviceName'},
+        {id: 0, title: 'service name', value: 'service'},
         {id: 1, title: 'application', value: 'application'}
       ],
       selected: 0,
@@ -188,7 +187,6 @@
       ],
       weights: [
       ],
-      required: value => !!value || 'Service ID is required, in form of group/service:version, group and version are optional',
       template:
         'weight: 100  # 100 for default\n' +
         'addresses:   # addresses\'s ip\n' +
@@ -247,7 +245,7 @@
             this.weights = response.data
             if (rewrite) {
               if (this.selected === 0) {
-                this.$router.push({path: 'weight', query: {serviceName: filter}})
+                this.$router.push({path: 'weight', query: {service: filter}})
               } else if (this.selected === 1) {
                 this.$router.push({path: 'weight', query: {application: filter}})
               }
@@ -275,12 +273,14 @@
       },
       saveItem: function () {
         let weight = yaml.safeLoad(this.ruleText)
-        if (this.service === '' && this.application === '') {
+        if (!this.service && !this.application) {
+          this.$notify.error('Either service or application is needed')
           return
         }
         weight.service = this.service
         weight.application = this.application
-        if (this.updateId !== '') {
+        let vm = this
+        if (this.updateId) {
           if (this.updateId === 'close') {
             this.closeDialog()
           } else {
@@ -288,14 +288,14 @@
             this.$axios.put('/rules/weight/' + weight.id, weight)
               .then(response => {
                 if (response.status === 200) {
-                  if (this.service !== '') {
-                    this.selected = 0
-                    this.search(this.service, true)
-                    this.filter = this.service
+                  if (vm.service) {
+                    vm.selected = 0
+                    vm.search(vm.service, true)
+                    vm.filter = vm.service
                   } else {
-                    this.selected = 1
-                    this.search(this.application, true)
-                    this.filter = this.application
+                    vm.selected = 1
+                    vm.search(vm.application, true)
+                    vm.filter = vm.application
                   }
                   this.closeDialog()
                   this.$notify.success('Update success')
@@ -306,17 +306,17 @@
           this.$axios.post('/rules/weight', weight)
             .then(response => {
               if (response.status === 201) {
-                if (this.service !== '') {
-                  this.selected = 0
-                  this.search(this.service, true)
-                  this.filter = this.service
+                if (this.service) {
+                  vm.selected = 0
+                  vm.search(vm.service, true)
+                  vm.filter = vm.service
                 } else {
-                  this.selected = 1
-                  this.search(this.application, true)
-                  this.filter = this.application
+                  vm.selected = 1
+                  vm.search(vm.application, true)
+                  vm.filter = vm.application
                 }
-                this.closeDialog()
-                this.$notify.success('Create success')
+                vm.closeDialog()
+                vm.$notify.success('Create success')
               }
             })
         }
@@ -328,6 +328,9 @@
         } else {
           itemId = item.application
         }
+        if (itemId.includes('/')) {
+          itemId = itemId.replace('/', '*')
+        }
         switch (icon) {
           case 'visibility':
             this.$axios.get('/rules/weight/' + itemId)
@@ -385,15 +388,21 @@
     mounted: function () {
       this.ruleText = this.template
       let query = this.$route.query
-      let service = null
+      let filter = null
+      let vm = this
       Object.keys(query).forEach(function (key) {
         if (key === 'service') {
-          service = query[key]
+          filter = query[key]
+          vm.selected = 0
+        }
+        if (key === 'application') {
+          filter = query[key]
+          vm.selected = 1
         }
       })
-      if (service !== null) {
-        this.filter = service
-        this.search(service, false)
+      if (filter !== null) {
+        this.filter = filter
+        this.search(filter, false)
       }
     }
   }
diff --git a/pom.xml b/pom.xml
index e975680..abee9bd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,7 +63,7 @@
 		<netty-version>4.1.30.Final</netty-version>
 		<jacoco-version>0.8.2</jacoco-version>
 		<jedis-version>2.9.0</jedis-version>
-        <apollo-version>1.1.2</apollo-version>
+        <apollo-version>1.2.0</apollo-version>
 		<snakeyaml-version>1.19</snakeyaml-version>
 	</properties>