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

[incubator-dubbo] branch dev-metadata updated (59dd98a -> ab2b736)

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

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


    from 59dd98a  Merge pull request #2626, simplify registry data and add a new service data store seperated from registry.
     new 91fddde  Improvements for dynamic config and router: 1. support route in StaticDirectory, multi-registry & group merger 2. tolerance of abnormal configs from configserver. 3. add check policy when failed to connect to configserver
     new 44fb07f  Demo and ut changes
     new ab2b736  Merge branch 'dev-metadata' of https://github.com/apache/incubator-dubbo into dev-metadata

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../java/org/apache/dubbo/rpc/cluster/Router.java  |   4 +-
 .../org/apache/dubbo/rpc/cluster/RouterChain.java  |  14 +-
 .../rpc/cluster/directory/AbstractDirectory.java   |  11 +-
 .../rpc/cluster/directory/StaticDirectory.java     |  15 +-
 .../dubbo/rpc/cluster/router/AbstractRouter.java   |   5 +
 .../condition/config/ConfigConditionRouter.java    |  30 ++-
 .../router/{ => mock}/MockInvokersSelector.java    | 229 +++++++++------------
 .../MockRouterFactory.java}                        |  11 +-
 .../dubbo/rpc/cluster/router/tag/TagRouter.java    |  13 +-
 .../cluster/support/AbstractClusterInvoker.java    |   6 +-
 .../dubbo/rpc/cluster/support/ClusterUtils.java    |   9 +-
 .../cluster/support/MergeableClusterInvoker.java   |  29 ++-
 ...dcastCluster.java => RegistryAwareCluster.java} |  71 +++----
 ...voker.java => RegistryAwareClusterInvoker.java} | 126 ++++++------
 .../internal/org.apache.dubbo.rpc.cluster.Cluster  |   3 +-
 .../org.apache.dubbo.rpc.cluster.RouterFactory     |   3 +-
 .../cluster/router/ConfigConditionRouterTest.java  |   7 +-
 .../dubbo/rpc/cluster/router/TagRouterTest.java    |  26 +--
 .../java/org/apache/dubbo/common/Constants.java    |   1 +
 .../dubbo/common/extension/ExtensionLoader.java    |   4 +
 .../org/apache/dubbo/config/ReferenceConfig.java   |   9 +-
 dubbo-config/dubbo-config-dynamic/pom.xml          |   2 +-
 .../dynamic/AbstractDynamicConfiguration.java      |   4 +-
 .../support/apollo/ApolloDynamicConfiguration.java |  49 ++---
 .../archaius/ArchaiusDynamicConfiguration.java     |   3 +-
 .../sources/ZooKeeperConfigurationSource.java      |  16 +-
 .../support/nop/NopDynamicConfiguration.java       |   2 +-
 .../org/apache/dubbo/demo/consumer/Consumer.java   |   4 +-
 .../dubbo/demo/consumer}/DemoServiceMock.java      |  70 ++++---
 .../META-INF/spring/dubbo-demo-consumer.xml        |   2 +
 .../META-INF/spring/dubbo-demo-provider.xml        |   6 +-
 .../registry/integration/RegistryDirectory.java    |  86 +++++---
 .../java/org/apache/dubbo/rpc/RpcException.java    |   5 +
 33 files changed, 458 insertions(+), 417 deletions(-)
 rename dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/{ => mock}/MockInvokersSelector.java (76%)
 copy dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/{condition/config/ConfigConditionRouterFactory.java => mock/MockRouterFactory.java} (84%)
 copy dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/{BroadcastCluster.java => RegistryAwareCluster.java} (86%)
 copy dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/{BroadcastClusterInvoker.java => RegistryAwareClusterInvoker.java} (61%)
 copy {dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter => dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer}/DemoServiceMock.java (77%)


[incubator-dubbo] 03/03: Merge branch 'dev-metadata' of https://github.com/apache/incubator-dubbo into dev-metadata

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit ab2b7361df36b20647460b1e4865f076de8c4bb7
Merge: 44fb07f 59dd98a
Author: ken.lj <ke...@gmail.com>
AuthorDate: Wed Oct 17 14:07:30 2018 +0800

    Merge branch 'dev-metadata' of https://github.com/apache/incubator-dubbo into dev-metadata

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



[incubator-dubbo] 02/03: Demo and ut changes

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 44fb07fa4f16322fbed14013c4c9f358f95b2e28
Author: ken.lj <ke...@gmail.com>
AuthorDate: Wed Oct 17 14:07:22 2018 +0800

    Demo and ut changes
---
 .../cluster/router/ConfigConditionRouterTest.java  |  7 ++--
 .../dubbo/rpc/cluster/router/TagRouterTest.java    | 26 +++++++--------
 .../org/apache/dubbo/demo/consumer/Consumer.java   |  4 +--
 .../dubbo/demo/consumer/DemoServiceMock.java       | 39 ++++++++++++++++++++++
 .../META-INF/spring/dubbo-demo-consumer.xml        |  2 ++
 .../META-INF/spring/dubbo-demo-provider.xml        |  6 ++--
 6 files changed, 64 insertions(+), 20 deletions(-)

diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/ConfigConditionRouterTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/ConfigConditionRouterTest.java
index 416fac5..b545f8e 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/ConfigConditionRouterTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/ConfigConditionRouterTest.java
@@ -88,15 +88,16 @@ public class ConfigConditionRouterTest {
                 "scope: service\n" +
                 "force: true\n" +
                 "runtime: true\n" +
-                "enabled: false\n" +
+                "enabled: true\n" +
                 "priority: 1\n" +
-                "key: org.apache.dubbo.demo.DemoService\n" +
+                "key: org.apache.dubbo.demo.DemoService:1.0.2\n" +
                 "conditions:\n" +
                 "  - method!=sayHello =>\n" +
                 "  - method=routeMethod1 => address=30.5.120.37:20880\n" +
                 "...";
+//        String serviceStr = "";
         try {
-            String servicePath = "/dubbo/config/org.apache.dubbo.demo.DemoService/routers";
+            String servicePath = "/dubbo/config/org.apache.dubbo.demo.DemoService:1.0.2/routers";
             if (client.checkExists().forPath(servicePath) == null) {
                 client.create().creatingParentsIfNeeded().forPath(servicePath);
             }
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/TagRouterTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/TagRouterTest.java
index 26367c2..2f5d4a8 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/TagRouterTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/TagRouterTest.java
@@ -37,19 +37,19 @@ public class TagRouterTest {
 
     @Test
     public void normalTagRuleTest() {
-//        String serviceStr = "---\n" +
-//                "force: false\n" +
-//                "runtime: true\n" +
-//                "enabled: true\n" +
-//                "priority: 1\n" +
-//                "key: demo-provider\n" +
-//                "tags:\n" +
-//                "  - name: tag1\n" +
-//                "    addresses: [\"30.5.120.37:20880\"]\n" +
-//                "  - name: tag2\n" +
-//                "    addresses: [\"30.5.120.37:20880\"]\n" +
-//                "...";
-        String serviceStr = "";
+        String serviceStr = "---\n" +
+                "force: false\n" +
+                "runtime: true\n" +
+                "enabled: false\n" +
+                "priority: 1\n" +
+                "key: demo-provider\n" +
+                "tags:\n" +
+                "  - name: tag1\n" +
+                "    addresses: [\"30.5.120.37:20881\"]\n" +
+                "  - name: tag2\n" +
+                "    addresses: [\"30.5.120.37:20880\"]\n" +
+                "...";
+//        String serviceStr = "";
         try {
             String servicePath = "/dubbo/config/demo-provider/tagrouters";
             if (client.checkExists().forPath(servicePath) == null) {
diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java
index 62ff67a..80d3eff 100644
--- a/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java
+++ b/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java
@@ -34,10 +34,10 @@ public class Consumer {
         while (true) {
             try {
                 Thread.sleep(1000);
-                RpcContext.getContext().setAttachment("tag", "tag3");
+//                RpcContext.getContext().setAttachment("tag", "tag3");
                 String hello = demoService.sayHello("world"); // call remote method
                 System.out.println(hello); // get result
-                RpcContext.getContext().setAttachment("tag", "tag1");
+//                RpcContext.getContext().setAttachment("tag", "tag1");
 //                RpcContext.getContext().setAttachment("force.tag", "true");
                 String routeMethod1 = demoService.routeMethod1(); // call remote method
                 System.out.println(routeMethod1); // get result
diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/DemoServiceMock.java b/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/DemoServiceMock.java
new file mode 100644
index 0000000..3e405a3
--- /dev/null
+++ b/dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/DemoServiceMock.java
@@ -0,0 +1,39 @@
+/*
+ * 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.demo.consumer;
+
+import org.apache.dubbo.demo.DemoService;
+
+/**
+ *
+ */
+public class DemoServiceMock implements DemoService {
+    @Override
+    public String sayHello(String name) {
+        return "mock value";
+    }
+
+    @Override
+    public String routeMethod1() {
+        return null;
+    }
+
+    @Override
+    public String routeMethod2() {
+        return null;
+    }
+}
diff --git a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml
index 86472c5..f80ceb0 100644
--- a/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml
+++ b/dubbo-demo/dubbo-demo-consumer/src/main/resources/META-INF/spring/dubbo-demo-consumer.xml
@@ -26,9 +26,11 @@
     <dubbo:application name="demo-consumer">
         <dubbo:parameter key="config.type" value="zookeeper"/>
         <dubbo:parameter key="config.address" value="127.0.0.1:2181"/>
+        <dubbo:parameter key="config.check" value="true"/>
     </dubbo:application>
 
     <!-- use multicast registry center to discover service -->
+    <dubbo:registry address="zookeeper://127.0.0.1:2181" default="true"/>
     <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
 
     <dubbo:servicestore address="zookeeper://127.0.0.1:2181"/>
diff --git a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml
index 7604b32..66982ae 100644
--- a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml
+++ b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml
@@ -26,9 +26,11 @@
     <!--<dubbo:provider tag="tag3"/>-->
 
     <!-- use multicast registry center to export service -->
-    <dubbo:registry address="zookeeper://127.0.0.1:2181" simple="true" />
+    <dubbo:registry address="zookeeper://127.0.0.1:2181" simple="false">
+        <dubbo:parameter key="config.check" value="false"/>
+    </dubbo:registry>
 
-    <dubbo:servicestore address="redis://127.0.0.1:6379"/>
+    <dubbo:servicestore address="zookeeper://127.0.0.1:2181"/>
 
     <!-- use dubbo protocol to export service on port 20880 -->
     <dubbo:protocol name="dubbo" port="-1"/>


[incubator-dubbo] 01/03: Improvements for dynamic config and router: 1. support route in StaticDirectory, multi-registry & group merger 2. tolerance of abnormal configs from configserver. 3. add check policy when failed to connect to configserver

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 91fddde79a718b3223b5caa421c4112bf5744f69
Author: ken.lj <ke...@gmail.com>
AuthorDate: Wed Oct 17 14:05:47 2018 +0800

    Improvements for dynamic config and router:
    1. support route in StaticDirectory, multi-registry & group merger
    2. tolerance of abnormal configs from configserver.
    3. add check policy when failed to connect to configserver
---
 .../java/org/apache/dubbo/rpc/cluster/Router.java  |   4 +-
 .../org/apache/dubbo/rpc/cluster/RouterChain.java  |  14 +-
 .../rpc/cluster/directory/AbstractDirectory.java   |  11 +-
 .../rpc/cluster/directory/StaticDirectory.java     |  15 +-
 .../dubbo/rpc/cluster/router/AbstractRouter.java   |   5 +
 .../condition/config/ConfigConditionRouter.java    |  30 ++-
 .../router/{ => mock}/MockInvokersSelector.java    | 229 +++++++++------------
 .../rpc/cluster/router/mock/MockRouterFactory.java |  32 ++-
 .../dubbo/rpc/cluster/router/tag/TagRouter.java    |  13 +-
 .../cluster/support/AbstractClusterInvoker.java    |   6 +-
 .../dubbo/rpc/cluster/support/ClusterUtils.java    |   9 +-
 .../cluster/support/MergeableClusterInvoker.java   |  29 ++-
 .../rpc/cluster/support/RegistryAwareCluster.java  |  30 +--
 .../support/RegistryAwareClusterInvoker.java       |  59 ++++++
 .../internal/org.apache.dubbo.rpc.cluster.Cluster  |   3 +-
 .../org.apache.dubbo.rpc.cluster.RouterFactory     |   3 +-
 .../java/org/apache/dubbo/common/Constants.java    |   1 +
 .../dubbo/common/extension/ExtensionLoader.java    |   4 +
 .../org/apache/dubbo/config/ReferenceConfig.java   |   9 +-
 dubbo-config/dubbo-config-dynamic/pom.xml          |   2 +-
 .../dynamic/AbstractDynamicConfiguration.java      |   4 +-
 .../support/apollo/ApolloDynamicConfiguration.java |  49 ++---
 .../archaius/ArchaiusDynamicConfiguration.java     |   3 +-
 .../sources/ZooKeeperConfigurationSource.java      |  16 +-
 .../support/nop/NopDynamicConfiguration.java       |   2 +-
 .../registry/integration/RegistryDirectory.java    |  86 +++++---
 .../java/org/apache/dubbo/rpc/RpcException.java    |   5 +
 27 files changed, 375 insertions(+), 298 deletions(-)

diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java
index 65cf69f..3aaf298 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java
@@ -63,9 +63,7 @@ public interface Router extends Comparable<Router> {
         return "";
     }
 
-    default boolean isRuntime() {
-        return true;
-    }
+    boolean isRuntime();
 
     default String getKey() {
         return TreeNode.FAILOVER_KEY;
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java
index a1cb9d5..d5db399 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java
@@ -75,7 +75,7 @@ public class RouterChain<T> {
     /**
      * @param methodInvokers
      * @param url
-     * @param invocation     TODO has no been used yet
+     * @param invocation     TODO has not being used yet
      */
     public void preRoute(Map<String, List<Invoker<T>>> methodInvokers, URL url, Invocation invocation) {
         if (CollectionUtils.isEmpty(routers)) {
@@ -103,7 +103,7 @@ public class RouterChain<T> {
         });
     }
 
-    public List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) {
+    public List<Invoker<T>> route(URL url, Invocation invocation) {
         List<Invoker<T>> finalInvokers = treeCache.getInvokers(treeCache.getTree(), url, invocation);
         for (Router router : routers) {
             if (router.isRuntime()) {
@@ -113,6 +113,16 @@ public class RouterChain<T> {
         return finalInvokers;
     }
 
+    public List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) {
+        List<Invoker<T>> finalInvokers = invokers;
+        for (Router router : routers) {
+            if (router.isRuntime()) {
+                finalInvokers = router.route(invokers, url, invocation);
+            }
+        }
+        return finalInvokers;
+    }
+
     public void notifyRuleChanged() {
         preRoute(this.fullMethodInvokers, url, null);
     }
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
index 07e6dd3..2cee248 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
@@ -68,16 +68,7 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
             throw new RpcException("Directory already destroyed .url: " + getUrl());
         }
 
-        List<Invoker<T>> invokers = doList(invocation);
-
-        try {
-            // Get invokers from cache, only runtime routers will be executed.
-            return routerChain.route(invokers, getConsumerUrl(), invocation);
-        } catch (Throwable t) {
-            logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
-        }
-
-        return invokers;
+        return doList(invocation);
     }
 
     @Override
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
index 9367bdf..154fafe 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
@@ -17,6 +17,8 @@
 package org.apache.dubbo.rpc.cluster.directory;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.rpc.Invocation;
 import org.apache.dubbo.rpc.Invoker;
 import org.apache.dubbo.rpc.RpcException;
@@ -31,6 +33,7 @@ import java.util.List;
  *
  */
 public class StaticDirectory<T> extends AbstractDirectory<T> {
+    private static final Logger logger = LoggerFactory.getLogger(StaticDirectory.class);
 
     private final List<Invoker<T>> invokers;
 
@@ -85,8 +88,16 @@ public class StaticDirectory<T> extends AbstractDirectory<T> {
 
     @Override
     protected List<Invoker<T>> doList(Invocation invocation) throws RpcException {
-
-        return invokers;
+        List<Invoker<T>> finalInvokers = invokers;
+        if (routerChain != null) {
+            try {
+                // Get invokers from cache, only runtime routers will be executed.
+                finalInvokers = routerChain.route(getConsumerUrl(), invocation);
+            } catch (Throwable t) {
+                logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
+            }
+        }
+        return finalInvokers;
     }
 
 }
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/AbstractRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/AbstractRouter.java
index f814336..bb76236 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/AbstractRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/AbstractRouter.java
@@ -74,6 +74,11 @@ public abstract class AbstractRouter implements Router {
     }
 
     @Override
+    public boolean isRuntime() {
+        return true;
+    }
+
+    @Override
     public boolean isForce() {
         return force;
     }
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouter.java
index 8605afe..1d60ee3 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouter.java
@@ -72,23 +72,23 @@ public class ConfigConditionRouter extends AbstractRouter implements Configurati
                 generateAppConditions();
             }
         } catch (Exception e) {
-            throw new IllegalStateException(e.getMessage(), e);
+            throw new IllegalStateException("Failed to init the condition router.", e);
         }
     }
 
     @Override
     public void process(ConfigChangeEvent event) {
-        try {
-            if (event.getChangeType().equals(ConfigChangeType.DELETED)) {
-                // Now, we can only recognize if it's a app level or service level change by try to match event key.
-                if (event.getKey().endsWith(this.url.getParameter(Constants.APPLICATION_KEY) + Constants.ROUTERS_SUFFIX)) {
-                    appRouterRule = null;
-                    conditionRouters.clear();
-                } else {
-                    routerRule = null;
-                    appConditionRouters.clear();
-                }
+        if (event.getChangeType().equals(ConfigChangeType.DELETED)) {
+            // Now, we can only recognize if it's a app level or service level change by try to match event key.
+            if (event.getKey().endsWith(this.url.getParameter(Constants.APPLICATION_KEY) + Constants.ROUTERS_SUFFIX)) {
+                appRouterRule = null;
+                conditionRouters.clear();
             } else {
+                routerRule = null;
+                appConditionRouters.clear();
+            }
+        } else {
+            try {
                 if (event.getKey().endsWith(this.url.getParameter(Constants.APPLICATION_KEY) + Constants.ROUTERS_SUFFIX)) {
                     appRouterRule = ConditionRuleParser.parse(event.getNewValue());
                     generateAppConditions();
@@ -96,12 +96,11 @@ public class ConfigConditionRouter extends AbstractRouter implements Configurati
                     routerRule = ConditionRuleParser.parse(event.getNewValue());
                     generateConditions();
                 }
+            } catch (Exception e) {
+                logger.error("Failed to parse the raw condition rule and it will not take effect, please check if the condition rule matches with the template, the raw rule is:\n " + event.getNewValue(), e);
             }
-            routerChain.notifyRuleChanged();
-        } catch (Exception e) {
-            logger.error(e);
-            // TODO
         }
+        routerChain.notifyRuleChanged();
     }
 
     @Override
@@ -139,7 +138,6 @@ public class ConfigConditionRouter extends AbstractRouter implements Configurati
             return invokers;
         }
 
-
         if (isAppRuleEnabled()) {
             for (Router router : appConditionRouters) {
                 invokers = router.route(invokers, url, invocation);
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java
similarity index 76%
rename from dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java
rename to dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java
index f775f89..5dc954a 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java
@@ -1,133 +1,96 @@
-/*
- * 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.rpc.cluster.router;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Router;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A specific Router designed to realize mock feature.
- * If a request is configured to use mock, then this router guarantees that only the invokers with protocol MOCK appear in final the invoker list, all other invokers will be excluded.
- *
- */
-public class MockInvokersSelector implements Router {
-
-    @Override
-    public <T> List<Invoker<T>> route(final List<Invoker<T>> invokers,
-                                      URL url, final Invocation invocation) throws RpcException {
-        if (invocation.getAttachments() == null) {
-            return getNormalInvokers(invokers);
-        } else {
-            String value = invocation.getAttachments().get(Constants.INVOCATION_NEED_MOCK);
-            if (value == null)
-                return getNormalInvokers(invokers);
-            else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
-                return getMockedInvokers(invokers);
-            }
-        }
-        return invokers;
-    }
-
-    @Override
-    public <T> Map<String, List<Invoker<T>>> preRoute(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
-        Map<String, List<Invoker<T>>> map = new HashMap<>();
-
-        if (CollectionUtils.isEmpty(invokers)) {
-            return map;
-        }
-
-        if (isRuntime()) {
-            map.put(TreeNode.FAILOVER_KEY, invokers);
-            return map;
-        }
-        return map;
-    }
-
-    @Override
-    public boolean isRuntime() {
-        return true;
-    }
-
-    @Override
-    public String getKey() {
-        return TreeNode.FAILOVER_KEY;
-    }
-
-    @Override
-    public boolean isForce() {
-        return false;
-    }
-
-    private <T> List<Invoker<T>> getMockedInvokers(final List<Invoker<T>> invokers) {
-        if (!hasMockProviders(invokers)) {
-            return null;
-        }
-        List<Invoker<T>> sInvokers = new ArrayList<Invoker<T>>(1);
-        for (Invoker<T> invoker : invokers) {
-            if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
-                sInvokers.add(invoker);
-            }
-        }
-        return sInvokers;
-    }
-
-    private <T> List<Invoker<T>> getNormalInvokers(final List<Invoker<T>> invokers) {
-        if (!hasMockProviders(invokers)) {
-            return invokers;
-        } else {
-            List<Invoker<T>> sInvokers = new ArrayList<Invoker<T>>(invokers.size());
-            for (Invoker<T> invoker : invokers) {
-                if (!invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
-                    sInvokers.add(invoker);
-                }
-            }
-            return sInvokers;
-        }
-    }
-
-    private <T> boolean hasMockProviders(final List<Invoker<T>> invokers) {
-        boolean hasMockProvider = false;
-        for (Invoker<T> invoker : invokers) {
-            if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
-                hasMockProvider = true;
-                break;
-            }
-        }
-        return hasMockProvider;
-    }
-
-    @Override
-    public URL getUrl() {
-        return null;
-    }
-
-    @Override
-    public int compareTo(Router o) {
-        return 1;
-    }
-
-}
+/*
+ * 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.rpc.cluster.router.mock;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.router.AbstractRouter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A specific Router designed to realize mock feature.
+ * If a request is configured to use mock, then this router guarantees that only the invokers with protocol MOCK appear in final the invoker list, all other invokers will be excluded.
+ *
+ */
+public class MockInvokersSelector extends AbstractRouter {
+
+    @Override
+    public <T> List<Invoker<T>> route(final List<Invoker<T>> invokers,
+                                      URL url, final Invocation invocation) throws RpcException {
+        if (invocation.getAttachments() == null) {
+            return getNormalInvokers(invokers);
+        } else {
+            String value = invocation.getAttachments().get(Constants.INVOCATION_NEED_MOCK);
+            if (value == null)
+                return getNormalInvokers(invokers);
+            else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
+                return getMockedInvokers(invokers);
+            }
+        }
+        return invokers;
+    }
+
+    private <T> List<Invoker<T>> getMockedInvokers(final List<Invoker<T>> invokers) {
+        if (!hasMockProviders(invokers)) {
+            return null;
+        }
+        List<Invoker<T>> sInvokers = new ArrayList<Invoker<T>>(1);
+        for (Invoker<T> invoker : invokers) {
+            if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
+                sInvokers.add(invoker);
+            }
+        }
+        return sInvokers;
+    }
+
+    private <T> List<Invoker<T>> getNormalInvokers(final List<Invoker<T>> invokers) {
+        if (!hasMockProviders(invokers)) {
+            return invokers;
+        } else {
+            List<Invoker<T>> sInvokers = new ArrayList<Invoker<T>>(invokers.size());
+            for (Invoker<T> invoker : invokers) {
+                if (!invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
+                    sInvokers.add(invoker);
+                }
+            }
+            return sInvokers;
+        }
+    }
+
+    private <T> boolean hasMockProviders(final List<Invoker<T>> invokers) {
+        boolean hasMockProvider = false;
+        for (Invoker<T> invoker : invokers) {
+            if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
+                hasMockProvider = true;
+                break;
+            }
+        }
+        return hasMockProvider;
+    }
+
+    @Override
+    public int compareTo(Router o) {
+        return 1;
+    }
+
+}
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/nop/NopDynamicConfiguration.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockRouterFactory.java
similarity index 57%
copy from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/nop/NopDynamicConfiguration.java
copy to dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockRouterFactory.java
index 75e8bf9..79b9b99 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/nop/NopDynamicConfiguration.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockRouterFactory.java
@@ -14,33 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.dynamic.support.nop;
+package org.apache.dubbo.rpc.cluster.router.mock;
 
-import org.apache.dubbo.config.dynamic.AbstractDynamicConfiguration;
-import org.apache.dubbo.config.dynamic.ConfigurationListener;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.dynamic.DynamicConfiguration;
+import org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.RouterFactory;
 
 /**
  *
  */
-public class NopDynamicConfiguration extends AbstractDynamicConfiguration {
+@Activate
+public class MockRouterFactory implements RouterFactory {
 
     @Override
-    public void init() {
-
-    }
-
-    @Override
-    protected String getInternalProperty(String key, String group, long timeout, ConfigurationListener listener) {
-        return null;
-    }
-
-    @Override
-    protected void addTargetListener(String key, Object o) {
-
+    public Router getRouter(URL url) {
+        return new MockInvokersSelector();
     }
 
     @Override
-    protected Object createTargetConfigListener(String key, ConfigurationListener listener) {
-        return null;
+    public Router getRouter(DynamicConfiguration dynamicConfiguration, URL url) {
+        return getRouter(url);
     }
-}
+}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java
index c970974..4aadc82 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java
@@ -77,9 +77,13 @@ public class TagRouter extends AbstractRouter implements Comparable<Router>, Con
         if (StringUtils.isEmpty(application)) {
             logger.error("TagRouter must getConfig from or subscribe to a specific application, but the application in this TagRouter is not specified.");
         }
-        String rawRule = this.configuration.getConfig(application + TAGROUTERRULES_DATAID, "dubbo", this);
-        if (StringUtils.isNotEmpty(rawRule)) {
-            this.tagRouterRule = TagRuleParser.parse(rawRule);
+        try {
+            String rawRule = this.configuration.getConfig(application + TAGROUTERRULES_DATAID, "dubbo", this);
+            if (StringUtils.isNotEmpty(rawRule)) {
+                this.tagRouterRule = TagRuleParser.parse(rawRule);
+            }
+        } catch (Exception e) {
+            logger.error("Failed to parse the raw tag router rule and it will not take effect, please check if the rule matches with the template, the raw rule is:\n ", e);
         }
     }
 
@@ -93,8 +97,7 @@ public class TagRouter extends AbstractRouter implements Comparable<Router>, Con
             }
             routerChain.notifyRuleChanged();
         } catch (Exception e) {
-            // TODO
-            logger.error(e);
+            logger.error("Failed to parse the raw tag router rule and it will not take effect, please check if the rule matches with the template, the raw rule is:\n ", e);
         }
     }
 
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
index 51fe092..92d2ee7 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
@@ -26,10 +26,10 @@ import org.apache.dubbo.common.utils.CollectionUtils;
 import org.apache.dubbo.common.utils.NetUtils;
 import org.apache.dubbo.rpc.Invocation;
 import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcContext;
-import org.apache.dubbo.rpc.RpcInvocation;
 import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcContext;
 import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.RpcInvocation;
 import org.apache.dubbo.rpc.cluster.Directory;
 import org.apache.dubbo.rpc.cluster.LoadBalance;
 import org.apache.dubbo.rpc.support.RpcUtils;
@@ -254,7 +254,7 @@ public abstract class AbstractClusterInvoker<T> implements Invoker<T> {
 
     protected void checkInvokers(List<Invoker<T>> invokers, Invocation invocation) {
         if (invokers == null || invokers.isEmpty()) {
-            throw new RpcException("Failed to invoke the method "
+            throw new RpcException(RpcException.NO_INVOKER_AVAILABLE_AFTER_FILTER, "Failed to invoke the method "
                     + invocation.getMethodName() + " in the service " + getInterface().getName()
                     + ". No provider available for the service " + directory.getUrl().getServiceKey()
                     + " from registry " + directory.getUrl().getAddress()
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
index 1c62d9f..5b4b589 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
@@ -35,7 +35,6 @@ public class ClusterUtils {
         Map<String, String> map = new HashMap<String, String>();
         Map<String, String> remoteMap = remoteUrl.getParameters();
 
-
         if (remoteMap != null && remoteMap.size() > 0) {
             map.putAll(remoteMap);
 
@@ -66,6 +65,10 @@ public class ClusterUtils {
         }
 
         if (localMap != null && localMap.size() > 0) {
+            // All providers come to here have been filtered by group, which means only those providers that have the exact same group value with the consumer could come to here.
+            // So, generally, we don't need to care about the group value here.
+            // But when comes to group merger, there is an exception, the consumer group may be '*' while the provider group can be empty or any other values.
+            localMap.remove(Constants.GROUP_KEY);
             map.putAll(localMap);
         }
         if (remoteMap != null && remoteMap.size() > 0) {
@@ -78,10 +81,6 @@ public class ClusterUtils {
             if (version != null && version.length() > 0) {
                 map.put(Constants.VERSION_KEY, version);
             }
-            String group = remoteMap.get(Constants.GROUP_KEY);
-            if (group != null && group.length() > 0) {
-                map.put(Constants.GROUP_KEY, group);
-            }
             String methods = remoteMap.get(Constants.METHODS_KEY);
             if (methods != null && methods.length() > 0) {
                 map.put(Constants.METHODS_KEY, methods);
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java
index 0c68eab..82a0e8a 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/MergeableClusterInvoker.java
@@ -30,6 +30,7 @@ import org.apache.dubbo.rpc.RpcException;
 import org.apache.dubbo.rpc.RpcInvocation;
 import org.apache.dubbo.rpc.RpcResult;
 import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
 import org.apache.dubbo.rpc.cluster.Merger;
 import org.apache.dubbo.rpc.cluster.merger.MergerFactory;
 
@@ -47,26 +48,31 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
 @SuppressWarnings("unchecked")
-public class MergeableClusterInvoker<T> implements Invoker<T> {
+public class MergeableClusterInvoker<T> extends AbstractClusterInvoker<T> {
 
     private static final Logger log = LoggerFactory.getLogger(MergeableClusterInvoker.class);
-    private final Directory<T> directory;
     private ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("mergeable-cluster-executor", true));
 
     public MergeableClusterInvoker(Directory<T> directory) {
-        this.directory = directory;
+        super(directory);
     }
 
     @Override
-    @SuppressWarnings("rawtypes")
-    public Result invoke(final Invocation invocation) throws RpcException {
-        List<Invoker<T>> invokers = directory.list(invocation);
-
+    protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
+        checkInvokers(invokers, invocation);
         String merger = getUrl().getMethodParameter(invocation.getMethodName(), Constants.MERGER_KEY);
         if (ConfigUtils.isEmpty(merger)) { // If a method doesn't have a merger, only invoke one Group
             for (final Invoker<T> invoker : invokers) {
                 if (invoker.isAvailable()) {
-                    return invoker.invoke(invocation);
+                    try {
+                        return invoker.invoke(invocation);
+                    } catch (RpcException e) {
+                        if (e.isNoInvokerAvailableAfterFilter()) {
+                            log.debug("No available provider for service" + directory.getUrl().getServiceKey() + " on group " + invoker.getUrl().getParameter(Constants.GROUP_KEY) + ", will continue to try another group.");
+                        } else {
+                            throw e;
+                        }
+                    }
                 }
             }
             return invokers.iterator().next().invoke(invocation);
@@ -101,8 +107,8 @@ public class MergeableClusterInvoker<T> implements Invoker<T> {
             try {
                 Result r = future.get(timeout, TimeUnit.MILLISECONDS);
                 if (r.hasException()) {
-                    log.error("Invoke " + getGroupDescFromServiceKey(entry.getKey()) + 
-                                    " failed: " + r.getException().getMessage(), 
+                    log.error("Invoke " + getGroupDescFromServiceKey(entry.getKey()) +
+                                    " failed: " + r.getException().getMessage(),
                             r.getException());
                 } else {
                     resultList.add(r);
@@ -128,7 +134,7 @@ public class MergeableClusterInvoker<T> implements Invoker<T> {
             try {
                 method = returnType.getMethod(merger, returnType);
             } catch (NoSuchMethodException e) {
-                throw new RpcException("Can not merge result because missing method [ " + merger + " ] in class [ " + 
+                throw new RpcException("Can not merge result because missing method [ " + merger + " ] in class [ " +
                         returnType.getClass().getName() + " ]");
             }
             if (!Modifier.isPublic(method.getModifiers())) {
@@ -170,6 +176,7 @@ public class MergeableClusterInvoker<T> implements Invoker<T> {
         return new RpcResult(result);
     }
 
+
     @Override
     public Class<T> getInterface() {
         return directory.getInterface();
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/nop/NopDynamicConfiguration.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/RegistryAwareCluster.java
similarity index 55%
copy from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/nop/NopDynamicConfiguration.java
copy to dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/RegistryAwareCluster.java
index 75e8bf9..81b21a3 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/nop/NopDynamicConfiguration.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/RegistryAwareCluster.java
@@ -14,33 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.dynamic.support.nop;
+package org.apache.dubbo.rpc.cluster.support;
 
-import org.apache.dubbo.config.dynamic.AbstractDynamicConfiguration;
-import org.apache.dubbo.config.dynamic.ConfigurationListener;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.Directory;
 
 /**
  *
  */
-public class NopDynamicConfiguration extends AbstractDynamicConfiguration {
+public class RegistryAwareCluster implements Cluster {
 
-    @Override
-    public void init() {
-
-    }
+    public final static String NAME = "registryaware";
 
     @Override
-    protected String getInternalProperty(String key, String group, long timeout, ConfigurationListener listener) {
-        return null;
+    public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+        return new RegistryAwareClusterInvoker<T>(directory);
     }
 
-    @Override
-    protected void addTargetListener(String key, Object o) {
-
-    }
-
-    @Override
-    protected Object createTargetConfigListener(String key, ConfigurationListener listener) {
-        return null;
-    }
-}
+}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/RegistryAwareClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/RegistryAwareClusterInvoker.java
new file mode 100644
index 0000000..dfd8156
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/RegistryAwareClusterInvoker.java
@@ -0,0 +1,59 @@
+/*
+ * 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.rpc.cluster.support;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+
+import java.util.List;
+
+/**
+ *
+ */
+public class RegistryAwareClusterInvoker<T> extends AbstractClusterInvoker<T> {
+
+    private static final Logger logger = LoggerFactory.getLogger(RegistryAwareClusterInvoker.class);
+
+    public RegistryAwareClusterInvoker(Directory<T> directory) {
+        super(directory);
+    }
+
+    @Override
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
+        // First, pick the invoker (XXXClusterInvoker) that comes from the local registry, distinguish by a 'default' key.
+        for (Invoker<T> invoker : invokers) {
+            if (invoker.getUrl().getParameter(Constants.REGISTRY_KEY + "." + Constants.DEFAULT_KEY, false)) {
+                return invoker.invoke(invocation);
+            }
+        }
+        // If none of the invokers has a local signal, pick the first one available.
+        for (Invoker<T> invoker : invokers) {
+            if (invoker.isAvailable()) {
+                return invoker.invoke(invocation);
+            }
+        }
+        throw new RpcException("No provider available in " + invokers);
+    }
+}
diff --git a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster
index ef212d7..ba30247 100644
--- a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster
+++ b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster
@@ -6,4 +6,5 @@ failback=org.apache.dubbo.rpc.cluster.support.FailbackCluster
 forking=org.apache.dubbo.rpc.cluster.support.ForkingCluster
 available=org.apache.dubbo.rpc.cluster.support.AvailableCluster
 mergeable=org.apache.dubbo.rpc.cluster.support.MergeableCluster
-broadcast=org.apache.dubbo.rpc.cluster.support.BroadcastCluster
\ No newline at end of file
+broadcast=org.apache.dubbo.rpc.cluster.support.BroadcastCluster
+registryaware=org.apache.dubbo.rpc.cluster.support.RegistryAwareCluster
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory
index 3c36311..4a27434 100644
--- a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory
+++ b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory
@@ -2,4 +2,5 @@ file=org.apache.dubbo.rpc.cluster.router.file.FileRouterFactory
 script=org.apache.dubbo.rpc.cluster.router.script.ScriptRouterFactory
 condition=org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory
 configcondition=org.apache.dubbo.rpc.cluster.router.condition.config.ConfigConditionRouterFactory
-tag=org.apache.dubbo.rpc.cluster.router.tag.TagRouterFactory
\ No newline at end of file
+tag=org.apache.dubbo.rpc.cluster.router.tag.TagRouterFactory
+mock=org.apache.dubbo.rpc.cluster.router.mock.MockRouterFactory
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
index 49b0bd1..8b99c9d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
@@ -61,6 +61,7 @@ public class Constants {
     public static final String CONFIG_ENV_KEY = "config.env";
     public static final String CONFIG_CLUSTER_KEY = "config.cluster";
     public static final String CONFIG_NAMESPACE_KEY = "config.namespace";
+    public static final String CONFIG_CHECK_KEY = "config.check";
 
     public static final String DEFAULT_CATEGORY = PROVIDERS_CATEGORY;
 
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
index 10e9fbb..e402a21 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
@@ -24,6 +24,7 @@ import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.ConcurrentHashSet;
 import org.apache.dubbo.common.utils.ConfigUtils;
 import org.apache.dubbo.common.utils.Holder;
+import org.apache.dubbo.common.utils.ReflectUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 
 import java.io.BufferedReader;
@@ -528,6 +529,9 @@ public class ExtensionLoader<T> {
                             && method.getParameterTypes().length == 1
                             && Modifier.isPublic(method.getModifiers())) {
                         Class<?> pt = method.getParameterTypes()[0];
+                        if (ReflectUtils.isPrimitives(pt)) {
+                            continue;
+                        }
                         try {
                             String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                             Object object = objectFactory.getExtension(pt, property);
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index 43e3ca0..b6cea16 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
@@ -36,8 +36,8 @@ import org.apache.dubbo.rpc.ProxyFactory;
 import org.apache.dubbo.rpc.StaticContext;
 import org.apache.dubbo.rpc.cluster.Cluster;
 import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
-import org.apache.dubbo.rpc.cluster.support.AvailableCluster;
 import org.apache.dubbo.rpc.cluster.support.ClusterUtils;
+import org.apache.dubbo.rpc.cluster.support.RegistryAwareCluster;
 import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;
 import org.apache.dubbo.rpc.service.GenericService;
 import org.apache.dubbo.rpc.support.ProtocolUtils;
@@ -404,10 +404,11 @@ public class ReferenceConfig<T> extends AbstractReferenceConfig {
                     }
                 }
                 if (registryURL != null) { // registry url is available
-                    // use AvailableCluster only when register's cluster is available
-                    URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME);
+                    // use RegistryAwareCluster only when register's cluster is available
+                    URL u = registryURL.addParameter(Constants.CLUSTER_KEY, RegistryAwareCluster.NAME);
+                    // The invoker wrap relation would be: RegistryAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, will execute route) -> Invoker
                     invoker = cluster.join(new StaticDirectory(u, invokers));
-                } else { // not a registry url
+                } else { // not a registry url, must be direct invoke.
                     invoker = cluster.join(new StaticDirectory(invokers));
                 }
             }
diff --git a/dubbo-config/dubbo-config-dynamic/pom.xml b/dubbo-config/dubbo-config-dynamic/pom.xml
index 3243be6..b08bc84 100644
--- a/dubbo-config/dubbo-config-dynamic/pom.xml
+++ b/dubbo-config/dubbo-config-dynamic/pom.xml
@@ -43,7 +43,7 @@
         <dependency>
             <groupId>com.ctrip.framework.apollo</groupId>
             <artifactId>apollo-client</artifactId>
-            <version>1.0.0</version>
+            <version>1.1.1</version>
         </dependency>
         <dependency>
             <groupId>com.netflix.archaius</groupId>
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/AbstractDynamicConfiguration.java b/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/AbstractDynamicConfiguration.java
index 5b8a189..a75db46 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/AbstractDynamicConfiguration.java
+++ b/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/AbstractDynamicConfiguration.java
@@ -57,7 +57,7 @@ public abstract class AbstractDynamicConfiguration<TargetConfigListener> impleme
             if (listener != null) {
                 this.addListener(key, listener);
             }
-            return getInternalProperty(key, group, timeout, listener);
+            return getInternalProperty(key, group, timeout);
         } catch (Exception e) {
             throw new IllegalStateException(e.getMessage(), e);
         }
@@ -71,7 +71,7 @@ public abstract class AbstractDynamicConfiguration<TargetConfigListener> impleme
         this.url = url;
     }
 
-    protected abstract String getInternalProperty(String key, String group, long timeout, ConfigurationListener listener);
+    protected abstract String getInternalProperty(String key, String group, long timeout);
 
     protected abstract void addTargetListener(String key, TargetConfigListener listener);
 
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/apollo/ApolloDynamicConfiguration.java b/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/apollo/ApolloDynamicConfiguration.java
index 489bf47..a70b113 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/apollo/ApolloDynamicConfiguration.java
+++ b/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/apollo/ApolloDynamicConfiguration.java
@@ -19,11 +19,14 @@ package org.apache.dubbo.config.dynamic.support.apollo;
 import com.ctrip.framework.apollo.Config;
 import com.ctrip.framework.apollo.ConfigChangeListener;
 import com.ctrip.framework.apollo.ConfigService;
+import com.ctrip.framework.apollo.enums.ConfigSourceType;
 import com.ctrip.framework.apollo.enums.PropertyChangeType;
 import com.ctrip.framework.apollo.model.ConfigChange;
 import com.ctrip.framework.apollo.model.ConfigChangeEvent;
 import org.apache.dubbo.common.Constants;
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.dynamic.AbstractDynamicConfiguration;
 import org.apache.dubbo.config.dynamic.ConfigChangeType;
@@ -37,15 +40,13 @@ import java.util.Set;
  *
  */
 public class ApolloDynamicConfiguration extends AbstractDynamicConfiguration<ConfigChangeListener> {
+    private static final Logger logger = LoggerFactory.getLogger(ApolloDynamicConfiguration.class);
     private static final String APOLLO_ENV_KEY = "env";
     private static final String APOLLO_ADDR_KEY = "apollo.meta";
     private static final String APOLLO_CLUSTER_KEY = "apollo.cluster";
     private static final String APPLO_DEFAULT_NAMESPACE = "dubbo";
-    /**
-     * support two namespaces: application -> dubbo
-     */
+
     private Config dubboConfig;
-    private Config appConfig;
 
     public ApolloDynamicConfiguration() {
 
@@ -72,33 +73,28 @@ public class ApolloDynamicConfiguration extends AbstractDynamicConfiguration<Con
         }
 
         dubboConfig = ConfigService.getConfig(url.getParameter(Constants.CONFIG_NAMESPACE_KEY, APPLO_DEFAULT_NAMESPACE));
-        appConfig = ConfigService.getAppConfig();
-    }
-
-    @Override
-    public void addListener(String key, ConfigurationListener listener) {
-        Set<String> keys = new HashSet<>(1);
-        keys.add(key);
-        this.appConfig.addChangeListener(new ApolloListener(listener), keys);
-        this.dubboConfig.addChangeListener(new ApolloListener(listener), keys);
+        // Decide to fail or to continue when failed to connect to remote server.
+        boolean check = url.getParameter(Constants.CONFIG_CHECK_KEY, false);
+        if (dubboConfig.getSourceType() != ConfigSourceType.REMOTE) {
+            if (check) {
+                throw new IllegalStateException("Failed to connect to ConfigCenter, the ConfigCenter is Apollo, the address is: " + (StringUtils.isNotEmpty(configAddr) ? configAddr : configEnv));
+            } else {
+                logger.warn("Failed to connect to ConfigCenter, the ConfigCenter is Apollo, " +
+                        "the address is: " + (StringUtils.isNotEmpty(configAddr) ? configAddr : configEnv) +
+                        ". will use the local cache value instead before finally connected.");
+            }
+        }
     }
 
     @Override
-    protected String getInternalProperty(String key, String group, long timeout, ConfigurationListener listener) {
-        // FIXME According to Apollo, if it fails to get a value from one namespace, it will keep logging warning msg. They are working to improve it.
-        String value = appConfig.getProperty(key, null);
-        if (value == null) {
-            value = dubboConfig.getProperty(key, null);
-        }
-
-        return value;
+    protected String getInternalProperty(String key, String group, long timeout) {
+        return dubboConfig.getProperty(key, null);
     }
 
     @Override
     protected void addTargetListener(String key, ConfigChangeListener listener) {
         Set<String> keys = new HashSet<>(1);
         keys.add(key);
-        this.appConfig.addChangeListener(listener, keys);
         this.dubboConfig.addChangeListener(listener, keys);
     }
 
@@ -107,8 +103,8 @@ public class ApolloDynamicConfiguration extends AbstractDynamicConfiguration<Con
         return new ApolloListener(listener);
     }
 
-    public ConfigChangeType getChangeType(PropertyChangeType changeType) {
-        if (changeType.equals(PropertyChangeType.DELETED)) {
+    public ConfigChangeType getChangeType(ConfigChange change) {
+        if (change.getChangeType() == PropertyChangeType.DELETED || StringUtils.isEmpty(change.getNewValue())) {
             return ConfigChangeType.DELETED;
         }
         return ConfigChangeType.MODIFIED;
@@ -127,16 +123,15 @@ public class ApolloDynamicConfiguration extends AbstractDynamicConfiguration<Con
             this.listener = listener;
         }
 
-        // FIXME will Apollo consider an empty value "" as deleted?
         @Override
         public void onChange(ConfigChangeEvent changeEvent) {
             for (String key : changeEvent.changedKeys()) {
                 ConfigChange change = changeEvent.getChange(key);
                 // TODO Maybe we no longer need to identify the type of change. Because there's no scenario that a callback will subscribe for both configurators and routers
                 if (change.getPropertyName().endsWith(Constants.CONFIGURATORS_SUFFIX)) {
-                    listener.process(new org.apache.dubbo.config.dynamic.ConfigChangeEvent(key, change.getNewValue(), ConfigType.CONFIGURATORS, getChangeType(change.getChangeType())));
+                    listener.process(new org.apache.dubbo.config.dynamic.ConfigChangeEvent(key, change.getNewValue(), ConfigType.CONFIGURATORS, getChangeType(change)));
                 } else {
-                    listener.process(new org.apache.dubbo.config.dynamic.ConfigChangeEvent(key, change.getNewValue(), ConfigType.ROUTERS, getChangeType(change.getChangeType())));
+                    listener.process(new org.apache.dubbo.config.dynamic.ConfigChangeEvent(key, change.getNewValue(), ConfigType.ROUTERS, getChangeType(change)));
                 }
             }
         }
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/archaius/ArchaiusDynamicConfiguration.java b/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/archaius/ArchaiusDynamicConfiguration.java
index feb177a..6639584 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/archaius/ArchaiusDynamicConfiguration.java
+++ b/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/archaius/ArchaiusDynamicConfiguration.java
@@ -48,6 +48,7 @@ public class ArchaiusDynamicConfiguration extends AbstractDynamicConfiguration<R
             System.setProperty(ZooKeeperConfigurationSource.ARCHAIUS_SOURCE_ADDRESS_KEY, address);
         }
         System.setProperty(ZooKeeperConfigurationSource.ARCHAIUS_CONFIG_ROOT_PATH_KEY, url.getParameter(Constants.CONFIG_NAMESPACE_KEY, ZooKeeperConfigurationSource.DEFAULT_CONFIG_ROOT_PATH));
+        System.setProperty(ZooKeeperConfigurationSource.ARCHAIUS_CONFIG_CHECK_KEY, url.getParameter(Constants.CONFIG_CHECK_KEY, "false"));
 
         try {
             ZooKeeperConfigurationSource zkConfigSource = new ZooKeeperConfigurationSource();
@@ -63,7 +64,7 @@ public class ArchaiusDynamicConfiguration extends AbstractDynamicConfiguration<R
     }
 
     @Override
-    protected String getInternalProperty(String key, String group, long timeout, ConfigurationListener listener) {
+    protected String getInternalProperty(String key, String group, long timeout) {
         return DynamicPropertyFactory.getInstance()
                 .getStringProperty(key, null)
                 .get();
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/archaius/sources/ZooKeeperConfigurationSource.java b/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/archaius/sources/ZooKeeperConfigurationSource.java
index 41d6861..fdfcba7 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/archaius/sources/ZooKeeperConfigurationSource.java
+++ b/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/archaius/sources/ZooKeeperConfigurationSource.java
@@ -48,6 +48,7 @@ import java.util.concurrent.TimeUnit;
 public class ZooKeeperConfigurationSource implements WatchedConfigurationSource, Closeable {
     public static final String ARCHAIUS_SOURCE_ADDRESS_KEY = "archaius.zk.address";
     public static final String ARCHAIUS_CONFIG_ROOT_PATH_KEY = "archaius.zk.rootpath";
+    public static final String ARCHAIUS_CONFIG_CHECK_KEY = "archaius.zk.check";
     public static final String DEFAULT_CONFIG_ROOT_PATH = "/dubbo/config";
 
     private static final Logger logger = LoggerFactory.getLogger(com.netflix.config.source.ZooKeeperConfigurationSource.class);
@@ -63,7 +64,7 @@ public class ZooKeeperConfigurationSource implements WatchedConfigurationSource,
     private List<WatchedUpdateListener> listeners = new CopyOnWriteArrayList<WatchedUpdateListener>();
 
     public ZooKeeperConfigurationSource() {
-        this(System.getProperty(ARCHAIUS_SOURCE_ADDRESS_KEY), 60 * 1000, 60 * 1000, System.getProperty(ARCHAIUS_CONFIG_ROOT_PATH_KEY, DEFAULT_CONFIG_ROOT_PATH));
+        this(System.getProperty(ARCHAIUS_SOURCE_ADDRESS_KEY), 60 * 1000, 10000, System.getProperty(ARCHAIUS_CONFIG_ROOT_PATH_KEY, DEFAULT_CONFIG_ROOT_PATH));
     }
 
     public ZooKeeperConfigurationSource(int sessionTimeout, int connectTimeout, String configRootPath) {
@@ -80,12 +81,17 @@ public class ZooKeeperConfigurationSource implements WatchedConfigurationSource,
                 new ExponentialBackoffRetry(1000, 3));
         client.start();
         try {
-            connected = client.blockUntilConnected(connectTimeout * 4, TimeUnit.MILLISECONDS);
+            connected = client.blockUntilConnected(connectTimeout, TimeUnit.MILLISECONDS);
             if (!connected) {
-                logger.warn("Cannot connect to ConfigCenter at zookeeper " + connectString + " in " + connectTimeout * 4 + "ms");
+                boolean check = Boolean.parseBoolean(System.getProperty(ARCHAIUS_CONFIG_CHECK_KEY, "false"));
+                if (check) {
+                    throw new IllegalStateException("Failed to connect to ConfigCenter Zookeeper : " + connectString + " in " + connectTimeout + "ms.");
+                } else {
+                    logger.warn("Cannot connect to ConfigCenter at zookeeper " + connectString + " in " + connectTimeout + "ms");
+                }
             }
         } catch (InterruptedException e) {
-            logger.error("The thread was interrupted unexpectedly when try connecting to zookeeper " + connectString + " as ConfigCenter, ", e);
+            throw new IllegalStateException("The thread was interrupted unexpectedly when try connecting to zookeeper " + connectString + " as ConfigCenter, ", e);
         }
         this.client = client;
         this.configRootPath = configRootPath;
@@ -181,7 +187,7 @@ public class ZooKeeperConfigurationSource implements WatchedConfigurationSource,
         Map<String, Object> all = new HashMap<>();
 
         if (!connected) {
-            logger.warn("ConfigServer is not connected yet, zookeeper don't support local snapshot yet, so there's no old data to use!");
+            logger.warn("ConfigCenter is not connected yet, zookeeper don't support local snapshot yet, so there's no old data to use!");
             return all;
         }
 
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/nop/NopDynamicConfiguration.java b/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/nop/NopDynamicConfiguration.java
index 75e8bf9..83f475e 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/nop/NopDynamicConfiguration.java
+++ b/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/support/nop/NopDynamicConfiguration.java
@@ -30,7 +30,7 @@ public class NopDynamicConfiguration extends AbstractDynamicConfiguration {
     }
 
     @Override
-    protected String getInternalProperty(String key, String group, long timeout, ConfigurationListener listener) {
+    protected String getInternalProperty(String key, String group, long timeout) {
         return null;
     }
 
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
index c3403df..0270e96 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
@@ -53,7 +53,6 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -116,13 +115,22 @@ public class RegistryDirectory<T> extends AbstractDirectory<T> implements Notify
         this.serviceType = serviceType;
         this.serviceKey = url.getServiceKey();
         this.queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY));
-        this.overrideDirectoryUrl = this.directoryUrl = url.setPath(url.getServiceInterface()).clearParameters().addParameters(queryMap).removeParameter(Constants.MONITOR_KEY);
+        this.overrideDirectoryUrl = this.directoryUrl = turnRegistryUrlToConsumerUrl(url);
         String group = directoryUrl.getParameter(Constants.GROUP_KEY, "");
         this.multiGroup = group != null && ("*".equals(group) || group.contains(","));
         String methods = queryMap.get(Constants.METHODS_KEY);
         this.serviceMethods = methods == null ? null : Constants.COMMA_SPLIT_PATTERN.split(methods);
     }
 
+    private URL turnRegistryUrlToConsumerUrl(URL url) {
+        // save any parameter in registry that will be useful to the new url.
+        String isDefault = url.getParameter(Constants.DEFAULT_KEY);
+        if (StringUtils.isNotEmpty(isDefault)) {
+            queryMap.put(Constants.REGISTRY_KEY + "." + Constants.DEFAULT_KEY, isDefault);
+        }
+        return url.setPath(url.getServiceInterface()).clearParameters().addParameters(queryMap).removeParameter(Constants.MONITOR_KEY);
+    }
+
     /**
      * Convert override urls to map for use when re-refer.
      * Send all rules every time, the urls will be reassembled and calculated
@@ -176,14 +184,24 @@ public class RegistryDirectory<T> extends AbstractDirectory<T> implements Notify
 
     public void subscribe(URL url) {
         setConsumerUrl(url);
-        String rawConfig = dynamicConfiguration.getConfig(url.getServiceKey() + Constants.CONFIGURATORS_SUFFIX, "dubbo", this);
-        String rawConfigApp = dynamicConfiguration.getConfig(url.getParameter(Constants.APPLICATION_KEY) + Constants.CONFIGURATORS_SUFFIX, "dubbo", this);
-
-        if (StringUtils.isNotEmpty(rawConfig)) {
-            this.dynamicConfigurators = configToConfiguratiors(rawConfig);
+        String rawConfig = null;
+        try {
+            rawConfig = dynamicConfiguration.getConfig(url.getServiceKey() + Constants.CONFIGURATORS_SUFFIX, "dubbo", this);
+            if (StringUtils.isNotEmpty(rawConfig)) {
+                this.dynamicConfigurators = configToConfiguratiors(rawConfig);
+            }
+        } catch (Exception e) {
+            logger.error("Failed to load or parse dynamic config (service level), the raw config is: " + rawConfig, e);
         }
-        if (StringUtils.isNotEmpty(rawConfigApp)) {
-            this.appDynamicConfigurators = configToConfiguratiors(rawConfigApp);
+
+        String rawConfigApp = null;
+        try {
+            rawConfigApp = dynamicConfiguration.getConfig(url.getParameter(Constants.APPLICATION_KEY) + Constants.CONFIGURATORS_SUFFIX, "dubbo", this);
+            if (StringUtils.isNotEmpty(rawConfigApp)) {
+                this.appDynamicConfigurators = configToConfiguratiors(rawConfigApp);
+            }
+        } catch (Exception e) {
+            logger.error("Failed to load or parse dynamic config (application level), the raw config is: " + rawConfigApp, e);
         }
 
         registry.subscribe(url, this);
@@ -306,10 +324,12 @@ public class RegistryDirectory<T> extends AbstractDirectory<T> implements Notify
                 logger.error(new IllegalStateException("urls to invokers error .invokerUrls.size :" + invokerUrls.size() + ", invoker.size :0. urls :" + invokerUrls.toString()));
                 return;
             }
+            // pre-route and build cache, notice that route cache should build on original Invoker list.
+            // toMergeMethodInvokerMap() will wrap some invokers having different groups, those wrapped invokers should be routed.
+            routerChain.notifyFullInvokers(newMethodInvokerMap, getConsumerUrl());
             this.methodInvokerMap = multiGroup ? toMergeMethodInvokerMap(newMethodInvokerMap) : newMethodInvokerMap;
             this.urlInvokerMap = newUrlInvokerMap;
-            // Route and build cache
-            routerChain.notifyFullInvokers(methodInvokerMap, getConsumerUrl());
+
             try {
                 destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap); // Close the unused Invoker
             } catch (Exception e) {
@@ -338,7 +358,9 @@ public class RegistryDirectory<T> extends AbstractDirectory<T> implements Notify
             } else if (groupMap.size() > 1) {
                 List<Invoker<T>> groupInvokers = new ArrayList<Invoker<T>>();
                 for (List<Invoker<T>> groupList : groupMap.values()) {
-                    groupInvokers.add(cluster.join(new StaticDirectory<T>(groupList)));
+                    StaticDirectory<T> staticDirectory = new StaticDirectory<>(groupList);
+                    staticDirectory.setRouterChain(routerChain);
+                    groupInvokers.add(cluster.join(staticDirectory));
                 }
                 result.put(method, groupInvokers);
             } else {
@@ -624,18 +646,27 @@ public class RegistryDirectory<T> extends AbstractDirectory<T> implements Notify
                     "No provider available from registry " + getUrl().getAddress() + " for service " + getConsumerUrl().getServiceKey() + " on consumer " + NetUtils.getLocalHost()
                             + " use dubbo version " + Version.getVersion() + ", please check status of providers(disabled, not registered or in blacklist).");
         }
+
+        if (multiGroup) {
+            Map<String, List<Invoker<T>>> localMethodInvokerMap = this.methodInvokerMap; // local reference
+            String methodName = RpcUtils.getMethodName(invocation);
+            return localMethodInvokerMap.get(methodName);
+        }
+
         List<Invoker<T>> invokers = null;
-        Map<String, List<Invoker<T>>> localMethodInvokerMap = this.methodInvokerMap; // local reference
+        try {
+            // Get invokers from cache, only runtime routers will be executed.
+            invokers = routerChain.route(getConsumerUrl(), invocation);
+        } catch (Throwable t) {
+            logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
+        }
+
+
+        // FIXME Is there any need of failing back to Constants.ANY_VALUE or the first available method invokers when invokers is null?
+        /*Map<String, List<Invoker<T>>> localMethodInvokerMap = this.methodInvokerMap; // local reference
         if (localMethodInvokerMap != null && localMethodInvokerMap.size() > 0) {
             String methodName = RpcUtils.getMethodName(invocation);
-            Object[] args = RpcUtils.getArguments(invocation);
-            if (args != null && args.length > 0 && args[0] != null
-                    && (args[0] instanceof String || args[0].getClass().isEnum())) {
-                invokers = localMethodInvokerMap.get(methodName + "." + args[0]); // The routing can be enumerated according to the first parameter
-            }
-            if (invokers == null) {
-                invokers = localMethodInvokerMap.get(methodName);
-            }
+            invokers = localMethodInvokerMap.get(methodName);
             if (invokers == null) {
                 invokers = localMethodInvokerMap.get(Constants.ANY_VALUE);
             }
@@ -645,8 +676,8 @@ public class RegistryDirectory<T> extends AbstractDirectory<T> implements Notify
                     invokers = iterator.next();
                 }
             }
-        }
-        return invokers == null ? new ArrayList<Invoker<T>>(0) : invokers;
+        }*/
+        return invokers == null ? new ArrayList<>(0) : invokers;
     }
 
     @Override
@@ -656,7 +687,7 @@ public class RegistryDirectory<T> extends AbstractDirectory<T> implements Notify
 
     @Override
     public void process(ConfigChangeEvent event) {
-        List<URL> urls;
+        List<URL> urls = new ArrayList<>();
         if (event.getChangeType().equals(ConfigChangeType.DELETED)) {
             URL url = getConsumerUrl().clearParameters().setProtocol(Constants.EMPTY_PROTOCOL);
             if (event.getKey().endsWith(this.queryMap.get(APPLICATION_KEY) + CONFIGURATORS_SUFFIX)) {
@@ -664,10 +695,13 @@ public class RegistryDirectory<T> extends AbstractDirectory<T> implements Notify
             } else {
                 url = url.addParameter(Constants.CATEGORY_KEY, Constants.DYNAMIC_CONFIGURATORS_CATEGORY);
             }
-            urls = new ArrayList<>();
             urls.add(url);
         } else {
-            urls = ConfigParser.parseConfigurators(event.getNewValue());
+            try {
+                urls = ConfigParser.parseConfigurators(event.getNewValue());
+            } catch (Exception e) {
+                logger.error("Failed to parse raw dynamic config and it will not take effect, the raw config is: " + event.getNewValue(), e);
+            }
         }
         notify(urls);
     }
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcException.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcException.java
index 2596912..deb37ca 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcException.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcException.java
@@ -32,6 +32,7 @@ public /**final**/ class RpcException extends RuntimeException {
     public static final int BIZ_EXCEPTION = 3;
     public static final int FORBIDDEN_EXCEPTION = 4;
     public static final int SERIALIZATION_EXCEPTION = 5;
+    public static final int NO_INVOKER_AVAILABLE_AFTER_FILTER = 6;
     private static final long serialVersionUID = 7815426752583648734L;
     private int code; // RpcException cannot be extended, use error code for exception type to keep compatibility
 
@@ -98,4 +99,8 @@ public /**final**/ class RpcException extends RuntimeException {
     public boolean isSerialization() {
         return code == SERIALIZATION_EXCEPTION;
     }
+
+    public boolean isNoInvokerAvailableAfterFilter() {
+        return code == NO_INVOKER_AVAILABLE_AFTER_FILTER;
+    }
 }
\ No newline at end of file