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/30 10:16:09 UTC

[incubator-dubbo] 03/07: Merge branch 'master' into dev-metadata-config-mergemaster

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 9af1f1a971a776ba6c4cad6fb09d6d7caf5d4f95
Merge: e125951 36a1155
Author: ken.lj <ke...@gmail.com>
AuthorDate: Tue Oct 30 14:36:32 2018 +0800

    Merge branch 'master' into dev-metadata-config-mergemaster
    
    # Conflicts:
    #	dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
    #	dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
    #	dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java
    #	dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouterTest.java
    #	dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java
    #	dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
    #	dubbo-dependencies-bom/pom.xml
    #	dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java

 .../ISSUE_TEMPLATE/dubbo-issue-report-template.md  |    4 +-
 .travis.yml                                        |    5 +-
 FAQ.md                                             |    6 +-
 NOTICE                                             |   11 +-
 README.md                                          |   21 +-
 dubbo-all/pom.xml                                  |   49 +-
 dubbo-bom/pom.xml                                  |    5 +
 .../rpc/cluster/directory/AbstractDirectory.java   |    1 +
 .../cluster/loadbalance/AbstractLoadBalance.java   |    6 +-
 .../loadbalance/LeastActiveLoadBalance.java        |   31 +-
 .../rpc/cluster/loadbalance/RandomLoadBalance.java |    8 +-
 .../cluster/loadbalance/RoundRobinLoadBalance.java |  164 ++-
 .../cluster/router/condition/ConditionRouter.java  |    9 +-
 .../cluster/router/mock/MockInvokersSelector.java  |    4 +-
 .../cluster/support/AbstractClusterInvoker.java    |   12 +-
 .../dubbo/rpc/cluster/support/ClusterUtils.java    |   14 +-
 .../org/apache/dubbo/rpc/cluster/StickyTest.java   |    4 +-
 .../loadbalance/LeastActiveBalanceTest.java        |   28 +-
 .../cluster/loadbalance/LoadBalanceBaseTest.java   |  131 ++-
 .../cluster/loadbalance/RandomLoadBalanceTest.java |   32 +-
 .../loadbalance/RoundRobinLoadBalanceTest.java     |  133 ++-
 .../support/AbstractClusterInvokerTest.java        |   18 +-
 .../java/org/apache/dubbo/common/Constants.java    |    2 +
 .../src/main/java/org/apache/dubbo/common/URL.java |  116 +-
 .../common/beanutil/JavaBeanSerializeUtil.java     |   18 +-
 .../dubbo/common/bytecode/ClassGenerator.java      |  722 ++++++------
 .../org/apache/dubbo/common/bytecode/Mixin.java    |   41 +-
 .../org/apache/dubbo/common/bytecode/Proxy.java    |   62 +-
 .../org/apache/dubbo/common/bytecode/Wrapper.java  |   90 +-
 .../dubbo/common/compiler/support/JdkCompiler.java |    6 +-
 .../dubbo/common/extension/ExtensionLoader.java    |   72 +-
 .../java/org/apache/dubbo/common/io/Bytes.java     |  123 +-
 .../org/apache/dubbo/common/io/StreamUtils.java    |   29 +-
 .../common/io/UnsafeByteArrayInputStream.java      |   21 +-
 .../common/io/UnsafeByteArrayOutputStream.java     |   15 +-
 .../apache/dubbo/common/io/UnsafeStringReader.java |   21 +-
 .../apache/dubbo/common/io/UnsafeStringWriter.java |   14 +-
 .../dubbo/common/json/GenericJSONConverter.java    |  108 +-
 .../org/apache/dubbo/common/json/J2oVisitor.java   |   77 +-
 .../java/org/apache/dubbo/common/json/JSON.java    |   28 +-
 .../org/apache/dubbo/common/json/JSONArray.java    |    8 +-
 .../org/apache/dubbo/common/json/JSONObject.java   |   11 +-
 .../org/apache/dubbo/common/json/JSONReader.java   |    6 +-
 .../org/apache/dubbo/common/json/JSONWriter.java   |   15 +-
 .../java/org/apache/dubbo/common/json/Yylex.java   |   30 +-
 .../dubbo/common/logger/jdk/JdkLoggerAdapter.java  |   36 +-
 .../common/logger/log4j/Log4jLoggerAdapter.java    |   36 +-
 .../common/status/support/LoadStatusChecker.java   |    5 +
 .../common/store/support/SimpleDataStore.java      |    4 +-
 .../dubbo/common/utils/AtomicPositiveInteger.java  |    8 +-
 .../org/apache/dubbo/common/utils/ClassHelper.java |   16 +-
 .../apache/dubbo/common/utils/CollectionUtils.java |    4 +-
 .../dubbo/common/utils/CompatibleTypeUtils.java    |   13 +-
 .../org/apache/dubbo/common/utils/ConfigUtils.java |    5 +-
 .../org/apache/dubbo/common/utils/IOUtils.java     |   15 +-
 .../java/org/apache/dubbo/common/utils/Log.java    |   44 +-
 .../org/apache/dubbo/common/utils/LogUtil.java     |   23 +-
 .../org/apache/dubbo/common/utils/NetUtils.java    |    9 +-
 .../org/apache/dubbo/common/utils/PojoUtils.java   |    6 +-
 .../apache/dubbo/common/utils/ReflectUtils.java    |  258 +++--
 .../java/org/apache/dubbo/common/utils/Stack.java  |   20 +-
 .../org/apache/dubbo/common/utils/StringUtils.java |   75 +-
 .../org/apache/dubbo/common/utils/UrlUtils.java    |   12 +-
 .../common/compiler/support/JavaCodeTest.java      |    6 +-
 .../compiler/support/JavassistCompilerTest.java    |    4 +-
 .../common/compiler/support/JdkCompilerTest.java   |    4 +-
 .../org/apache/dubbo/common/model/AnimalEnum.java  |   21 -
 .../model/BizExceptionNoDefaultConstructor.java    |   26 -
 .../dubbo/common/model/media/MediaContent.java     |   78 --
 .../common/utils/CompatibleTypeUtilsTest.java      |    9 +
 .../apache/dubbo/common/utils/PojoUtilsTest.java   |   30 +
 .../apache/dubbo/common/utils/UrlUtilsTest.java    |   18 +-
 .../main/java/com/alibaba/dubbo/common/URL.java    |   12 +-
 .../org/apache/dubbo/config/MethodConfigTest.java  |   27 +-
 .../apache/dubbo/generic/GenericServiceTest.java   |    2 +-
 .../org/apache/dubbo/config/AbstractConfig.java    |   58 +-
 .../org/apache/dubbo/config/ReferenceConfig.java   |   73 +-
 .../org/apache/dubbo/config/RegistryConfig.java    |    3 +-
 .../org/apache/dubbo/config/ServiceConfig.java     |    8 +-
 .../dubbo/config/model/ApplicationModel.java       |   94 --
 .../dubbo/config/model/ConsumerMethodModel.java    |   86 --
 .../dubbo/config/utils/ReferenceConfigCache.java   |    4 +-
 .../apache/dubbo/config/AbstractConfigTest.java    |    4 +-
 .../apache/dubbo/config/GenericServiceTest.java    |   10 +-
 .../org/apache/dubbo/config/MethodConfigTest.java  |   12 +-
 .../org/apache/dubbo/config/cache/CacheTest.java   |    4 +-
 .../apache/dubbo/config/spring/ReferenceBean.java  |   20 +-
 .../apache/dubbo/config/spring/ServiceBean.java    |   35 +-
 .../DubboConfigBindingBeanPostProcessor.java       |    2 +-
 .../ReferenceAnnotationBeanPostProcessor.java      |  107 +-
 .../spring/extension/SpringExtensionFactory.java   |    4 +
 .../spring/initializer/DubboContextListener.java   |   72 ++
 .../spring/status/DataSourceStatusChecker.java     |   12 +-
 .../config/spring/status/SpringStatusChecker.java  |   12 +-
 .../src/main/resources/META-INF/compat/dubbo.xsd   |    4 +-
 .../src/main/resources/META-INF/dubbo.xsd          |    2 +-
 .../src/main/resources/META-INF/web-fragment.xml   |    6 +-
 .../org/apache/dubbo/config/spring/ConfigTest.java |    6 +-
 .../ReferenceAnnotationBeanPostProcessorTest.java  |   84 +-
 .../DubboApplicationContextInitializerTest.java    |   15 +-
 .../spring/status/DataSourceStatusCheckerTest.java |   11 +-
 .../spring/status/SpringStatusCheckerTest.java     |   13 +-
 .../dubbo/config/spring/annotation-consumer.xml    |    2 +-
 .../dubbo/config/spring/delay-fixed-time.xml       |    2 +-
 .../dubbo/config/spring/delay-on-initialized.xml   |    2 +-
 .../config/spring/override-multi-protocol.xml      |    5 +-
 .../apache/dubbo/config/spring/provider-multi.xml  |    3 +-
 dubbo-dependencies-bom/pom.xml                     |   15 +-
 dubbo-distribution/pom.xml                         |    7 +-
 .../org/apache/dubbo/cache/filter/CacheFilter.java |   26 +-
 .../apache/dubbo/cache/filter/CacheFilterTest.java |    4 +-
 .../validation/support/jvalidation/JValidator.java |   23 +-
 .../java/org/apache/dubbo/metrics/MetricName.java  |   66 +-
 .../org/apache/dubbo/monitor/dubbo/Statistics.java |   51 +-
 .../apache/dubbo/qos/command/CommandContext.java   |    3 +-
 .../java/org/apache/dubbo/qos/command/impl/Ls.java |    6 +-
 .../org/apache/dubbo/qos/command/impl/Offline.java |    8 +-
 .../org/apache/dubbo/qos/command/impl/Online.java  |    8 +-
 .../org/apache/dubbo/qos/command/impl/LsTest.java  |    6 +-
 .../apache/dubbo/qos/command/impl/OfflineTest.java |    4 +-
 .../apache/dubbo/qos/command/impl/OnlineTest.java  |    4 +-
 .../registry/integration/RegistryDirectory.java    |    6 +-
 .../dubbo/registry/support/AbstractRegistry.java   |    4 +-
 .../registry/support/AbstractRegistryFactory.java  |    6 +-
 .../support/AbstractRegistryFactoryTest.java       |   17 +-
 .../registry/support/AbstractRegistryTest.java     |   64 +-
 .../apache/dubbo/registry/dubbo/DubboRegistry.java |    3 +-
 .../apache/dubbo/registry/redis/RedisRegistry.java |   24 +-
 .../registry/zookeeper/ZookeeperRegistry.java      |    4 +-
 .../apache/dubbo/remoting/exchange/Request.java    |    4 +-
 .../remoting/exchange/codec/ExchangeCodec.java     |   40 +-
 .../support/header/HeaderExchangeChannel.java      |   20 +-
 .../support/header/HeaderExchangeHandler.java      |   10 +-
 .../support/header/HeaderExchangeServer.java       |    3 +-
 .../dubbo/remoting/transport/AbstractClient.java   |   23 +-
 .../dubbo/remoting/transport/CodecSupport.java     |    6 +
 .../transport/dispatcher/ChannelEventRunnable.java |    1 +
 .../dubbo/remoting/codec/ExchangeCodecTest.java    |   18 +
 .../transport/codec/DeprecatedExchangeCodec.java   |   18 +-
 .../remoting/transport/grizzly/GrizzlyChannel.java |   20 +-
 .../remoting/transport/grizzly/GrizzlyClient.java  |    5 +-
 .../dubbo/remoting/transport/mina/MinaChannel.java |   20 +-
 .../dubbo/remoting/transport/mina/MinaClient.java  |    9 +-
 .../remoting/transport/mina/MinaCodecAdapter.java  |    4 +-
 .../transport/mina/MinaClientToServerTest.java     |    2 +-
 .../remoting/transport/netty/NettyChannel.java     |   20 +-
 .../remoting/transport/netty/NettyClient.java      |    5 +-
 .../transport/netty/ClientReconnectTest.java       |    2 +-
 .../transport/netty/NettyClientToServerTest.java   |    2 +-
 .../remoting/transport/netty4/NettyChannel.java    |   20 +-
 .../remoting/transport/netty4/NettyClient.java     |    9 +-
 .../transport/netty4/NettyClientToServerTest.java  |    2 +-
 .../java/org/apache/dubbo/rpc/AsyncRpcResult.java  |    5 +-
 .../main/java/org/apache/dubbo/rpc/RpcContext.java |   25 +
 .../org/apache/dubbo/rpc/ServiceClassHolder.java   |   45 -
 .../java/org/apache/dubbo/rpc/StaticContext.java   |   75 --
 .../org/apache/dubbo/rpc/filter/EchoFilter.java    |    3 +-
 .../apache/dubbo/rpc/model/ApplicationModel.java   |   75 ++
 .../dubbo/rpc/model/ConsumerMethodModel.java       |  160 +++
 .../org/apache/dubbo/rpc}/model/ConsumerModel.java |   38 +-
 .../dubbo/rpc}/model/ProviderMethodModel.java      |    2 +-
 .../org/apache/dubbo/rpc}/model/ProviderModel.java |   19 +-
 .../dubbo/rpc/protocol/AbstractExporter.java       |    9 +-
 .../apache/dubbo/rpc/protocol/AbstractInvoker.java |   12 +-
 .../apache/dubbo/rpc/support/DelegateExporter.java |   47 -
 .../org/apache/dubbo/rpc/support/RpcUtils.java     |    8 +-
 .../org/apache/dubbo/rpc/StaticContextTest.java    |   64 --
 .../rpc/protocol/dubbo/DecodeableRpcResult.java    |    6 +-
 .../dubbo/rpc/protocol/dubbo/DubboCodec.java       |   41 +-
 .../dubbo/rpc/protocol/dubbo/DubboInvoker.java     |    3 +-
 .../dubbo/rpc/protocol/dubbo/DubboProtocol.java    |    6 +-
 .../protocol/dubbo/LazyConnectExchangeClient.java  |   17 +-
 .../rpc/protocol/dubbo/filter/FutureFilter.java    |   48 +-
 .../rpc/protocol/dubbo/DubboProtocolTest.java      |   24 +-
 .../rpc/protocol/dubbo/ExplicitCallbackTest.java   |    5 +-
 .../rpc/protocol/dubbo/ImplicitCallBackTest.java   |   75 +-
 .../dubbo/telnet/ChangeTelnetHandlerTest.java      |    2 +-
 .../dubbo/telnet/InvokerTelnetHandlerTest.java     |   12 +-
 .../dubbo/telnet/ListTelnetHandlerTest.java        |    8 +-
 .../dubbo/telnet/PortTelnetHandlerTest.java        |   12 +-
 .../dubbo/rpc/protocol/redis/RedisProtocol.java    |   24 +-
 .../dubbo/rpc/protocol/rest/RestProtocol.java      |    6 +-
 .../dubbo/rpc/protocol/rest/RestProtocolTest.java  |   50 +-
 .../dubbo/rpc/protol/rest/RestProtocolTest.java    |   23 +-
 .../dubbo/rpc/protocol/thrift/ThriftProtocol.java  |    3 +-
 .../io/RandomAccessByteArrayOutputStream.java      |   15 +-
 .../webservice/WebserviceProtocolTest.java         |    4 +-
 .../dubbo-serialization-api/pom.xml                |    2 +-
 .../dubbo-serialization-fastjson/pom.xml           |    2 +-
 .../serialize/fastjson/FastJsonObjectInput.java    |    5 +-
 .../common/serialize/fastjson/model/Image.java     |  104 --
 .../common/serialize/fastjson/model/Person.java    |   38 -
 .../src/test/resources/log4j.xml                   |   32 -
 .../dubbo-serialization-fst/pom.xml                |    2 +-
 .../common/serialize/fst/model/AnimalEnum.java     |   21 -
 .../common/serialize/fst/model/FullAddress.java    |  199 ----
 .../src/test/resources/log4j.xml                   |   32 -
 .../dubbo-serialization-hessian2/pom.xml           |    2 +-
 .../org/apache/dubbo/common/model/AnimalEnum.java  |   21 -
 .../apache/dubbo/common/model/BizException.java    |   29 -
 .../model/BizExceptionNoDefaultConstructor.java    |   26 -
 .../java/org/apache/dubbo/common/model/Person.java |   95 --
 .../dubbo/common/model/SerializablePerson.java     |   97 --
 .../org/apache/dubbo/common/model/media/Image.java |  120 --
 .../org/apache/dubbo/common/model/media/Media.java |  205 ----
 .../dubbo/common/model/media/MediaContent.java     |   78 --
 .../dubbo/common/model/person/BigPerson.java       |  151 ---
 .../dubbo/common/model/person/FullAddress.java     |  202 ----
 .../dubbo/common/model/person/PersonInfo.java      |  206 ----
 .../apache/dubbo/common/model/person/Phone.java    |  139 ---
 .../src/test/resources/log4j.xml                   |   32 -
 .../dubbo/common/serialize/dubbo/SimpleDO.fc       |    2 -
 .../dubbo-serialization-jdk/pom.xml                |    2 +-
 .../serialize/java/CompactedObjectInputStream.java |    3 +-
 .../common/serialize/java/JavaObjectInput.java     |   15 +-
 .../java/org/apache/dubbo/common/model/Person.java |   95 --
 .../dubbo/common/model/SerializablePerson.java     |   97 --
 .../org/apache/dubbo/common/model/media/Image.java |  120 --
 .../dubbo/common/model/person/BigPerson.java       |  151 ---
 .../dubbo/common/model/person/PersonInfo.java      |  206 ----
 .../dubbo/common/model/person/PersonStatus.java    |   22 -
 .../apache/dubbo/common/model/person/Phone.java    |  139 ---
 .../AbstractSerializationPersionFailTest.java      |  137 ---
 .../AbstractSerializationPersionOkTest.java        |   93 --
 .../serialization/AbstractSerializationTest.java   | 1210 -------------------
 .../src/test/resources/log4j.xml                   |   32 -
 .../dubbo/common/serialize/dubbo/SimpleDO.fc       |    2 -
 .../dubbo-serialization-kryo/pom.xml               |    2 +-
 .../org/apache/dubbo/common/model/AnimalEnum.java  |   21 -
 .../apache/dubbo/common/model/BizException.java    |   29 -
 .../model/BizExceptionNoDefaultConstructor.java    |   26 -
 .../org/apache/dubbo/common/model/media/Media.java |  205 ----
 .../dubbo/common/model/media/MediaContent.java     |   78 --
 .../dubbo/common/model/person/FullAddress.java     |  202 ----
 .../dubbo/common/model/person/PersonStatus.java    |   22 -
 .../AbstractSerializationPersionFailTest.java      |  137 ---
 .../AbstractSerializationPersionOkTest.java        |   93 --
 .../serialization/AbstractSerializationTest.java   | 1215 --------------------
 .../src/test/resources/log4j.xml                   |   32 -
 .../pom.xml                                        |   28 +-
 .../protostuff/ProtostuffObjectInput.java          |  134 +++
 .../protostuff/ProtostuffObjectOutput.java         |  128 +++
 .../protostuff/ProtostuffSerialization.java        |  110 +-
 .../dubbo/common/serialize/protostuff/Wrapper.java |   62 +-
 .../protostuff/delegate/TimeDelegate.java          |   54 +
 .../serialize/protostuff/utils/WrapperUtils.java   |   92 ++
 ...org.apache.dubbo.common.serialize.Serialization |    1 +
 .../dubbo-serialization-test/pom.xml               |   73 ++
 .../base/AbstractSerializationPersonFailTest.java} |   25 +-
 .../base/AbstractSerializationPersonOkTest.java}   |   41 +-
 .../serialize/base}/AbstractSerializationTest.java |   50 +-
 .../fastjson/FastJsonObjectInputTest.java          |    2 +-
 .../fastjson/FastJsonObjectOutputTest.java         |    6 +-
 .../fastjson/FastJsonSerializationTest.java        |    3 -
 .../dubbo/common/serialize/fst/FstFactoryTest.java |    0
 .../common/serialize/fst/FstObjectInputTest.java   |    5 +-
 .../common/serialize/fst/FstObjectOutputTest.java  |    6 +-
 .../common/serialize/fst/FstSerializationTest.java |    0
 .../serialize/hessian2/Hessian2PersonOkTest.java}  |   17 +-
 .../hessian2}/Hessian2SerializationTest.java       |    7 +-
 .../jdk}/CompactedJavaSerializationTest.java       |    5 +-
 .../serialize/jdk}/JavaSerializationTest.java      |    5 +-
 .../common/serialize/jdk/JdkPersonOkTest.java}     |   12 +-
 .../jdk}/NativeJavaSerializationTest.java          |    5 +-
 .../common/serialize/kryo/KryoPersonOkTest.java}   |   11 +-
 .../serialize/kryo}/KyroSerializationTest.java     |    4 +-
 .../serialize/kryo}/ReflectionUtilsTest.java       |    3 +-
 .../dubbo/common/serialize}/model/AnimalEnum.java  |    2 +-
 .../common/serialize}/model/BizException.java      |    2 +-
 .../model/BizExceptionNoDefaultConstructor.java    |    2 +-
 .../dubbo/common/serialize}/model/Person.java      |    2 +-
 .../serialize}/model/SerializablePerson.java       |    2 +-
 .../dubbo/common/serialize}/model/media/Image.java |    2 +-
 .../dubbo/common/serialize}/model/media/Media.java |    2 +-
 .../serialize}/model/media/MediaContent.java       |    2 +-
 .../common/serialize}/model/person/BigPerson.java  |    2 +-
 .../serialize}/model/person/FullAddress.java       |    2 +-
 .../common/serialize}/model/person/PersonInfo.java |    2 +-
 .../serialize}/model/person/PersonStatus.java      |    2 +-
 .../common/serialize}/model/person/Phone.java      |    2 +-
 .../protostuff/ProtostuffSerializationTest.java    |   21 +-
 .../support/SerializableClassRegistryTest.java     |   13 +-
 .../src/test/resources/log4j.xml                   |   58 +-
 .../SimpleDO.fc                                    |    0
 dubbo-serialization/pom.xml                        |    4 +-
 pom.xml                                            |    8 +-
 286 files changed, 4269 insertions(+), 8503 deletions(-)

diff --cc dubbo-all/pom.xml
index f4ce3e9,8e8fa66..e7ac32e
--- a/dubbo-all/pom.xml
+++ b/dubbo-all/pom.xml
@@@ -452,10 -438,8 +459,11 @@@
                                      <include>org.apache.dubbo:dubbo-serialization-fst</include>
                                      <include>org.apache.dubbo:dubbo-serialization-kryo</include>
                                      <include>org.apache.dubbo:dubbo-serialization-jdk</include>
+                                     <include>org.apache.dubbo:dubbo-serialization-protostuff</include>
                                      <include>org.apache.dubbo:dubbo-bootstrap</include>
 +                                    <include>org.apache.dubbo:dubbo-governance-api</include>
 +                                    <include>org.apache.dubbo:dubbo-governance-apollo</include>
 +                                    <include>org.apache.dubbo:dubbo-governance-zookeeper</include>
                                  </includes>
                              </artifactSet>
                              <transformers>
diff --cc dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
index 1f51999,0cea0b8..e77ac49
--- 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
@@@ -50,16 -54,17 +50,17 @@@ public abstract class AbstractDirectory
          this(url, null);
      }
  
 -    public AbstractDirectory(URL url, List<Router> routers) {
 -        this(url, url, routers);
 +    public AbstractDirectory(URL url, RouterChain<T> routerChain) {
 +        this(url, url, routerChain);
      }
  
 -    public AbstractDirectory(URL url, URL consumerUrl, List<Router> routers) {
 -        if (url == null) {
 +    public AbstractDirectory(URL url, URL consumerUrl, RouterChain<T> routerChain) {
 +        if (url == null)
              throw new IllegalArgumentException("url == null");
+         }
          this.url = url;
          this.consumerUrl = consumerUrl;
 -        setRouters(routers);
 +        setRouterChain(routerChain);
      }
  
      @Override
diff --cc dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java
index 66f9ccb,35ce7e5..a479136
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java
@@@ -1,109 -1,100 +1,109 @@@
 -/*
 - * 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.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.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 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;
 -    }
 -
 -    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 {
 +
 +    public static final String NAME = "MOCK_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)
++            if (value == null) {
 +                return getNormalInvokers(invokers);
-             else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
++            } 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 String getName() {
 +        return NAME;
 +    }
 +
 +    /**
 +     * Always stay on the top of the list
 +     *
 +     * @param o
 +     * @return
 +     */
 +    @Override
 +    public int compareTo(Router o) {
 +        return 1;
 +    }
 +
 +}
diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java
index be98ae4,fdaa3b1..ff74233
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java
@@@ -1,579 -1,534 +1,627 @@@
 -/*
 - * 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.config;
 -
 -import org.apache.dubbo.common.Constants;
 -import org.apache.dubbo.common.URL;
 -import org.apache.dubbo.common.extension.ExtensionLoader;
 -import org.apache.dubbo.common.logger.Logger;
 -import org.apache.dubbo.common.logger.LoggerFactory;
 -import org.apache.dubbo.common.utils.CollectionUtils;
 -import org.apache.dubbo.common.utils.ConfigUtils;
 -import org.apache.dubbo.common.utils.ReflectUtils;
 -import org.apache.dubbo.common.utils.StringUtils;
 -import org.apache.dubbo.config.support.Parameter;
 -import org.apache.dubbo.rpc.model.ConsumerMethodModel;
 -
 -import java.io.Serializable;
 -import java.lang.reflect.Method;
 -import java.lang.reflect.Modifier;
 -import java.util.HashMap;
 -import java.util.Map;
 -import java.util.regex.Matcher;
 -import java.util.regex.Pattern;
 -
 -/**
 - * Utility methods and public methods for parsing configuration
 - *
 - * @export
 - */
 -public abstract class AbstractConfig implements Serializable {
 -
 -    protected static final Logger logger = LoggerFactory.getLogger(AbstractConfig.class);
 -    private static final long serialVersionUID = 4267533505537413570L;
 -    private static final int MAX_LENGTH = 200;
 -
 -    private static final int MAX_PATH_LENGTH = 200;
 -
 -    private static final Pattern PATTERN_NAME = Pattern.compile("[\\-._0-9a-zA-Z]+");
 -
 -    private static final Pattern PATTERN_MULTI_NAME = Pattern.compile("[,\\-._0-9a-zA-Z]+");
 -
 -    private static final Pattern PATTERN_METHOD_NAME = Pattern.compile("[a-zA-Z][0-9a-zA-Z]*");
 -
 -    private static final Pattern PATTERN_PATH = Pattern.compile("[/\\-$._0-9a-zA-Z]+");
 -
 -    private static final Pattern PATTERN_NAME_HAS_SYMBOL = Pattern.compile("[:*,/\\-._0-9a-zA-Z]+");
 -
 -    private static final Pattern PATTERN_KEY = Pattern.compile("[*,\\-._0-9a-zA-Z]+");
 -    private static final Map<String, String> legacyProperties = new HashMap<String, String>();
 -    private static final String[] SUFFIXES = new String[]{"Config", "Bean"};
 -
 -    static {
 -        legacyProperties.put("dubbo.protocol.name", "dubbo.service.protocol");
 -        legacyProperties.put("dubbo.protocol.host", "dubbo.service.server.host");
 -        legacyProperties.put("dubbo.protocol.port", "dubbo.service.server.port");
 -        legacyProperties.put("dubbo.protocol.threads", "dubbo.service.max.thread.pool.size");
 -        legacyProperties.put("dubbo.consumer.timeout", "dubbo.service.invoke.timeout");
 -        legacyProperties.put("dubbo.consumer.retries", "dubbo.service.max.retry.providers");
 -        legacyProperties.put("dubbo.consumer.check", "dubbo.service.allow.no.provider");
 -        legacyProperties.put("dubbo.service.url", "dubbo.service.address");
 -
 -        // this is only for compatibility
 -        Runtime.getRuntime().addShutdownHook(DubboShutdownHook.getDubboShutdownHook());
 -    }
 -
 -    protected String id;
 -
 -    private static String convertLegacyValue(String key, String value) {
 -        if (value != null && value.length() > 0) {
 -            if ("dubbo.service.max.retry.providers".equals(key)) {
 -                return String.valueOf(Integer.parseInt(value) - 1);
 -            } else if ("dubbo.service.allow.no.provider".equals(key)) {
 -                return String.valueOf(!Boolean.parseBoolean(value));
 -            }
 -        }
 -        return value;
 -    }
 -
 -    protected static void appendProperties(AbstractConfig config) {
 -        if (config == null) {
 -            return;
 -        }
 -        String prefix = "dubbo." + getTagName(config.getClass()) + ".";
 -        Method[] methods = config.getClass().getMethods();
 -        for (Method method : methods) {
 -            try {
 -                String name = method.getName();
 -                if (name.length() > 3 && name.startsWith("set") && Modifier.isPublic(method.getModifiers())
 -                        && method.getParameterTypes().length == 1 && isPrimitive(method.getParameterTypes()[0])) {
 -                    String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), ".");
 -
 -                    String value = null;
 -                    if (config.getId() != null && config.getId().length() > 0) {
 -                        String pn = prefix + config.getId() + "." + property;
 -                        value = System.getProperty(pn);
 -                        if (!StringUtils.isBlank(value)) {
 -                            logger.info("Use System Property " + pn + " to config dubbo");
 -                        }
 -                    }
 -                    if (value == null || value.length() == 0) {
 -                        String pn = prefix + property;
 -                        value = System.getProperty(pn);
 -                        if (!StringUtils.isBlank(value)) {
 -                            logger.info("Use System Property " + pn + " to config dubbo");
 -                        }
 -                    }
 -                    if (value == null || value.length() == 0) {
 -                        Method getter;
 -                        try {
 -                            getter = config.getClass().getMethod("get" + name.substring(3));
 -                        } catch (NoSuchMethodException e) {
 -                            try {
 -                                getter = config.getClass().getMethod("is" + name.substring(3));
 -                            } catch (NoSuchMethodException e2) {
 -                                getter = null;
 -                            }
 -                        }
 -                        if (getter != null) {
 -                            if (getter.invoke(config) == null) {
 -                                if (config.getId() != null && config.getId().length() > 0) {
 -                                    value = ConfigUtils.getProperty(prefix + config.getId() + "." + property);
 -                                }
 -                                if (value == null || value.length() == 0) {
 -                                    value = ConfigUtils.getProperty(prefix + property);
 -                                }
 -                                if (value == null || value.length() == 0) {
 -                                    String legacyKey = legacyProperties.get(prefix + property);
 -                                    if (legacyKey != null && legacyKey.length() > 0) {
 -                                        value = convertLegacyValue(legacyKey, ConfigUtils.getProperty(legacyKey));
 -                                    }
 -                                }
 -
 -                            }
 -                        }
 -                    }
 -                    if (value != null && value.length() > 0) {
 -                        method.invoke(config, convertPrimitive(method.getParameterTypes()[0], value));
 -                    }
 -                }
 -            } catch (Exception e) {
 -                logger.error(e.getMessage(), e);
 -            }
 -        }
 -    }
 -
 -    private static String getTagName(Class<?> cls) {
 -        String tag = cls.getSimpleName();
 -        for (String suffix : SUFFIXES) {
 -            if (tag.endsWith(suffix)) {
 -                tag = tag.substring(0, tag.length() - suffix.length());
 -                break;
 -            }
 -        }
 -        tag = tag.toLowerCase();
 -        return tag;
 -    }
 -
 -    protected static void appendParameters(Map<String, String> parameters, Object config) {
 -        appendParameters(parameters, config, null);
 -    }
 -
 -    @SuppressWarnings("unchecked")
 -    protected static void appendParameters(Map<String, String> parameters, Object config, String prefix) {
 -        if (config == null) {
 -            return;
 -        }
 -        Method[] methods = config.getClass().getMethods();
 -        for (Method method : methods) {
 -            try {
 -                String name = method.getName();
 -                if ((name.startsWith("get") || name.startsWith("is"))
 -                        && !"getClass".equals(name)
 -                        && Modifier.isPublic(method.getModifiers())
 -                        && method.getParameterTypes().length == 0
 -                        && isPrimitive(method.getReturnType())) {
 -                    Parameter parameter = method.getAnnotation(Parameter.class);
 -                    if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) {
 -                        continue;
 -                    }
 -                    int i = name.startsWith("get") ? 3 : 2;
 -                    String prop = StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), ".");
 -                    String key;
 -                    if (parameter != null && parameter.key().length() > 0) {
 -                        key = parameter.key();
 -                    } else {
 -                        key = prop;
 -                    }
 -                    Object value = method.invoke(config);
 -                    String str = String.valueOf(value).trim();
 -                    if (value != null && str.length() > 0) {
 -                        if (parameter != null && parameter.escaped()) {
 -                            str = URL.encode(str);
 -                        }
 -                        if (parameter != null && parameter.append()) {
 -                            String pre = parameters.get(Constants.DEFAULT_KEY + "." + key);
 -                            if (pre != null && pre.length() > 0) {
 -                                str = pre + "," + str;
 -                            }
 -                            pre = parameters.get(key);
 -                            if (pre != null && pre.length() > 0) {
 -                                str = pre + "," + str;
 -                            }
 -                        }
 -                        if (prefix != null && prefix.length() > 0) {
 -                            key = prefix + "." + key;
 -                        }
 -                        parameters.put(key, str);
 -                    } else if (parameter != null && parameter.required()) {
 -                        throw new IllegalStateException(config.getClass().getSimpleName() + "." + key + " == null");
 -                    }
 -                } else if ("getParameters".equals(name)
 -                        && Modifier.isPublic(method.getModifiers())
 -                        && method.getParameterTypes().length == 0
 -                        && method.getReturnType() == Map.class) {
 -                    Map<String, String> map = (Map<String, String>) method.invoke(config, new Object[0]);
 -                    if (map != null && map.size() > 0) {
 -                        String pre = (prefix != null && prefix.length() > 0 ? prefix + "." : "");
 -                        for (Map.Entry<String, String> entry : map.entrySet()) {
 -                            parameters.put(pre + entry.getKey().replace('-', '.'), entry.getValue());
 -                        }
 -                    }
 -                }
 -            } catch (Exception e) {
 -                throw new IllegalStateException(e.getMessage(), e);
 -            }
 -        }
 -    }
 -
 -    protected static void appendAttributes(Map<String, Object> parameters, Object config) {
 -        appendAttributes(parameters, config, null);
 -    }
 -
 -    protected static void appendAttributes(Map<String, Object> parameters, Object config, String prefix) {
 -        if (config == null) {
 -            return;
 -        }
 -        Method[] methods = config.getClass().getMethods();
 -        for (Method method : methods) {
 -            try {
 -                Parameter parameter = method.getAnnotation(Parameter.class);
 -                if (parameter == null || !parameter.attribute()) {
 -                    continue;
 -                }
 -                String name = method.getName();
 -                if ((name.startsWith("get") || name.startsWith("is"))
 -                        && !"getClass".equals(name)
 -                        && Modifier.isPublic(method.getModifiers())
 -                        && method.getParameterTypes().length == 0
 -                        && isPrimitive(method.getReturnType())) {
 -                    String key;
 -                    if (parameter.key().length() > 0) {
 -                        key = parameter.key();
 -                    } else {
 -                        int i = name.startsWith("get") ? 3 : 2;
 -                        key = name.substring(i, i + 1).toLowerCase() + name.substring(i + 1);
 -                    }
 -                    Object value = method.invoke(config);
 -                    if (value != null) {
 -                        if (prefix != null && prefix.length() > 0) {
 -                            key = prefix + "." + key;
 -                        }
 -                        parameters.put(key, value);
 -                    }
 -                }
 -            } catch (Exception e) {
 -                throw new IllegalStateException(e.getMessage(), e);
 -            }
 -        }
 -    }
 -
 -    protected static ConsumerMethodModel.AsyncMethodInfo convertMethodConfig2AyncInfo(MethodConfig methodConfig) {
 -        if (methodConfig == null || (methodConfig.getOninvoke() == null && methodConfig.getOnreturn() == null && methodConfig.getOnthrow() == null)) {
 -            return null;
 -        }
 -
 -        //check config conflict
 -        if (Boolean.FALSE.equals(methodConfig.isReturn()) && (methodConfig.getOnreturn() != null || methodConfig.getOnthrow() != null)) {
 -            throw new IllegalStateException("method config error : return attribute must be set true when onreturn or onthrow has been set.");
 -        }
 -
 -        ConsumerMethodModel.AsyncMethodInfo asyncMethodInfo = new ConsumerMethodModel.AsyncMethodInfo();
 -
 -        asyncMethodInfo.setOninvokeInstance(methodConfig.getOninvoke());
 -        asyncMethodInfo.setOnreturnInstance(methodConfig.getOnreturn());
 -        asyncMethodInfo.setOnthrowInstance(methodConfig.getOnthrow());
 -
 -        try {
 -            String oninvokeMethod = methodConfig.getOninvokeMethod();
 -            if (StringUtils.isNotEmpty(oninvokeMethod)) {
 -                asyncMethodInfo.setOninvokeMethod(getMethodByName(methodConfig.getOninvoke().getClass(), oninvokeMethod));
 -            }
 -
 -            String onreturnMethod = methodConfig.getOnreturnMethod();
 -            if (StringUtils.isNotEmpty(onreturnMethod)) {
 -                asyncMethodInfo.setOnreturnMethod(getMethodByName(methodConfig.getOnreturn().getClass(), onreturnMethod));
 -            }
 -
 -            String onthrowMethod = methodConfig.getOnthrowMethod();
 -            if (StringUtils.isNotEmpty(onthrowMethod)) {
 -                asyncMethodInfo.setOnthrowMethod(getMethodByName(methodConfig.getOnthrow().getClass(), onthrowMethod));
 -            }
 -        } catch (Exception e) {
 -            throw new IllegalStateException(e.getMessage(), e);
 -        }
 -
 -        return asyncMethodInfo;
 -    }
 -
 -    private static Method getMethodByName(Class<?> clazz, String methodName) {
 -        try {
 -            return ReflectUtils.findMethodByMethodName(clazz, methodName);
 -        } catch (Exception e) {
 -            throw new IllegalStateException(e);
 -        }
 -    }
 -
 -    private static boolean isPrimitive(Class<?> type) {
 -        return type.isPrimitive()
 -                || type == String.class
 -                || type == Character.class
 -                || type == Boolean.class
 -                || type == Byte.class
 -                || type == Short.class
 -                || type == Integer.class
 -                || type == Long.class
 -                || type == Float.class
 -                || type == Double.class
 -                || type == Object.class;
 -    }
 -
 -    private static Object convertPrimitive(Class<?> type, String value) {
 -        if (type == char.class || type == Character.class) {
 -            return value.length() > 0 ? value.charAt(0) : '\0';
 -        } else if (type == boolean.class || type == Boolean.class) {
 -            return Boolean.valueOf(value);
 -        } else if (type == byte.class || type == Byte.class) {
 -            return Byte.valueOf(value);
 -        } else if (type == short.class || type == Short.class) {
 -            return Short.valueOf(value);
 -        } else if (type == int.class || type == Integer.class) {
 -            return Integer.valueOf(value);
 -        } else if (type == long.class || type == Long.class) {
 -            return Long.valueOf(value);
 -        } else if (type == float.class || type == Float.class) {
 -            return Float.valueOf(value);
 -        } else if (type == double.class || type == Double.class) {
 -            return Double.valueOf(value);
 -        }
 -        return value;
 -    }
 -
 -    protected static void checkExtension(Class<?> type, String property, String value) {
 -        checkName(property, value);
 -        if (value != null && value.length() > 0
 -                && !ExtensionLoader.getExtensionLoader(type).hasExtension(value)) {
 -            throw new IllegalStateException("No such extension " + value + " for " + property + "/" + type.getName());
 -        }
 -    }
 -
 -    protected static void checkMultiExtension(Class<?> type, String property, String value) {
 -        checkMultiName(property, value);
 -        if (value != null && value.length() > 0) {
 -            String[] values = value.split("\\s*[,]+\\s*");
 -            for (String v : values) {
 -                if (v.startsWith(Constants.REMOVE_VALUE_PREFIX)) {
 -                    v = v.substring(1);
 -                }
 -                if (Constants.DEFAULT_KEY.equals(v)) {
 -                    continue;
 -                }
 -                if (!ExtensionLoader.getExtensionLoader(type).hasExtension(v)) {
 -                    throw new IllegalStateException("No such extension " + v + " for " + property + "/" + type.getName());
 -                }
 -            }
 -        }
 -    }
 -
 -    protected static void checkLength(String property, String value) {
 -        checkProperty(property, value, MAX_LENGTH, null);
 -    }
 -
 -    protected static void checkPathLength(String property, String value) {
 -        checkProperty(property, value, MAX_PATH_LENGTH, null);
 -    }
 -
 -    protected static void checkName(String property, String value) {
 -        checkProperty(property, value, MAX_LENGTH, PATTERN_NAME);
 -    }
 -
 -    protected static void checkNameHasSymbol(String property, String value) {
 -        checkProperty(property, value, MAX_LENGTH, PATTERN_NAME_HAS_SYMBOL);
 -    }
 -
 -    protected static void checkKey(String property, String value) {
 -        checkProperty(property, value, MAX_LENGTH, PATTERN_KEY);
 -    }
 -
 -    protected static void checkMultiName(String property, String value) {
 -        checkProperty(property, value, MAX_LENGTH, PATTERN_MULTI_NAME);
 -    }
 -
 -    protected static void checkPathName(String property, String value) {
 -        checkProperty(property, value, MAX_PATH_LENGTH, PATTERN_PATH);
 -    }
 -
 -    protected static void checkMethodName(String property, String value) {
 -        checkProperty(property, value, MAX_LENGTH, PATTERN_METHOD_NAME);
 -    }
 -
 -    protected static void checkParameterName(Map<String, String> parameters) {
 -        if (parameters == null || parameters.size() == 0) {
 -            return;
 -        }
 -        for (Map.Entry<String, String> entry : parameters.entrySet()) {
 -            checkNameHasSymbol(entry.getKey(), entry.getValue());
 -        }
 -    }
 -
 -    protected static void checkProperty(String property, String value, int maxlength, Pattern pattern) {
 -        if (value == null || value.length() == 0) {
 -            return;
 -        }
 -        if (value.length() > maxlength) {
 -            throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" is longer than " + maxlength);
 -        }
 -        if (pattern != null) {
 -            Matcher matcher = pattern.matcher(value);
 -            if (!matcher.matches()) {
 -                throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" contains illegal " +
 -                        "character, only digit, letter, '-', '_' or '.' is legal.");
 -            }
 -        }
 -    }
 -
 -    @Parameter(excluded = true)
 -    public String getId() {
 -        return id;
 -    }
 -
 -    public void setId(String id) {
 -        this.id = id;
 -    }
 -
 -    protected void appendAnnotation(Class<?> annotationClass, Object annotation) {
 -        Method[] methods = annotationClass.getMethods();
 -        for (Method method : methods) {
 -            if (method.getDeclaringClass() != Object.class
 -                    && method.getReturnType() != void.class
 -                    && method.getParameterTypes().length == 0
 -                    && Modifier.isPublic(method.getModifiers())
 -                    && !Modifier.isStatic(method.getModifiers())) {
 -                try {
 -                    String property = method.getName();
 -                    if ("interfaceClass".equals(property) || "interfaceName".equals(property)) {
 -                        property = "interface";
 -                    }
 -                    String setter = "set" + property.substring(0, 1).toUpperCase() + property.substring(1);
 -                    Object value = method.invoke(annotation);
 -                    if (value != null && !value.equals(method.getDefaultValue())) {
 -                        Class<?> parameterType = ReflectUtils.getBoxedClass(method.getReturnType());
 -                        if ("filter".equals(property) || "listener".equals(property)) {
 -                            parameterType = String.class;
 -                            value = StringUtils.join((String[]) value, ",");
 -                        } else if ("parameters".equals(property)) {
 -                            parameterType = Map.class;
 -                            value = CollectionUtils.toStringMap((String[]) value);
 -                        }
 -                        try {
 -                            Method setterMethod = getClass().getMethod(setter, parameterType);
 -                            setterMethod.invoke(this, value);
 -                        } catch (NoSuchMethodException e) {
 -                            // ignore
 -                        }
 -                    }
 -                } catch (Throwable e) {
 -                    logger.error(e.getMessage(), e);
 -                }
 -            }
 -        }
 -    }
 -
 -    @Override
 -    public String toString() {
 -        try {
 -            StringBuilder buf = new StringBuilder();
 -            buf.append("<dubbo:");
 -            buf.append(getTagName(getClass()));
 -            Method[] methods = getClass().getMethods();
 -            for (Method method : methods) {
 -                try {
 -                    String name = method.getName();
 -                    if ((name.startsWith("get") || name.startsWith("is"))
 -                            && !"getClass".equals(name) && !"get".equals(name) && !"is".equals(name)
 -                            && Modifier.isPublic(method.getModifiers())
 -                            && method.getParameterTypes().length == 0
 -                            && isPrimitive(method.getReturnType())) {
 -                        int i = name.startsWith("get") ? 3 : 2;
 -                        String key = name.substring(i, i + 1).toLowerCase() + name.substring(i + 1);
 -                        Object value = method.invoke(this);
 -                        if (value != null) {
 -                            buf.append(" ");
 -                            buf.append(key);
 -                            buf.append("=\"");
 -                            buf.append(value);
 -                            buf.append("\"");
 -                        }
 -                    }
 -                } catch (Exception e) {
 -                    logger.warn(e.getMessage(), e);
 -                }
 -            }
 -            buf.append(" />");
 -            return buf.toString();
 -        } catch (Throwable t) {
 -            logger.warn(t.getMessage(), t);
 -            return super.toString();
 -        }
 -    }
 -
 -}
 +/*
 + * 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.config;
 +
 +import org.apache.dubbo.common.Constants;
 +import org.apache.dubbo.common.URL;
 +import org.apache.dubbo.common.config.CompositeConfiguration;
 +import org.apache.dubbo.common.config.Configuration;
 +import org.apache.dubbo.common.extension.ExtensionLoader;
 +import org.apache.dubbo.common.logger.Logger;
 +import org.apache.dubbo.common.logger.LoggerFactory;
 +import org.apache.dubbo.common.utils.CollectionUtils;
 +import org.apache.dubbo.common.utils.ReflectUtils;
 +import org.apache.dubbo.common.utils.StringUtils;
 +import org.apache.dubbo.config.context.Environment;
 +import org.apache.dubbo.config.support.Parameter;
 +import org.apache.dubbo.config.utils.ConfigConverter;
++import org.apache.dubbo.rpc.model.ConsumerMethodModel;
 +
 +import javax.annotation.PostConstruct;
 +import java.io.Serializable;
 +import java.lang.reflect.Method;
 +import java.lang.reflect.Modifier;
 +import java.util.HashMap;
 +import java.util.Map;
 +import java.util.regex.Matcher;
 +import java.util.regex.Pattern;
 +
 +/**
 + * Utility methods and public methods for parsing configuration
 + *
 + * @export
 + */
 +public abstract class AbstractConfig implements Serializable {
 +
 +    protected static final Logger logger = LoggerFactory.getLogger(AbstractConfig.class);
 +    private static final long serialVersionUID = 4267533505537413570L;
 +    private static final int MAX_LENGTH = 200;
 +
 +    private static final int MAX_PATH_LENGTH = 200;
 +
 +    private static final Pattern PATTERN_NAME = Pattern.compile("[\\-._0-9a-zA-Z]+");
 +
 +    private static final Pattern PATTERN_MULTI_NAME = Pattern.compile("[,\\-._0-9a-zA-Z]+");
 +
 +    private static final Pattern PATTERN_METHOD_NAME = Pattern.compile("[a-zA-Z][0-9a-zA-Z]*");
 +
 +    private static final Pattern PATTERN_PATH = Pattern.compile("[/\\-$._0-9a-zA-Z]+");
 +
 +    private static final Pattern PATTERN_NAME_HAS_SYMBOL = Pattern.compile("[:*,/\\-._0-9a-zA-Z]+");
 +
 +    private static final Pattern PATTERN_KEY = Pattern.compile("[*,\\-._0-9a-zA-Z]+");
 +    private static final Map<String, String> legacyProperties = new HashMap<String, String>();
 +    private static final String[] SUFFIXES = new String[]{"Config", "Bean"};
 +
 +    private boolean init;
 +    private volatile Map<String, String> metaData;
 +
 +    static {
 +        legacyProperties.put("dubbo.protocol.name", "dubbo.service.protocol");
 +        legacyProperties.put("dubbo.protocol.host", "dubbo.service.server.host");
 +        legacyProperties.put("dubbo.protocol.port", "dubbo.service.server.port");
 +        legacyProperties.put("dubbo.protocol.threads", "dubbo.service.max.thread.pool.size");
 +        legacyProperties.put("dubbo.consumer.timeout", "dubbo.service.invoke.timeout");
 +        legacyProperties.put("dubbo.consumer.retries", "dubbo.service.max.retry.providers");
 +        legacyProperties.put("dubbo.consumer.check", "dubbo.service.allow.no.provider");
 +        legacyProperties.put("dubbo.service.url", "dubbo.service.address");
 +    }
 +
 +    protected String id;
 +
 +    private static String convertLegacyValue(String key, String value) {
 +        if (value != null && value.length() > 0) {
 +            if ("dubbo.service.max.retry.providers".equals(key)) {
 +                return String.valueOf(Integer.parseInt(value) - 1);
 +            } else if ("dubbo.service.allow.no.provider".equals(key)) {
 +                return String.valueOf(!Boolean.parseBoolean(value));
 +            }
 +        }
 +        return value;
 +    }
 +
 +    private static String getTagName(Class<?> cls) {
 +        String tag = cls.getSimpleName();
 +        for (String suffix : SUFFIXES) {
 +            if (tag.endsWith(suffix)) {
 +                tag = tag.substring(0, tag.length() - suffix.length());
 +                break;
 +            }
 +        }
 +        tag = tag.toLowerCase();
 +        return tag;
 +    }
 +
 +    protected static void appendParameters(Map<String, String> parameters, Object config) {
 +        appendParameters(parameters, config, null);
 +    }
 +
 +    @SuppressWarnings("unchecked")
 +    protected static void appendParameters(Map<String, String> parameters, Object config, String prefix) {
 +        if (config == null) {
 +            return;
 +        }
 +        Method[] methods = config.getClass().getMethods();
 +        for (Method method : methods) {
 +            try {
 +                String name = method.getName();
 +                if ((name.startsWith("get") || name.startsWith("is"))
 +                        && !"getClass".equals(name)
 +                        && Modifier.isPublic(method.getModifiers())
 +                        && method.getParameterTypes().length == 0
 +                        && isPrimitive(method.getReturnType())) {
 +                    Parameter parameter = method.getAnnotation(Parameter.class);
 +                    if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) {
 +                        continue;
 +                    }
 +                    int i = name.startsWith("get") ? 3 : 2;
 +                    String prop = StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), ".");
 +                    String key;
 +                    if (parameter != null && parameter.key().length() > 0) {
 +                        key = parameter.key();
 +                    } else {
 +                        key = prop;
 +                    }
 +                    Object value = method.invoke(config);
 +                    String str = String.valueOf(value).trim();
 +                    if (value != null && str.length() > 0) {
 +                        if (parameter != null && parameter.escaped()) {
 +                            str = URL.encode(str);
 +                        }
 +                        if (parameter != null && parameter.append()) {
 +                            String pre = parameters.get(Constants.DEFAULT_KEY + "." + key);
 +                            if (pre != null && pre.length() > 0) {
 +                                str = pre + "," + str;
 +                            }
 +                            pre = parameters.get(key);
 +                            if (pre != null && pre.length() > 0) {
 +                                str = pre + "," + str;
 +                            }
 +                        }
 +                        if (prefix != null && prefix.length() > 0) {
 +                            key = prefix + "." + key;
 +                        }
 +                        parameters.put(key, str);
 +                    } else if (parameter != null && parameter.required()) {
 +                        throw new IllegalStateException(config.getClass().getSimpleName() + "." + key + " == null");
 +                    }
 +                } else if ("getParameters".equals(name)
 +                        && Modifier.isPublic(method.getModifiers())
 +                        && method.getParameterTypes().length == 0
 +                        && method.getReturnType() == Map.class) {
 +                    Map<String, String> map = (Map<String, String>) method.invoke(config, new Object[0]);
 +                    if (map != null && map.size() > 0) {
 +                        String pre = (prefix != null && prefix.length() > 0 ? prefix + "." : "");
 +                        for (Map.Entry<String, String> entry : map.entrySet()) {
 +                            parameters.put(pre + entry.getKey().replace('-', '.'), entry.getValue());
 +                        }
 +                    }
 +                }
 +            } catch (Exception e) {
 +                throw new IllegalStateException(e.getMessage(), e);
 +            }
 +        }
 +    }
 +
-     protected static void appendAttributes(Map<Object, Object> parameters, Object config) {
++    protected static void appendAttributes(Map<String, Object> parameters, Object config) {
 +        appendAttributes(parameters, config, null);
 +    }
 +
-     protected static void appendAttributes(Map<Object, Object> parameters, Object config, String prefix) {
++    protected static void appendAttributes(Map<String, Object> parameters, Object config, String prefix) {
 +        if (config == null) {
 +            return;
 +        }
 +        Method[] methods = config.getClass().getMethods();
 +        for (Method method : methods) {
 +            try {
++                Parameter parameter = method.getAnnotation(Parameter.class);
++                if (parameter == null || !parameter.attribute()) {
++                    continue;
++                }
 +                String name = method.getName();
 +                if ((name.startsWith("get") || name.startsWith("is"))
 +                        && !"getClass".equals(name)
 +                        && Modifier.isPublic(method.getModifiers())
 +                        && method.getParameterTypes().length == 0
 +                        && isPrimitive(method.getReturnType())) {
-                     Parameter parameter = method.getAnnotation(Parameter.class);
-                     if (parameter == null || !parameter.attribute())
-                         continue;
 +                    String key;
 +                    if (parameter.key().length() > 0) {
 +                        key = parameter.key();
 +                    } else {
 +                        int i = name.startsWith("get") ? 3 : 2;
 +                        key = name.substring(i, i + 1).toLowerCase() + name.substring(i + 1);
 +                    }
 +                    Object value = method.invoke(config);
 +                    if (value != null) {
 +                        if (prefix != null && prefix.length() > 0) {
 +                            key = prefix + "." + key;
 +                        }
 +                        parameters.put(key, value);
 +                    }
 +                }
 +            } catch (Exception e) {
 +                throw new IllegalStateException(e.getMessage(), e);
 +            }
 +        }
 +    }
 +
++    protected static ConsumerMethodModel.AsyncMethodInfo convertMethodConfig2AyncInfo(MethodConfig methodConfig) {
++        if (methodConfig == null || (methodConfig.getOninvoke() == null && methodConfig.getOnreturn() == null && methodConfig.getOnthrow() == null)) {
++            return null;
++        }
++
++        //check config conflict
++        if (Boolean.FALSE.equals(methodConfig.isReturn()) && (methodConfig.getOnreturn() != null || methodConfig.getOnthrow() != null)) {
++            throw new IllegalStateException("method config error : return attribute must be set true when onreturn or onthrow has been set.");
++        }
++
++        ConsumerMethodModel.AsyncMethodInfo asyncMethodInfo = new ConsumerMethodModel.AsyncMethodInfo();
++
++        asyncMethodInfo.setOninvokeInstance(methodConfig.getOninvoke());
++        asyncMethodInfo.setOnreturnInstance(methodConfig.getOnreturn());
++        asyncMethodInfo.setOnthrowInstance(methodConfig.getOnthrow());
++
++        try {
++            String oninvokeMethod = methodConfig.getOninvokeMethod();
++            if (StringUtils.isNotEmpty(oninvokeMethod)) {
++                asyncMethodInfo.setOninvokeMethod(getMethodByName(methodConfig.getOninvoke().getClass(), oninvokeMethod));
++            }
++
++            String onreturnMethod = methodConfig.getOnreturnMethod();
++            if (StringUtils.isNotEmpty(onreturnMethod)) {
++                asyncMethodInfo.setOnreturnMethod(getMethodByName(methodConfig.getOnreturn().getClass(), onreturnMethod));
++            }
++
++            String onthrowMethod = methodConfig.getOnthrowMethod();
++            if (StringUtils.isNotEmpty(onthrowMethod)) {
++                asyncMethodInfo.setOnthrowMethod(getMethodByName(methodConfig.getOnthrow().getClass(), onthrowMethod));
++            }
++        } catch (Exception e) {
++            throw new IllegalStateException(e.getMessage(), e);
++        }
++
++        return asyncMethodInfo;
++    }
++
++    private static Method getMethodByName(Class<?> clazz, String methodName) {
++        try {
++            return ReflectUtils.findMethodByMethodName(clazz, methodName);
++        } catch (Exception e) {
++            throw new IllegalStateException(e);
++        }
++    }
++
 +    private static boolean isPrimitive(Class<?> type) {
 +        return type.isPrimitive()
 +                || type == String.class
 +                || type == Character.class
 +                || type == Boolean.class
 +                || type == Byte.class
 +                || type == Short.class
 +                || type == Integer.class
 +                || type == Long.class
 +                || type == Float.class
 +                || type == Double.class
 +                || type == Object.class;
 +    }
 +
 +    private static Object convertPrimitive(Class<?> type, String value) {
 +        if (type == char.class || type == Character.class) {
 +            return value.length() > 0 ? value.charAt(0) : '\0';
 +        } else if (type == boolean.class || type == Boolean.class) {
 +            return Boolean.valueOf(value);
 +        } else if (type == byte.class || type == Byte.class) {
 +            return Byte.valueOf(value);
 +        } else if (type == short.class || type == Short.class) {
 +            return Short.valueOf(value);
 +        } else if (type == int.class || type == Integer.class) {
 +            return Integer.valueOf(value);
 +        } else if (type == long.class || type == Long.class) {
 +            return Long.valueOf(value);
 +        } else if (type == float.class || type == Float.class) {
 +            return Float.valueOf(value);
 +        } else if (type == double.class || type == Double.class) {
 +            return Double.valueOf(value);
 +        }
 +        return value;
 +    }
 +
 +    protected static void checkExtension(Class<?> type, String property, String value) {
 +        checkName(property, value);
 +        if (value != null && value.length() > 0
 +                && !ExtensionLoader.getExtensionLoader(type).hasExtension(value)) {
 +            throw new IllegalStateException("No such extension " + value + " for " + property + "/" + type.getName());
 +        }
 +    }
 +
 +    protected static void checkMultiExtension(Class<?> type, String property, String value) {
 +        checkMultiName(property, value);
 +        if (value != null && value.length() > 0) {
 +            String[] values = value.split("\\s*[,]+\\s*");
 +            for (String v : values) {
 +                if (v.startsWith(Constants.REMOVE_VALUE_PREFIX)) {
 +                    v = v.substring(1);
 +                }
 +                if (Constants.DEFAULT_KEY.equals(v)) {
 +                    continue;
 +                }
 +                if (!ExtensionLoader.getExtensionLoader(type).hasExtension(v)) {
 +                    throw new IllegalStateException("No such extension " + v + " for " + property + "/" + type.getName());
 +                }
 +            }
 +        }
 +    }
 +
 +    protected static void checkLength(String property, String value) {
 +        checkProperty(property, value, MAX_LENGTH, null);
 +    }
 +
 +    protected static void checkPathLength(String property, String value) {
 +        checkProperty(property, value, MAX_PATH_LENGTH, null);
 +    }
 +
 +    protected static void checkName(String property, String value) {
 +        checkProperty(property, value, MAX_LENGTH, PATTERN_NAME);
 +    }
 +
 +    protected static void checkNameHasSymbol(String property, String value) {
 +        checkProperty(property, value, MAX_LENGTH, PATTERN_NAME_HAS_SYMBOL);
 +    }
 +
 +    protected static void checkKey(String property, String value) {
 +        checkProperty(property, value, MAX_LENGTH, PATTERN_KEY);
 +    }
 +
 +    protected static void checkMultiName(String property, String value) {
 +        checkProperty(property, value, MAX_LENGTH, PATTERN_MULTI_NAME);
 +    }
 +
 +    protected static void checkPathName(String property, String value) {
 +        checkProperty(property, value, MAX_PATH_LENGTH, PATTERN_PATH);
 +    }
 +
 +    protected static void checkMethodName(String property, String value) {
 +        checkProperty(property, value, MAX_LENGTH, PATTERN_METHOD_NAME);
 +    }
 +
 +    protected static void checkParameterName(Map<String, String> parameters) {
 +        if (parameters == null || parameters.size() == 0) {
 +            return;
 +        }
 +        for (Map.Entry<String, String> entry : parameters.entrySet()) {
 +            checkNameHasSymbol(entry.getKey(), entry.getValue());
 +        }
 +    }
 +
 +    protected static void checkProperty(String property, String value, int maxlength, Pattern pattern) {
 +        if (value == null || value.length() == 0) {
 +            return;
 +        }
 +        if (value.length() > maxlength) {
 +            throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" is longer than " + maxlength);
 +        }
 +        if (pattern != null) {
 +            Matcher matcher = pattern.matcher(value);
 +            if (!matcher.matches()) {
 +                throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" contains illegal " +
 +                        "character, only digit, letter, '-', '_' or '.' is legal.");
 +            }
 +        }
 +    }
 +
 +    @Parameter(excluded = true)
 +    public String getId() {
 +        return id;
 +    }
 +
 +    public void setId(String id) {
 +        this.id = id;
 +    }
 +
 +    protected void appendAnnotation(Class<?> annotationClass, Object annotation) {
 +        Method[] methods = annotationClass.getMethods();
 +        for (Method method : methods) {
 +            if (method.getDeclaringClass() != Object.class
 +                    && method.getReturnType() != void.class
 +                    && method.getParameterTypes().length == 0
 +                    && Modifier.isPublic(method.getModifiers())
 +                    && !Modifier.isStatic(method.getModifiers())) {
 +                try {
 +                    String property = method.getName();
 +                    if ("interfaceClass".equals(property) || "interfaceName".equals(property)) {
 +                        property = "interface";
 +                    }
 +                    String setter = "set" + property.substring(0, 1).toUpperCase() + property.substring(1);
 +                    Object value = method.invoke(annotation);
 +                    if (value != null && !value.equals(method.getDefaultValue())) {
 +                        Class<?> parameterType = ReflectUtils.getBoxedClass(method.getReturnType());
 +                        if ("filter".equals(property) || "listener".equals(property)) {
 +                            parameterType = String.class;
 +                            value = StringUtils.join((String[]) value, ",");
 +                        } else if ("parameters".equals(property)) {
 +                            parameterType = Map.class;
 +                            value = CollectionUtils.toStringMap((String[]) value);
 +                        }
 +                        try {
 +                            Method setterMethod = getClass().getMethod(setter, parameterType);
 +                            setterMethod.invoke(this, value);
 +                        } catch (NoSuchMethodException e) {
 +                            // ignore
 +                        }
 +                    }
 +                } catch (Throwable e) {
 +                    logger.error(e.getMessage(), e);
 +                }
 +            }
 +        }
 +    }
 +
 +
 +    /**
 +     * Should be called after Config was fully initialized.
 +     *
 +     * @return
 +     */
 +    public Map<String, String> getMetaData() {
 +        metaData = new HashMap<>();
 +        Method[] methods = this.getClass().getMethods();
 +        for (Method method : methods) {
 +            try {
 +                String name = method.getName();
 +                if ((name.startsWith("get") || name.startsWith("is"))
 +                        && !name.equals("get")
 +                        && !"getClass".equals(name)
 +                        && Modifier.isPublic(method.getModifiers())
 +                        && method.getParameterTypes().length == 0
 +                        && isPrimitive(method.getReturnType())) {
 +                    int i = name.startsWith("get") ? 3 : 2;
 +                    String prop = StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), ".");
 +                    String key;
 +                    Parameter parameter = method.getAnnotation(Parameter.class);
 +                    if (parameter != null && parameter.key().length() > 0) {
 +                        key = parameter.key();
 +                    } else {
 +                        key = prop;
 +                    }
 +                    if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) {
 +                        metaData.put(key, null);
 +                        continue;
 +                    }
 +                    Object value = method.invoke(this);
 +                    String str = String.valueOf(value).trim();
 +                    if (value != null && str.length() > 0) {
 +                        if (parameter != null && parameter.escaped()) {
 +                            str = URL.encode(str);
 +                        }
 +                        if (parameter != null && parameter.append()) {
 +                            String pre = String.valueOf(metaData.get(Constants.DEFAULT_KEY + "." + key));
 +                            if (pre != null && pre.length() > 0) {
 +                                str = pre + "," + str;
 +                            }
 +                            pre = String.valueOf(metaData.get(key));
 +                            if (pre != null && pre.length() > 0) {
 +                                str = pre + "," + str;
 +                            }
 +                        }
 +                      /*  if (prefix != null && prefix.length() > 0) {
 +                            key = prefix + "." + key;
 +                        }*/
 +                        metaData.put(key, str);
 +                    } else {
 +                        metaData.put(key, null);
 +                    }
 +                    // TODO check required somewhere else.
 +                    /*else if (parameter != null && parameter.required()) {
 +                        throw new IllegalStateException(this.getClass().getSimpleName() + "." + key + " == null");
 +                    }*/
 +                } else if ("getParameters".equals(name)
 +                        && Modifier.isPublic(method.getModifiers())
 +                        && method.getParameterTypes().length == 0
 +                        && method.getReturnType() == Map.class) {
 +                    Map<String, String> map = (Map<String, String>) method.invoke(this, new Object[0]);
 +                    if (map != null && map.size() > 0) {
 +//                            String pre = (prefix != null && prefix.length() > 0 ? prefix + "." : "");
 +                        for (Map.Entry<String, String> entry : map.entrySet()) {
 +                            metaData.put(entry.getKey().replace('-', '.'), entry.getValue());
 +                        }
 +                    }
 +                }
 +            } catch (Exception e) {
 +                System.out.println(this.getClass().getName());
 +                System.out.println(method.getName());
 +                throw new IllegalStateException(e.getMessage(), e);
 +            }
 +        }
 +        return metaData;
 +    }
 +
 +    public String getPrefix() {
 +        return Constants.DUBBO + "." + getTagName(this.getClass());
 +    }
 +
 +    /**
 +     * TODO
 +     * Currently, only support overriding of properties explicitly defined in Config class, doesn't support overriding of customized parameters stored in 'parameters'.
 +     */
 +    @PostConstruct
 +    public void refresh() {
 +        if (init) {
 +            return;
 +        }
 +        init = true;
 +
 +        try {
 +            Configuration configuration = ConfigConverter.toConfiguration(this);
 +            CompositeConfiguration compositeConfiguration = Environment.getInstance().getStartupCompositeConf(getPrefix(), getId());
 +            int index = 1;
 +            if (Environment.getInstance().isConfigCenterFirst()) {
 +                index = 2;
 +            }
 +            compositeConfiguration.addConfiguration(index, configuration);
 +            // loop methods, get override value and set the new value back to method
 +            Method[] methods = getClass().getMethods();
 +            for (Method method : methods) {
 +                if (isSetter(method)) {
 +                    try {
 +                        String value = compositeConfiguration.getString(extractPropertyName(method));
 +                        if (value != null) {
 +                            method.invoke(this, convertPrimitive(method.getParameterTypes()[0], value));
 +                        }
 +                    } catch (NoSuchMethodException e) {
 +                        logger.warn("Failed to override the property " + method.getName() + " in " + this.getClass().getSimpleName() + ", please make sure every property has a getter/setter pair.");
 +                    }
 +                }
 +            }
 +        } catch (Exception e) {
 +            logger.error("Failed to override ", e);
 +        }
 +    }
 +
 +    private static boolean isSetter(Method method) {
 +        if (method.getName().startsWith("set")
 +                && !"set".equals(method.getName())
 +                && Modifier.isPublic(method.getModifiers())
 +                && method.getParameterCount() == 1
 +                && isPrimitive(method.getParameterTypes()[0])) {
 +            return true;
 +        }
 +        return false;
 +    }
 +
 +    public String extractPropertyName(Method setter) throws Exception {
 +        String propertyName = setter.getName().substring("set".length());
 +        Method getter = null;
 +        try {
 +            getter = getClass().getMethod("get" + propertyName);
 +        } catch (NoSuchMethodException e) {
 +            getter = getClass().getMethod("is" + propertyName);
 +        }
 +        Parameter parameter = getter.getAnnotation(Parameter.class);
 +        if (parameter != null && StringUtils.isNotEmpty(parameter.key())) {
 +            propertyName = parameter.key();
 +        } else {
 +            propertyName = propertyName.toLowerCase();
 +        }
 +        return propertyName;
 +    }
 +
 +    @Override
 +    public String toString() {
 +        try {
 +            StringBuilder buf = new StringBuilder();
 +            buf.append("<dubbo:");
 +            buf.append(getTagName(getClass()));
 +            Method[] methods = getClass().getMethods();
 +            for (Method method : methods) {
 +                try {
 +                    String name = method.getName();
 +                    if ((name.startsWith("get") || name.startsWith("is"))
 +                            && !"getClass".equals(name) && !"get".equals(name) && !"is".equals(name)
 +                            && Modifier.isPublic(method.getModifiers())
 +                            && method.getParameterTypes().length == 0
 +                            && isPrimitive(method.getReturnType())) {
 +                        int i = name.startsWith("get") ? 3 : 2;
 +                        String key = name.substring(i, i + 1).toLowerCase() + name.substring(i + 1);
 +                        Object value = method.invoke(this);
 +                        if (value != null) {
 +                            buf.append(" ");
 +                            buf.append(key);
 +                            buf.append("=\"");
 +                            buf.append(value);
 +                            buf.append("\"");
 +                        }
 +                    }
 +                } catch (Exception e) {
 +                    logger.warn(e.getMessage(), e);
 +                }
 +            }
 +            buf.append(" />");
 +            return buf.toString();
 +        } catch (Throwable t) {
 +            logger.warn(t.getMessage(), t);
 +            return super.toString();
 +        }
 +    }
 +
 +    /**
 +     * FIXME check @Parameter(required=true) and any conditions that need to match.
 +     */
 +    public boolean isValid() {
 +        return true;
 +    }
 +
 +}
diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index 927fe51,61ed531..5587340
--- 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
@@@ -24,21 -24,18 +24,19 @@@ import org.apache.dubbo.common.config.A
  import org.apache.dubbo.common.extension.ExtensionLoader;
  import org.apache.dubbo.common.utils.ConfigUtils;
  import org.apache.dubbo.common.utils.NetUtils;
- import org.apache.dubbo.common.utils.ReflectUtils;
  import org.apache.dubbo.common.utils.StringUtils;
  import org.apache.dubbo.config.annotation.Reference;
- import org.apache.dubbo.config.model.ApplicationModel;
- import org.apache.dubbo.config.model.ConsumerModel;
  import org.apache.dubbo.config.support.Parameter;
 +import org.apache.dubbo.metadata.integration.MetadataReportService;
  import org.apache.dubbo.rpc.Invoker;
  import org.apache.dubbo.rpc.Protocol;
  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.model.ApplicationModel;
+ import org.apache.dubbo.rpc.model.ConsumerModel;
  import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;
  import org.apache.dubbo.rpc.service.GenericService;
  import org.apache.dubbo.rpc.support.ProtocolUtils;
diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
index 608b52d,e2d3969..82cf3b3
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
@@@ -27,10 -27,7 +27,8 @@@ import org.apache.dubbo.common.utils.Na
  import org.apache.dubbo.common.utils.StringUtils;
  import org.apache.dubbo.config.annotation.Service;
  import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker;
- import org.apache.dubbo.config.model.ApplicationModel;
- import org.apache.dubbo.config.model.ProviderModel;
  import org.apache.dubbo.config.support.Parameter;
 +import org.apache.dubbo.metadata.integration.MetadataReportService;
  import org.apache.dubbo.rpc.Exporter;
  import org.apache.dubbo.rpc.Invoker;
  import org.apache.dubbo.rpc.Protocol;
diff --cc dubbo-dependencies-bom/pom.xml
index 1c4cbc5,c95f748..242caab
--- a/dubbo-dependencies-bom/pom.xml
+++ b/dubbo-dependencies-bom/pom.xml
@@@ -98,11 -98,7 +98,12 @@@
          <kryo_version>4.0.1</kryo_version>
          <kryo_serializers_version>0.42</kryo_serializers_version>
          <fst_version>2.48-jdk-6</fst_version>
 +        <apollo_client_version>1.1.1</apollo_client_version>
 +        <archaius_version>0.7.6</archaius_version>
 +        <snakeyaml_version>1.20</snakeyaml_version>
 +        <commons_configuration_version>1.8</commons_configuration_version>
 +        <commons_lang3_version>3.8.1</commons_lang3_version>
+         <protostuff_version>1.5.9</protostuff_version>
  
          <rs_api_version>2.0</rs_api_version>
          <resteasy_version>3.0.19.Final</resteasy_version>