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 2019/07/27 07:50:48 UTC

[dubbo] 01/04: Merge branch 'master' into cloud-native

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

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

commit c5dd1ea581622f03038255a43a4f808707afe5f2
Merge: fe562c3 f2af6fd
Author: ken.lj <ke...@gmail.com>
AuthorDate: Sat Jul 27 08:46:57 2019 +0800

    Merge branch 'master' into cloud-native
    
    # Conflicts:
    #	dubbo-all/pom.xml
    #	dubbo-bom/pom.xml
    #	dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java
    #	dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
    #	dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
    #	dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigCenterConfig.java
    #	dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
    #	dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
    #	dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
    #	dubbo-configcenter/dubbo-configcenter-api/src/test/java/org/apache/dubbo/configcenter/mock/MockDynamicConfiguration.java
    #	dubbo-configcenter/dubbo-configcenter-consul/src/main/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfiguration.java
    #	dubbo-configcenter/dubbo-configcenter-etcd/src/test/java/org/apache/dubbo/configcenter/support/etcd/EtcdDynamicConfigurationTest.java
    #	dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
    #	dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java
    #	dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
    #	dubbo-metadata-report/dubbo-metadata-definition-protobuf/src/main/java/org/apache/dubbo/metadata/definition/protobuf/ProtobufTypeBuilder.java
    #	dubbo-metadata-report/dubbo-metadata-definition-protobuf/src/test/java/org/apache/dubbo/metadata/definition/protobuf/ProtobufTypeBuilderTest.java
    #	dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/model/MethodDefinition.java
    #	dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java
    #	dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java
    #	dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifierTest.java
    #	dubbo-metadata/pom.xml
    #	dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/AbstractConfiguratorListener.java
    #	dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java
    #	dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java
    #	dubbo-rpc/dubbo-rpc-xml/src/main/java/org/apache/dubbo/xml/rpc/protocol/xmlrpc/XmlRpcProtocol.java

 .travis.yml                                        |    2 -
 CHANGES.md                                         |  140 ++
 DISCLAIMER                                         |    1 -
 Jenkinsfile                                        |  138 ++
 README.md                                          |    4 +-
 dubbo-all/pom.xml                                  |    7 +-
 dubbo-bom/pom.xml                                  |    9 +-
 .../rpc/cluster/loadbalance/RandomLoadBalance.java |   15 +-
 .../router/condition/config/ListenableRouter.java  |    2 +-
 .../router/condition/config/ServiceRouter.java     |    2 +-
 .../dubbo/rpc/cluster/router/tag/TagRouter.java    |    2 +-
 .../cluster/router/tag/model/TagRouterRule.java    |    8 +-
 .../dubbo/rpc/cluster/support/ClusterUtils.java    |   51 +-
 .../support/wrapper/MockClusterInvoker.java        |   13 +-
 .../org/apache/dubbo/rpc/cluster/StickyTest.java   |    4 +-
 .../dubbo/rpc/cluster/merger/ResultMergerTest.java |   18 +-
 .../dubbo/rpc/cluster/router/TagRouterTest.java    |   45 +
 .../router/condition/ConditionRouterTest.java      |  131 +-
 .../support/AbstractClusterInvokerTest.java        |   21 +-
 .../rpc/cluster/support/ClusterUtilsTest.java      |   72 +
 .../support/FailoverClusterInvokerTest.java        |    2 +-
 .../dubbo/rpc/cluster/support/MenuService.java     |    4 +-
 .../support/wrapper/MockClusterInvokerTest.java    |   38 +-
 .../wrapper/MockProviderRpcExceptionTest.java      |  238 +++
 .../src/main/java/org/apache/dubbo/common/URL.java |  144 +-
 .../main/java/org/apache/dubbo/common/Version.java |   19 +-
 .../common/beanutil/JavaBeanSerializeUtil.java     |    4 +-
 .../org/apache/dubbo/common/bytecode/Proxy.java    |    5 +-
 .../dubbo/common/compiler/support/JdkCompiler.java |    2 +-
 .../common/config/AbstractPrefixConfiguration.java |   17 +-
 .../apache/dubbo/common/config/Environment.java    |    1 +
 .../common/config/EnvironmentConfiguration.java    |    8 +-
 .../config/configcenter/DynamicConfiguration.java  |   44 +-
 .../configcenter/nop/NopDynamicConfiguration.java  |    4 +-
 .../dubbo/common/constants/CommonConstants.java    |   17 +-
 .../dubbo/common/constants/QosConstants.java       |   12 +-
 .../extension/AdaptiveClassCodeGenerator.java      |  765 ++++-----
 .../dubbo/common/extension/ExtensionLoader.java    |   19 +-
 .../extension/support/ActivateComparator.java      |    2 +-
 .../java/org/apache/dubbo/common/io/Bytes.java     |   10 +
 .../org/apache/dubbo/common/json/JSONArray.java    |   10 +-
 .../org/apache/dubbo/common/json/JSONObject.java   |   10 +-
 .../org/apache/dubbo/common/json/JSONVisitor.java  |    2 +-
 .../dubbo/common/utils/CompatibleTypeUtils.java    |    2 +
 .../org/apache/dubbo/common/utils/IOUtils.java     |   22 +-
 .../org/apache/dubbo/common/utils/MethodUtils.java |   23 +
 .../org/apache/dubbo/common/utils/NetUtils.java    |   28 +-
 .../org/apache/dubbo/common/utils/PojoUtils.java   |    7 +-
 .../org/apache/dubbo/common/utils/StringUtils.java |   32 +
 .../org/apache/dubbo/common/utils/UrlUtils.java    |    1 +
 .../test/java/org/apache/dubbo/common/URLTest.java |   27 +-
 .../common/beanutil/JavaBeanSerializeUtilTest.java |   14 +-
 .../apache/dubbo/common/bytecode/MixinTest.java    |    7 +-
 .../apache/dubbo/common/bytecode/ProxyTest.java    |    6 +-
 .../apache/dubbo/common/bytecode/WrapperTest.java  |   20 +-
 .../common/compiler/support/ClassUtilsTest.java    |    2 +-
 .../config/EnvironmentConfigurationTest.java       |  104 ++
 .../common/config/InmemoryConfigurationTest.java   |   95 ++
 .../common/config/SystemConfigurationTest.java     |  117 ++
 .../common/extension/ExtensionLoaderTest.java      |   30 +-
 .../ext10_multi_names/Ext10MultiNames.java         |   10 +-
 .../impl/Ext10MultiNamesImpl.java}                 |    6 +-
 .../dubbo/common/extension/ext6_inject/Dao.java    |    2 +-
 .../extension/support/ActivateComparatorTest.java  |    1 -
 .../java/org/apache/dubbo/common/io/BytesTest.java |   14 +
 .../org/apache/dubbo/common/json/JSONTest.java     |    6 +-
 .../threadlocal/InternalThreadLocalTest.java       |   29 +-
 .../NamedInternalThreadFactoryTest.java            |    2 +-
 .../support/eager/EagerThreadPoolExecutorTest.java |    8 +-
 .../common/utils/CompatibleTypeUtilsTest.java      |    2 +-
 .../org/apache/dubbo/common/utils/IOUtilsTest.java |    3 +-
 .../apache/dubbo/common/utils/MethodUtilsTest.java |    4 +-
 .../apache/dubbo/common/utils/PojoUtilsTest.java   | 1699 ++++++++++----------
 .../dubbo/common/utils/ReflectUtilsTest.java       |    2 +-
 .../apache/dubbo/common/utils/StringUtilsTest.java |   14 +
 .../apache/dubbo/common/version/VersionTest.java   |    7 +
 ...mon.extension.ext10_multi_names.Ext10MultiNames |    1 +
 .../spring/context/annotation/EnableDubbo.java     |   12 +-
 .../alibaba/dubbo/remoting/RemotingException.java  |    4 +
 .../dubbo/remoting/exchange/ResponseCallback.java  |   23 +-
 .../dubbo/remoting/exchange/ResponseFuture.java    |   44 +-
 .../main/java/com/alibaba/dubbo/rpc/Result.java    |    4 +-
 .../java/com/alibaba/dubbo/rpc/RpcContext.java     |   24 +-
 .../dubbo/rpc/protocol/dubbo/FutureAdapter.java    |  147 ++
 .../com/alibaba/dubbo/rpc/support/RpcUtils.java    |    5 -
 ...atibleReferenceAnnotationBeanPostProcessor.java |  508 ------
 .../annotation/CompatibleReferenceBeanBuilder.java |  167 --
 ...mpatibleServiceAnnotationBeanPostProcessor.java |  525 ------
 .../annotation/CompatibleDubboComponentScan.java   |   66 -
 .../CompatibleDubboComponentScanRegistrar.java     |  110 --
 .../CompatibleAnnotationBeanDefinitionParser.java  |   93 --
 .../org/apache/dubbo/config/MethodConfigTest.java  |    7 +-
 .../java/org/apache/dubbo/rpc/RpcContextTest.java  |   37 +-
 .../org/apache/dubbo/service/ComplexObject.java    |    2 +-
 .../alibaba/dubbo/config/annotation/Reference.java |    0
 .../alibaba/dubbo/config/annotation/Service.java   |    0
 .../org/apache/dubbo/config/AbstractConfig.java    |   40 +-
 .../org/apache/dubbo/config/ApplicationConfig.java |   80 +-
 .../apache/dubbo/config/ConfigCenterConfig.java    |   22 +-
 .../org/apache/dubbo/config/ReferenceConfig.java   |    2 +-
 .../org/apache/dubbo/config/RegistryConfig.java    |   16 +
 .../org/apache/dubbo/config/ServiceConfig.java     |    2 +-
 .../apache/dubbo/config/annotation/Reference.java  |   25 +-
 .../config/context/ConfigConfigurationAdapter.java |   21 +-
 .../dubbo/config/telnet/ShutdownTelnetHandler.java |    2 +-
 .../dubbo/config/utils/ReferenceConfigCache.java   |    2 +-
 .../apache/dubbo/config/AbstractConfigTest.java    |   77 +
 .../apache/dubbo/config/ApplicationConfigTest.java |   34 +
 .../dubbo/config/ConfigCenterConfigTest.java       |   14 +
 .../apache/dubbo/config/ReferenceConfigTest.java   |   14 +-
 .../apache/dubbo/config/RegistryConfigTest.java    |   10 +
 .../dubbo/config/validation/ValidationTest.java    |    2 +-
 dubbo-config/dubbo-config-spring/pom.xml           |    1 +
 .../AbstractAnnotationConfigBeanBuilder.java       |    3 +
 .../AnnotatedInterfaceConfigBeanBuilder.java       |  215 +++
 .../AnnotationInjectedBeanPostProcessor.java       |  135 +-
 .../AnnotationPropertyValuesAdapter.java           |   39 +-
 .../ReferenceAnnotationBeanPostProcessor.java      |  122 +-
 .../factory/annotation/ReferenceBeanBuilder.java   |   84 +-
 .../ServiceAnnotationBeanPostProcessor.java        |  126 +-
 .../factory/annotation/ServiceBeanNameBuilder.java |   43 +-
 .../annotation/DubboConfigConfiguration.java       |    7 +-
 .../spring/schema/DubboBeanDefinitionParser.java   |    2 +-
 .../util/AnnotatedBeanDefinitionRegistryUtils.java |   64 +-
 .../dubbo/config/spring/util/AnnotationUtils.java  |  179 ++-
 .../dubbo/config/spring/util/BeanFactoryUtils.java |    6 +
 .../config/spring/SimpleRegistryExporter.java      |    4 +-
 .../spring/annotation/merged/MergedReference.java  |   34 +-
 .../merged/MergedService.java}                     |   33 +-
 .../AnnotationPropertyValuesAdapterTest.java       |   10 +-
 .../factory/annotation/MergedAnnotationTest.java   |   76 +
 .../ReferenceAnnotationBeanPostProcessorTest.java  |   60 +-
 .../annotation/ReferenceBeanBuilderTest.java       |    2 +-
 .../spring/context/annotation/EnableDubboTest.java |    5 +
 .../annotation/consumer/ConsumerConfiguration.java |   22 +-
 .../consumer/test/TestConsumerConfiguration.java   |   18 +-
 .../annotation/provider/HelloServiceImpl.java      |    3 +-
 .../DubboComponentScanRegistrarTest.java           |    2 +
 .../annotation/provider/DefaultHelloService.java   |    4 +-
 .../annotation/provider/ProviderConfiguration.java |    4 +-
 .../AnnotatedBeanDefinitionRegistryUtilsTest.java  |   74 +
 .../support/apollo/ApolloDynamicConfiguration.java |   10 +-
 .../consul/ConsulDynamicConfiguration.java         |   38 +-
 .../support/etcd/EtcdDynamicConfiguration.java     |   27 +-
 .../support/etcd/EtcdDynamicConfigurationTest.java |    5 +-
 .../support/nacos/NacosDynamicConfiguration.java   |   65 +-
 .../nacos/NacosDynamicConfigurationTest.java       |   55 +-
 .../support/zookeeper/CacheListener.java           |   13 +-
 .../zookeeper/ZookeeperDynamicConfiguration.java   |   46 +-
 .../ZookeeperDynamicConfigurationTest.java         |   29 +-
 dubbo-demo/README.md                               |    4 +-
 .../dubbo-demo-annotation-consumer/pom.xml         |   24 +
 .../dubbo-demo-annotation-provider/pom.xml         |   24 +
 .../dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml |   24 +
 .../dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml |   24 +
 dubbo-dependencies-bom/pom.xml                     |   15 +-
 .../dubbo/cache/support/expiring/ExpiringMap.java  |    5 +-
 .../apache/dubbo/cache/filter/CacheFilterTest.java |    4 +-
 .../support/jvalidation/JValidationTest.java       |    1 -
 .../jvalidation/mock/JValidatorTestTarget.java     |   10 +-
 .../dubbo-metadata-definition-protobuf}/pom.xml    |   40 +-
 ...e.dubbo.metadata.definition.builder.TypeBuilder |    1 +
 .../definition/protobuf}/model/GooglePB.java       |    2 +-
 .../protobuf/model/ServiceInterface.java           |    7 +-
 .../metadata/definition/TypeDefinitionBuilder.java |   18 +-
 .../definition/model/MethodDefinition.java         |   18 +-
 .../metadata/definition/model/TypeDefinition.java  |    9 +
 .../report/identifier/MetadataIdentifier.java      |   10 +-
 .../report/support/AbstractMetadataReport.java     |    4 +-
 .../dubbo/metadata/definition/MetadataTest.java    |   10 +-
 .../metadata/definition/common/ColorEnum.java      |    2 +-
 .../metadata/definition/service/ComplexObject.java |    2 +-
 .../report/identifier/MetadataIdentifierTest.java  |   11 +-
 .../report/support/AbstractMetadataReportTest.java |    8 +-
 .../metadata/store/InterfaceNameTestService2.java  |    2 +-
 .../store/etcd/EtcdMetadataReportTest.java         |    2 +
 .../metadata/store/nacos/NacosMetadataReport.java  |   12 +-
 .../store/nacos/NacosMetadataReportTest.java       |    8 +-
 .../metadata/store/redis/RedisMetadataReport.java  |    4 +-
 dubbo-metadata/pom.xml                             |    2 +
 .../dubbo/monitor/support/MonitorFilterTest.java   |   24 +-
 .../dubbo/monitor/dubbo/AppResponseBuilder.java    |   55 +
 .../dubbo/monitor/dubbo/MetricsFilterTest.java     |   80 +-
 .../dubbo/qos/command/util/CommandHelperTest.java  |    1 -
 .../integration/AbstractConfiguratorListener.java  |    7 +-
 .../registry/integration/RegistryDirectory.java    |    2 +-
 .../registry/integration/RegistryProtocol.java     |    4 +-
 .../dubbo/registry/PerformanceRegistryTest.java    |    1 -
 .../java/org/apache/dubbo/registry/ZKTools.java    |    3 +-
 .../registry/support/AbstractRegistryTest.java     |    2 +-
 .../registry/support/FailbackRegistryTest.java     |    4 +-
 .../dubbo/registry/consul/ConsulRegistry.java      |   30 +-
 .../registry/dubbo/RegistryDirectoryTest.java      |   64 +-
 .../dubbo/registry/dubbo/RegistryProtocolTest.java |   11 +-
 .../registry/dubbo/SimpleRegistryExporter.java     |    4 +-
 .../dubbo/registry/etcd/EtcdRegistryTest.java      |   30 +-
 .../registry/multicast/MulticastRegistry.java      |    4 +-
 .../multiple/MultipleRegistry2S2RTest.java         |   30 +-
 .../apache/dubbo/registry/nacos/NacosRegistry.java |   86 +-
 .../dubbo/registry/nacos/NacosServiceName.java     |  244 +++
 .../consumer/DemoServiceConsumerXmlBootstrap.java  |   10 +-
 .../dubbo/registry/nacos/NacosServiceNameTest.java |  123 ++
 .../META-INF/spring/dubbo-consumer-context.xml     |   14 +-
 .../META-INF/spring/dubbo-provider-context.xml     |    3 +-
 .../java/org/apache/dubbo/remoting/Constants.java  |    6 +-
 .../dubbo/remoting/buffer/ChannelBuffer.java       |    2 +-
 .../support/command/StatusTelnetHandler.java       |    2 +-
 .../dispatcher/WrappedChannelHandler.java          |    7 +-
 .../org/apache/dubbo/remoting/utils/UrlUtils.java  |    1 +
 .../apache/dubbo/remoting/RpcMessageHandler.java   |    2 +-
 .../dubbo/remoting/codec/ExchangeCodecTest.java    |   32 +-
 .../handler/ConnectChannelHandlerTest.java         |    2 +-
 .../handler/HeaderExchangeHandlerTest.java         |    2 +-
 .../handler/WrappedChannelHandlerTest.java         |    2 -
 .../remoting/transport/AbstractCodecTest.java      |    5 +-
 .../org/apache/dubbo/remoting/etcd/EtcdClient.java |    2 +-
 .../apache/dubbo/remoting/etcd/RetryPolicy.java    |    2 +-
 .../dubbo/remoting/etcd/jetcd/JEtcdClient.java     |   13 +-
 .../dubbo/remoting/etcd/jetcd/JEtcdClientTest.java |    4 +-
 .../remoting/transport/netty/NettyHelper.java      |    2 +-
 .../support/header/HeartbeatHandlerTest.java       |    4 +-
 .../transport/netty/ClientReconnectTest.java       |    8 +-
 .../remoting/transport/netty4/NettyChannel.java    |   48 +-
 .../remoting/transport/netty4/NettyClient.java     |   42 +-
 .../transport/netty4/NettyClientHandler.java       |    1 +
 .../remoting/transport/netty4/NettyServer.java     |   26 +-
 .../transport/netty4/NettyServerHandler.java       |   10 +-
 .../transport/netty4/NettyTransporter.java         |    3 +
 .../transport/netty4/ClientReconnectTest.java      |    8 +-
 .../zookeeper/curator/CuratorZookeeperClient.java  |    8 +-
 .../curator/CuratorZookeeperClientTest.java        |    7 +-
 .../curator/CuratorZookeeperTransporterTest.java   |    1 -
 .../java/org/apache/dubbo/rpc/AppResponse.java     |    4 +-
 .../org/apache/dubbo/rpc/AsyncContextImpl.java     |    4 -
 .../java/org/apache/dubbo/rpc/AsyncRpcResult.java  |   91 +-
 .../main/java/org/apache/dubbo/rpc/Constants.java  |    4 -
 .../java/org/apache/dubbo/rpc/FutureContext.java   |   64 +-
 .../main/java/org/apache/dubbo/rpc/InvokeMode.java |    2 +-
 .../src/main/java/org/apache/dubbo/rpc/Result.java |    6 +-
 .../main/java/org/apache/dubbo/rpc/RpcContext.java |    7 +-
 .../java/org/apache/dubbo/rpc/RpcException.java    |    7 +
 .../java/org/apache/dubbo/rpc/RpcInvocation.java   |    2 +-
 .../apache/dubbo/rpc/filter/AccessLogFilter.java   |    8 +-
 .../apache/dubbo/rpc/filter/ActiveLimitFilter.java |   18 +-
 .../dubbo/rpc/filter/ExecuteLimitFilter.java       |   13 +-
 .../rpc/model/invoker/ProviderInvokerWrapper.java  |    2 +-
 .../dubbo/rpc/protocol/AsyncToSyncInvoker.java     |    6 +-
 .../dubbo/rpc/protocol/ProtocolFilterWrapper.java  |   17 +-
 .../dubbo/rpc/protocol/dubbo/FutureAdapter.java    |    3 +
 .../dubbo/rpc/proxy/AbstractProxyInvoker.java      |    6 +-
 .../org/apache/dubbo/rpc/support/RpcUtils.java     |   18 +-
 .../java/org/apache/dubbo/rpc/AppResponseTest.java |    4 +-
 .../org/apache/dubbo/rpc/FutureContextTest.java    |   53 +
 .../java/org/apache/dubbo/rpc/RpcContextTest.java  |    8 +-
 .../dubbo/rpc/filter/AccessLogFilterTest.java      |   20 +-
 .../rpc/filter/ConsumerContextFilterTest.java      |    3 +-
 .../apache/dubbo/rpc/filter/tps/StatItemTest.java  |    4 +-
 .../apache/dubbo/rpc/support/MockInvokerTest.java  |  139 ++
 .../org/apache/dubbo/rpc/support/RpcUtilsTest.java |    8 +-
 .../rpc/protocol/dubbo/CallbackServiceCodec.java   |    4 +-
 .../dubbo/rpc/protocol/dubbo/DubboCodec.java       |    6 +-
 .../dubbo/rpc/protocol/dubbo/DubboInvoker.java     |   17 +-
 .../protocol/dubbo/telnet/ChangeTelnetHandler.java |    2 +-
 .../protocol/dubbo/DubboInvokerAvilableTest.java   |   18 +-
 .../rpc/protocol/dubbo/DubboProtocolTest.java      |   36 +-
 .../rpc/protocol/dubbo/ExplicitCallbackTest.java   |   12 +-
 .../dubbo/rpc/protocol/dubbo/IDemoService.java     |    2 +-
 .../rpc/protocol/dubbo/ImplicitCallBackTest.java   |   22 +-
 .../dubbo/ReferenceCountExchangeClientTest.java    |   12 +-
 .../dubbo/decode/DubboTelnetDecodeTest.java        |    2 +-
 .../dubbo/telnet/CurrentTelnetHandlerTest.java     |    1 -
 .../rpc/protocol/hessian/HessianProtocol.java      |    2 +-
 .../dubbo/rpc/protocol/http/HttpProtocol.java      |    2 +-
 .../dubbo/rpc/protocol/http/HttpProtocolTest.java  |    2 +-
 .../rpc/protocol/jsonrpc/JsonRpcProtocol.java      |    4 +-
 .../rpc/protocol/nativethrift/DemoService.java     |   24 +-
 .../rpc/protocol/nativethrift/UserService.java     |    4 +-
 .../dubbo/rpc/protocol/rest/RestProtocol.java      |    1 +
 .../integration/swagger/DubboSwaggerService.java   |    4 +-
 .../rpc/protocol/rest/support/LoggingFilter.java   |    5 +-
 .../DubboSwaggerApiListingResourceTest.java        |    2 -
 .../dubbo/rpc/protocol/rmi/RmiProtocolTest.java    |    7 +-
 .../rpc/protocol/thrift/ClassNameGenerator.java    |    4 +-
 .../dubbo/rpc/protocol/thrift/ThriftInvoker.java   |    6 +-
 .../src/test/java/ClassNameTestDubbo.java          |    2 +-
 .../src/test/java/ClassNameTestThrift.java         |    4 +-
 .../java/org/apache/dubbo/rpc/gen/dubbo/Demo.java  |   14 +-
 .../java/org/apache/dubbo/rpc/gen/thrift/Demo.java |   30 +-
 .../dubbo/rpc/protocol/thrift/ThriftCodecTest.java |    2 +-
 .../xml/rpc/protocol/xmlrpc/XmlRpcProtocol.java    |    7 +-
 .../protocol/xmlrpc/XmlRpcProxyFactoryBean.java    |    2 +-
 .../common/serialize/avro/AvroObjectInput.java     |    3 +-
 .../common/serialize/avro/AvroObjectOutput.java    |    5 +-
 .../support/GenericProtobufObjectInput.java        |   37 +-
 .../support/GenericProtobufObjectOutput.java       |   42 +-
 .../serialize/protobuf/support/MapValue.java       |  830 ++++++++++
 .../protostuff/delegate/SqlDateDelegate.java       |   55 +
 .../serialize/protostuff/utils/WrapperUtils.java   |    3 +
 .../serialize/base/AbstractSerializationTest.java  |    8 +-
 .../serialize/hessian2/Hessian2PersonOkTest.java   |    1 -
 .../dubbo/common/serialize/model/AnimalEnum.java   |    2 +-
 .../support/GenericProtobufObjectOutputTest.java   |  122 +-
 .../serialize/protobuf/support/model/GooglePB.java |    4 +-
 .../protostuff/ProtostuffObjectOutputTest.java     |   32 +
 .../protostuff/ProtostuffSerializationTest.java    |    1 -
 .../support/SerializableClassRegistryTest.java     |    1 -
 pom.xml                                            |    9 +-
 307 files changed, 7221 insertions(+), 4327 deletions(-)

diff --cc dubbo-all/pom.xml
index 473de7e,cf26097..f9932a1
--- a/dubbo-all/pom.xml
+++ b/dubbo-all/pom.xml
@@@ -787,9 -761,13 +788,13 @@@
                                      </resource>
                                  </transformer>
                                  <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
 -                                    <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory
 +                                    <resource>META-INF/dubbo/internal/org.apache.dubbo.registry.client.ServiceDiscoveryFactory
                                      </resource>
                                  </transformer>
+                                 <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+                                     <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.definition.builder.TypeBuilder
+                                     </resource>
+                                 </transformer>
                              </transformers>
                              <filters>
                                  <filter>
diff --cc dubbo-bom/pom.xml
index a98794f,5ab6604..175a9cf
--- a/dubbo-bom/pom.xml
+++ b/dubbo-bom/pom.xml
@@@ -425,6 -422,16 +425,11 @@@
                  <artifactId>dubbo-configcenter-nacos</artifactId>
                  <version>${project.version}</version>
              </dependency>
+             <dependency>
 -                <groupId>org.apache.dubbo</groupId>
 -                <artifactId>dubbo-metadata-definition</artifactId>
 -                <version>${project.version}</version>
 -            </dependency>
 -            <dependency>
+                 <groupId>org.apache.dubbo</groupId>
+                 <artifactId>dubbo-metadata-definition-protobuf</artifactId>
+                 <version>${project.version}</version>
+             </dependency>
          </dependencies>
      </dependencyManagement>
  
diff --cc dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
index cf335b4,1880874..bb2b40b
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
@@@ -155,9 -155,12 +155,12 @@@ public abstract class Proxy 
  
                  for (Method method : ics[i].getMethods()) {
                      String desc = ReflectUtils.getDesc(method);
 -                    if (worked.contains(desc)) {
 +                    if (worked.contains(desc) || Modifier.isStatic(method.getModifiers())) {
                          continue;
                      }
+                     if (ics[i].isInterface() && Modifier.isStatic(method.getModifiers())) {
+                         continue;
+                     }
                      worked.add(desc);
  
                      int ix = methods.size();
diff --cc dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java
index f5bf9a4,357632c..239208f
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java
@@@ -14,8 -14,9 +14,9 @@@
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
 -package org.apache.dubbo.configcenter;
 +package org.apache.dubbo.common.config.configcenter;
  
+ import org.apache.dubbo.common.URL;
  import org.apache.dubbo.common.config.Configuration;
  import org.apache.dubbo.common.config.Environment;
  
@@@ -127,69 -111,12 +117,68 @@@ public interface DynamicConfiguration e
      }
  
      /**
-      * {@see #getConfig(String, String, long)}
-      * <p>
       * This method are mostly used to get a compound config file, such as a complete dubbo.properties file.
+      * Also {@see #getConfig(String, String, long)}
       */
-     String getConfigs(String key, String group, long timeout) throws IllegalStateException;
+     String getProperties(String key, String group, long timeout) throws IllegalStateException;
  
      /**
 +     * Publish Config mapped to the given key and the given group.
 +     *
 +     * @param key     the key to represent a configuration
 +     * @param group   the group where the key belongs to
 +     * @param content the content of configuration
 +     * @return <code>true</code> if success, or <code>false</code>
 +     * @throws UnsupportedOperationException If the under layer does not support
 +     * @since 2.7.4
 +     */
 +    default boolean publishConfig(String key, String group, String content) throws UnsupportedOperationException {
 +        throw new UnsupportedOperationException("No support");
 +    }
 +
 +    /**
 +     * Get the config keys by the specified group
 +     *
 +     * @param group the specified group
 +     * @return the read-only non-null sorted {@link Set set} of config keys
 +     * @throws UnsupportedOperationException If the under layer does not support
 +     * @since 2.7.4
 +     */
 +    default SortedSet<String> getConfigKeys(String group) throws UnsupportedOperationException {
 +        throw new UnsupportedOperationException("No support");
 +    }
 +
 +    /**
 +     * Get the {@link SortedMap} with with config keys and contents value by the specified group
 +     *
 +     * @param group the specified group
 +     * @return the read-only non-null sorted {@link SortedMap map}
 +     * @throws UnsupportedOperationException If the under layer does not support
 +     * @since 2.7.4
 +     */
 +    default SortedMap<String, String> getConfigs(String group) throws UnsupportedOperationException {
 +        return getConfigs(group, -1);
 +    }
 +
 +    /**
 +     * Get the {@link SortedMap} with with config keys and content value by the specified group
 +     *
 +     * @param group   the specified group
 +     * @param timeout the millisecond for timeout
 +     * @return the read-only non-null sorted {@link SortedMap map}
 +     * @throws UnsupportedOperationException If the under layer does not support
 +     * @throws IllegalStateException         If timeout exceeds
 +     * @since 2.7.4
 +     */
 +    default SortedMap<String, String> getConfigs(String group, long timeout) throws UnsupportedOperationException,
 +            IllegalStateException {
 +        SortedMap<String, String> configs = new TreeMap<>();
 +        SortedSet<String> configKeys = getConfigKeys(group);
 +        configKeys.forEach(key -> configs.put(key, getConfig(key, group, timeout)));
 +        return Collections.unmodifiableSortedMap(configs);
 +    }
 +
 +    /**
       * Find DynamicConfiguration instance
       *
       * @return DynamicConfiguration instance
diff --cc dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java
index 14accb2,6316821..23a2544
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java
@@@ -55,23 -52,7 +55,23 @@@ public class NopDynamicConfiguration im
      }
  
      @Override
-     public String getConfigs(String key, String group, long timeout) throws IllegalStateException {
+     public String getProperties(String key, String group, long timeout) throws IllegalStateException {
          return null;
      }
 +
 +    /**
 +     * @since 2.7.4
 +     */
 +    @Override
 +    public boolean publishConfig(String key, String group, String content) {
 +        return true;
 +    }
 +
 +    /**
 +     * @since 2.7.4
 +     */
 +    @Override
 +    public SortedSet<String> getConfigKeys(String group) {
 +        return emptySortedSet();
 +    }
  }
diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
index b33ec75,aa723de..1958372
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
@@@ -379,11 -382,45 +387,53 @@@ public class ApplicationConfig extends 
          return !StringUtils.isEmpty(name);
      }
  
 +    public String getMetadata() {
 +        return metadata;
 +    }
 +
 +    public void setMetadata(String metadata) {
 +        this.metadata = metadata;
 +    }
++
+     @Override
+     public void refresh() {
+         super.refresh();
+         appendEnvironmentProperties();
+     }
+ 
+     /**
+      * 1. OS Environment: DUBBO_LABELS=tag=pre;key=value
+      * 2. JVM Options: -Denv_keys = DUBBO_KEY1, DUBBO_KEY2
+      */
+     private void appendEnvironmentProperties() {
+         String rawLabels = ConfigurationUtils.getProperty(DUBBO_LABELS);
+         if (StringUtils.isNotEmpty(rawLabels)) {
+             String[] labelPairs = SEMICOLON_SPLIT_PATTERN.split(rawLabels);
+             for (String pair : labelPairs) {
+                 String[] label = EQUAL_SPLIT_PATTERN.split(pair);
+                 if (label.length == 2) {
+                     updateParameters(parameters, label[0], label[1]);
+                 }
+             }
+         }
+ 
+         String rawKeys = ConfigurationUtils.getProperty(DUBBO_ENV_KEYS);
+         if (StringUtils.isNotEmpty(rawKeys)) {
+             String[] keys = COMMA_SPLIT_PATTERN.split(rawKeys);
+             for (String key : keys) {
+                 String value = ConfigurationUtils.getProperty(key);
+                 if (value != null) {
+                     updateParameters(parameters, key, value);
+                 }
+             }
+         }
+     }
+ 
+     private void updateParameters(Map<String, String> map, String key, String value) {
+         if (parameters == null) {
+             parameters = new HashMap<>();
+         }
+         parameters.put(key, value);
+     }
+ 
  }
diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index e98039c,3065a63..13ec542
--- 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
@@@ -1,694 -1,664 +1,694 @@@
 -/*
 - * 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.URL;
 -import org.apache.dubbo.common.Version;
 -import org.apache.dubbo.common.bytecode.Wrapper;
 -import org.apache.dubbo.common.extension.ExtensionLoader;
 -import org.apache.dubbo.common.utils.ClassUtils;
 -import org.apache.dubbo.common.utils.CollectionUtils;
 -import org.apache.dubbo.common.utils.ConfigUtils;
 -import org.apache.dubbo.common.utils.NetUtils;
 -import org.apache.dubbo.common.utils.StringUtils;
 -import org.apache.dubbo.config.annotation.Reference;
 -import org.apache.dubbo.config.context.ConfigManager;
 -import org.apache.dubbo.config.support.Parameter;
 -import org.apache.dubbo.metadata.integration.MetadataReportService;
 -import org.apache.dubbo.remoting.Constants;
 -import org.apache.dubbo.rpc.Invoker;
 -import org.apache.dubbo.rpc.Protocol;
 -import org.apache.dubbo.rpc.ProxyFactory;
 -import org.apache.dubbo.rpc.cluster.Cluster;
 -import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
 -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;
 -
 -import java.io.File;
 -import java.io.FileInputStream;
 -import java.io.IOException;
 -import java.lang.reflect.Method;
 -import java.util.ArrayList;
 -import java.util.Arrays;
 -import java.util.HashMap;
 -import java.util.HashSet;
 -import java.util.List;
 -import java.util.Map;
 -import java.util.Properties;
 -
 -import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
 -import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;
 -import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
 -import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
 -import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
 -import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
 -import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
 -import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;
 -import static org.apache.dubbo.common.constants.CommonConstants.SEMICOLON_SPLIT_PATTERN;
 -import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
 -import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
 -import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
 -import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
 -import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
 -import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
 -import static org.apache.dubbo.registry.Constants.CONSUMER_PROTOCOL;
 -import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
 -import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
 -import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost;
 -
 -/**
 - * ReferenceConfig
 - *
 - * @export
 - */
 -public class ReferenceConfig<T> extends AbstractReferenceConfig {
 -
 -    private static final long serialVersionUID = -5864351140409987595L;
 -
 -    /**
 -     * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios.
 -     * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}.
 -     * For example:
 -     *
 -     * <li>when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample,
 -     * then the protocol is <b>RegistryProtocol</b></li>
 -     *
 -     * <li>when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then
 -     * the protocol is <b>DubboProtocol</b></li>
 -     * <p>
 -     * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two
 -     * layers, and eventually will get a <b>ProtocolFilterWrapper</b> or <b>ProtocolListenerWrapper</b>
 -     */
 -    private static final Protocol REF_PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
 -
 -    /**
 -     * The {@link Cluster}'s implementation with adaptive functionality, and actually it will get a {@link Cluster}'s
 -     * specific implementation who is wrapped with <b>MockClusterInvoker</b>
 -     */
 -    private static final Cluster CLUSTER = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension();
 -
 -    /**
 -     * A {@link ProxyFactory} implementation that will generate a reference service's proxy,the JavassistProxyFactory is
 -     * its default implementation
 -     */
 -    private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
 -
 -    /**
 -     * The url of the reference service
 -     */
 -    private final List<URL> urls = new ArrayList<URL>();
 -
 -    /**
 -     * The interface name of the reference service
 -     */
 -    private String interfaceName;
 -
 -    /**
 -     * The interface class of the reference service
 -     */
 -    private Class<?> interfaceClass;
 -
 -    /**
 -     * client type
 -     */
 -    private String client;
 -
 -    /**
 -     * The url for peer-to-peer invocation
 -     */
 -    private String url;
 -
 -    /**
 -     * The method configs
 -     */
 -    private List<MethodConfig> methods;
 -
 -    /**
 -     * The consumer config (default)
 -     */
 -    private ConsumerConfig consumer;
 -
 -    /**
 -     * Only the service provider of the specified protocol is invoked, and other protocols are ignored.
 -     */
 -    private String protocol;
 -
 -    /**
 -     * The interface proxy reference
 -     */
 -    private transient volatile T ref;
 -
 -    /**
 -     * The invoker of the reference service
 -     */
 -    private transient volatile Invoker<?> invoker;
 -
 -    /**
 -     * The flag whether the ReferenceConfig has been initialized
 -     */
 -    private transient volatile boolean initialized;
 -
 -    /**
 -     * whether this ReferenceConfig has been destroyed
 -     */
 -    private transient volatile boolean destroyed;
 -
 -    @SuppressWarnings("unused")
 -    private final Object finalizerGuardian = new Object() {
 -        @Override
 -        protected void finalize() throws Throwable {
 -            super.finalize();
 -
 -            if (!ReferenceConfig.this.destroyed) {
 -                logger.warn("ReferenceConfig(" + url + ") is not DESTROYED when FINALIZE");
 -
 -                /* don't destroy for now
 -                try {
 -                    ReferenceConfig.this.destroy();
 -                } catch (Throwable t) {
 -                        logger.warn("Unexpected err when destroy invoker of ReferenceConfig(" + url + ") in finalize method!", t);
 -                }
 -                */
 -            }
 -        }
 -    };
 -
 -    public ReferenceConfig() {
 -    }
 -
 -    public ReferenceConfig(Reference reference) {
 -        appendAnnotation(Reference.class, reference);
 -        setMethods(MethodConfig.constructMethodConfig(reference.methods()));
 -    }
 -
 -    public URL toUrl() {
 -        return urls.isEmpty() ? null : urls.iterator().next();
 -    }
 -
 -    public List<URL> toUrls() {
 -        return urls;
 -    }
 -
 -    /**
 -     * This method should be called right after the creation of this class's instance, before any property in other config modules is used.
 -     * Check each config modules are created properly and override their properties if necessary.
 -     */
 -    public void checkAndUpdateSubConfigs() {
 -        if (StringUtils.isEmpty(interfaceName)) {
 -            throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
 -        }
 -        completeCompoundConfigs();
 -        startConfigCenter();
 -        // get consumer's global configuration
 -        checkDefault();
 -        this.refresh();
 -        if (getGeneric() == null && getConsumer() != null) {
 -            setGeneric(getConsumer().getGeneric());
 -        }
 -        if (ProtocolUtils.isGeneric(getGeneric())) {
 -            interfaceClass = GenericService.class;
 -        } else {
 -            try {
 -                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
 -                        .getContextClassLoader());
 -            } catch (ClassNotFoundException e) {
 -                throw new IllegalStateException(e.getMessage(), e);
 -            }
 -            checkInterfaceAndMethods(interfaceClass, methods);
 -        }
 -        resolveFile();
 -        checkApplication();
 -        checkMetadataReport();
 -    }
 -
 -    public synchronized T get() {
 -        checkAndUpdateSubConfigs();
 -
 -        if (destroyed) {
 -            throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
 -        }
 -        if (ref == null) {
 -            init();
 -        }
 -        return ref;
 -    }
 -
 -    public synchronized void destroy() {
 -        if (ref == null) {
 -            return;
 -        }
 -        if (destroyed) {
 -            return;
 -        }
 -        destroyed = true;
 -        try {
 -            invoker.destroy();
 -        } catch (Throwable t) {
 -            logger.warn("Unexpected error occured when destroy invoker of ReferenceConfig(" + url + ").", t);
 -        }
 -        invoker = null;
 -        ref = null;
 -    }
 -
 -    private void init() {
 -        if (initialized) {
 -            return;
 -        }
 -        checkStubAndLocal(interfaceClass);
 -        checkMock(interfaceClass);
 -        Map<String, String> map = new HashMap<String, String>();
 -
 -        map.put(SIDE_KEY, CONSUMER_SIDE);
 -
 -        appendRuntimeParameters(map);
 -        if (!isGeneric()) {
 -            String revision = Version.getVersion(interfaceClass, version);
 -            if (revision != null && revision.length() > 0) {
 -                map.put(REVISION_KEY, revision);
 -            }
 -
 -            String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
 -            if (methods.length == 0) {
 -                logger.warn("No method found in service interface " + interfaceClass.getName());
 -                map.put(METHODS_KEY, ANY_VALUE);
 -            } else {
 -                map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), COMMA_SEPARATOR));
 -            }
 -        }
 -        map.put(INTERFACE_KEY, interfaceName);
 -        appendParameters(map, metrics);
 -        appendParameters(map, application);
 -        appendParameters(map, module);
 -        // remove 'default.' prefix for configs from ConsumerConfig
 -        // appendParameters(map, consumer, Constants.DEFAULT_KEY);
 -        appendParameters(map, consumer);
 -        appendParameters(map, this);
 -        Map<String, Object> attributes = null;
 -        if (CollectionUtils.isNotEmpty(methods)) {
 -            attributes = new HashMap<String, Object>();
 -            for (MethodConfig methodConfig : methods) {
 -                appendParameters(map, methodConfig, methodConfig.getName());
 -                String retryKey = methodConfig.getName() + ".retry";
 -                if (map.containsKey(retryKey)) {
 -                    String retryValue = map.remove(retryKey);
 -                    if ("false".equals(retryValue)) {
 -                        map.put(methodConfig.getName() + ".retries", "0");
 -                    }
 -                }
 -                attributes.put(methodConfig.getName(), convertMethodConfig2AsyncInfo(methodConfig));
 -            }
 -        }
 -
 -        String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);
 -        if (StringUtils.isEmpty(hostToRegistry)) {
 -            hostToRegistry = NetUtils.getLocalHost();
 -        } else if (isInvalidLocalHost(hostToRegistry)) {
 -            throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
 -        }
 -        map.put(REGISTER_IP_KEY, hostToRegistry);
 -
 -        ref = createProxy(map);
 -
 -        String serviceKey = URL.buildKey(interfaceName, group, version);
 -        ApplicationModel.initConsumerModel(serviceKey, buildConsumerModel(serviceKey, attributes));
 -        initialized = true;
 -    }
 -
 -    private ConsumerModel buildConsumerModel(String serviceKey, Map<String, Object> attributes) {
 -        Method[] methods = interfaceClass.getMethods();
 -        Class serviceInterface = interfaceClass;
 -        if (interfaceClass == GenericService.class) {
 -            try {
 -                serviceInterface = Class.forName(interfaceName);
 -                methods = serviceInterface.getMethods();
 -            } catch (ClassNotFoundException e) {
 -                methods = interfaceClass.getMethods();
 -            }
 -        }
 -        return new ConsumerModel(serviceKey, serviceInterface, ref, methods, attributes);
 -    }
 -
 -    @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
 -    private T createProxy(Map<String, String> map) {
 -        if (shouldJvmRefer(map)) {
 -            URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
 -            invoker = REF_PROTOCOL.refer(interfaceClass, url);
 -            if (logger.isInfoEnabled()) {
 -                logger.info("Using injvm service " + interfaceClass.getName());
 -            }
 -        } else {
 -            urls.clear(); // reference retry init will add url to urls, lead to OOM
 -            if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address.
 -                String[] us = SEMICOLON_SPLIT_PATTERN.split(url);
 -                if (us != null && us.length > 0) {
 -                    for (String u : us) {
 -                        URL url = URL.valueOf(u);
 -                        if (StringUtils.isEmpty(url.getPath())) {
 -                            url = url.setPath(interfaceName);
 -                        }
 -                        if (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
 -                            urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
 -                        } else {
 -                            urls.add(ClusterUtils.mergeUrl(url, map));
 -                        }
 -                    }
 -                }
 -            } else { // assemble URL from register center's configuration
 -                // if protocols not injvm checkRegistry
 -                if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())){
 -                    checkRegistry();
 -                    List<URL> us = loadRegistries(false);
 -                    if (CollectionUtils.isNotEmpty(us)) {
 -                        for (URL u : us) {
 -                            URL monitorUrl = loadMonitor(u);
 -                            if (monitorUrl != null) {
 -                                map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
 -                            }
 -                            urls.add(u.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
 -                        }
 -                    }
 -                    if (urls.isEmpty()) {
 -                        throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config.");
 -                    }
 -                }
 -            }
 -
 -            if (urls.size() == 1) {
 -                invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));
 -            } else {
 -                List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
 -                URL registryURL = null;
 -                for (URL url : urls) {
 -                    invokers.add(REF_PROTOCOL.refer(interfaceClass, url));
 -                    if (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
 -                        registryURL = url; // use last registry url
 -                    }
 -                }
 -                if (registryURL != null) { // registry url is available
 -                    // use RegistryAwareCluster only when register's CLUSTER is available
 -                    URL u = registryURL.addParameter(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, must be direct invoke.
 -                    invoker = CLUSTER.join(new StaticDirectory(invokers));
 -                }
 -            }
 -        }
 -
 -        if (shouldCheck() && !invoker.isAvailable()) {
 -            throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());
 -        }
 -        if (logger.isInfoEnabled()) {
 -            logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
 -        }
 -        /**
 -         * @since 2.7.0
 -         * ServiceData Store
 -         */
 -        MetadataReportService metadataReportService = null;
 -        if ((metadataReportService = getMetadataReportService()) != null) {
 -            URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map);
 -            metadataReportService.publishConsumer(consumerURL);
 -        }
 -        // create service proxy
 -        return (T) PROXY_FACTORY.getProxy(invoker);
 -    }
 -
 -    /**
 -     * Figure out should refer the service in the same JVM from configurations. The default behavior is true
 -     * 1. if injvm is specified, then use it
 -     * 2. then if a url is specified, then assume it's a remote call
 -     * 3. otherwise, check scope parameter
 -     * 4. if scope is not specified but the target service is provided in the same JVM, then prefer to make the local
 -     * call, which is the default behavior
 -     */
 -    protected boolean shouldJvmRefer(Map<String, String> map) {
 -        URL tmpUrl = new URL("temp", "localhost", 0, map);
 -        boolean isJvmRefer;
 -        if (isInjvm() == null) {
 -            // if a url is specified, don't do local reference
 -            if (url != null && url.length() > 0) {
 -                isJvmRefer = false;
 -            } else {
 -                // by default, reference local service if there is
 -                isJvmRefer = InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl);
 -            }
 -        } else {
 -            isJvmRefer = isInjvm();
 -        }
 -        return isJvmRefer;
 -    }
 -
 -    protected boolean shouldCheck() {
 -        Boolean shouldCheck = isCheck();
 -        if (shouldCheck == null && getConsumer() != null) {
 -            shouldCheck = getConsumer().isCheck();
 -        }
 -        if (shouldCheck == null) {
 -            // default true
 -            shouldCheck = true;
 -        }
 -        return shouldCheck;
 -    }
 -
 -    protected boolean shouldInit() {
 -        Boolean shouldInit = isInit();
 -        if (shouldInit == null && getConsumer() != null) {
 -            shouldInit = getConsumer().isInit();
 -        }
 -        if (shouldInit == null) {
 -            // default is false
 -            return false;
 -        }
 -        return shouldInit;
 -    }
 -
 -    private void checkDefault() {
 -        if (consumer != null) {
 -            return;
 -        }
 -        setConsumer(ConfigManager.getInstance().getDefaultConsumer().orElseGet(() -> {
 -            ConsumerConfig consumerConfig = new ConsumerConfig();
 -            consumerConfig.refresh();
 -            return consumerConfig;
 -        }));
 -    }
 -
 -    private void completeCompoundConfigs() {
 -        if (consumer != null) {
 -            if (application == null) {
 -                setApplication(consumer.getApplication());
 -            }
 -            if (module == null) {
 -                setModule(consumer.getModule());
 -            }
 -            if (registries == null) {
 -                setRegistries(consumer.getRegistries());
 -            }
 -            if (monitor == null) {
 -                setMonitor(consumer.getMonitor());
 -            }
 -        }
 -        if (module != null) {
 -            if (registries == null) {
 -                setRegistries(module.getRegistries());
 -            }
 -            if (monitor == null) {
 -                setMonitor(module.getMonitor());
 -            }
 -        }
 -        if (application != null) {
 -            if (registries == null) {
 -                setRegistries(application.getRegistries());
 -            }
 -            if (monitor == null) {
 -                setMonitor(application.getMonitor());
 -            }
 -        }
 -    }
 -
 -    public Class<?> getInterfaceClass() {
 -        if (interfaceClass != null) {
 -            return interfaceClass;
 -        }
 -        if (isGeneric()
 -                || (getConsumer() != null && getConsumer().isGeneric())) {
 -            return GenericService.class;
 -        }
 -        try {
 -            if (interfaceName != null && interfaceName.length() > 0) {
 -                this.interfaceClass = Class.forName(interfaceName, true, ClassUtils.getClassLoader());
 -            }
 -        } catch (ClassNotFoundException t) {
 -            throw new IllegalStateException(t.getMessage(), t);
 -        }
 -        return interfaceClass;
 -    }
 -
 -    /**
 -     * @param interfaceClass
 -     * @see #setInterface(Class)
 -     * @deprecated
 -     */
 -    @Deprecated
 -    public void setInterfaceClass(Class<?> interfaceClass) {
 -        setInterface(interfaceClass);
 -    }
 -
 -    public String getInterface() {
 -        return interfaceName;
 -    }
 -
 -    public void setInterface(String interfaceName) {
 -        this.interfaceName = interfaceName;
 -        if (StringUtils.isEmpty(id)) {
 -            id = interfaceName;
 -        }
 -    }
 -
 -    public void setInterface(Class<?> interfaceClass) {
 -        if (interfaceClass != null && !interfaceClass.isInterface()) {
 -            throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
 -        }
 -        this.interfaceClass = interfaceClass;
 -        setInterface(interfaceClass == null ? null : interfaceClass.getName());
 -    }
 -
 -    public String getClient() {
 -        return client;
 -    }
 -
 -    public void setClient(String client) {
 -        checkName(Constants.CLIENT_KEY, client);
 -        this.client = client;
 -    }
 -
 -    @Parameter(excluded = true)
 -    public String getUrl() {
 -        return url;
 -    }
 -
 -    public void setUrl(String url) {
 -        this.url = url;
 -    }
 -
 -    public List<MethodConfig> getMethods() {
 -        return methods;
 -    }
 -
 -    @SuppressWarnings("unchecked")
 -    public void setMethods(List<? extends MethodConfig> methods) {
 -        this.methods = (List<MethodConfig>) methods;
 -    }
 -
 -    public ConsumerConfig getConsumer() {
 -        return consumer;
 -    }
 -
 -    public void setConsumer(ConsumerConfig consumer) {
 -        ConfigManager.getInstance().addConsumer(consumer);
 -        this.consumer = consumer;
 -    }
 -
 -    public String getProtocol() {
 -        return protocol;
 -    }
 -
 -    public void setProtocol(String protocol) {
 -        this.protocol = protocol;
 -    }
 -
 -    // just for test
 -    Invoker<?> getInvoker() {
 -        return invoker;
 -    }
 -
 -    @Override
 -    @Parameter(excluded = true)
 -    public String getPrefix() {
 -        return DUBBO + ".reference." + interfaceName;
 -    }
 -
 -    private void resolveFile() {
 -        String resolve = System.getProperty(interfaceName);
 -        String resolveFile = null;
 -        if (StringUtils.isEmpty(resolve)) {
 -            resolveFile = System.getProperty("dubbo.resolve.file");
 -            if (StringUtils.isEmpty(resolveFile)) {
 -                File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties");
 -                if (userResolveFile.exists()) {
 -                    resolveFile = userResolveFile.getAbsolutePath();
 -                }
 -            }
 -            if (resolveFile != null && resolveFile.length() > 0) {
 -                Properties properties = new Properties();
 -                try (FileInputStream fis = new FileInputStream(new File(resolveFile))) {
 -                    properties.load(fis);
 -                } catch (IOException e) {
 -                    throw new IllegalStateException("Failed to load " + resolveFile + ", cause: " + e.getMessage(), e);
 -                }
 -
 -                resolve = properties.getProperty(interfaceName);
 -            }
 -        }
 -        if (resolve != null && resolve.length() > 0) {
 -            url = resolve;
 -            if (logger.isWarnEnabled()) {
 -                if (resolveFile != null) {
 -                    logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service.");
 -                } else {
 -                    logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service.");
 -                }
 -            }
 -        }
 -    }
 -}
 +/*
 + * 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.URL;
 +import org.apache.dubbo.common.Version;
 +import org.apache.dubbo.common.bytecode.Wrapper;
 +import org.apache.dubbo.common.extension.ExtensionLoader;
 +import org.apache.dubbo.common.utils.ClassUtils;
 +import org.apache.dubbo.common.utils.CollectionUtils;
 +import org.apache.dubbo.common.utils.ConfigUtils;
 +import org.apache.dubbo.common.utils.NetUtils;
 +import org.apache.dubbo.common.utils.StringUtils;
 +import org.apache.dubbo.config.annotation.Reference;
 +import org.apache.dubbo.config.context.ConfigManager;
 +import org.apache.dubbo.config.event.ReferenceConfigDestroyedEvent;
 +import org.apache.dubbo.config.event.ReferenceConfigInitializedEvent;
 +import org.apache.dubbo.config.support.Parameter;
 +import org.apache.dubbo.event.Event;
 +import org.apache.dubbo.event.EventDispatcher;
 +import org.apache.dubbo.metadata.WritableMetadataService;
 +import org.apache.dubbo.remoting.Constants;
 +import org.apache.dubbo.rpc.Invoker;
 +import org.apache.dubbo.rpc.Protocol;
 +import org.apache.dubbo.rpc.ProxyFactory;
 +import org.apache.dubbo.rpc.cluster.Cluster;
 +import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
 +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;
 +
 +import java.io.File;
 +import java.io.FileInputStream;
 +import java.io.IOException;
 +import java.lang.reflect.Method;
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Properties;
 +
 +import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
 +import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;
 +import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
 +import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
 +import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
 +import static org.apache.dubbo.common.constants.CommonConstants.METADATA_DEFAULT;
 +import static org.apache.dubbo.common.constants.CommonConstants.METADATA_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.SEMICOLON_SPLIT_PATTERN;
 +import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
 +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
 +import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost;
 +import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
 +import static org.apache.dubbo.registry.Constants.CONSUMER_PROTOCOL;
 +import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
 +import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
 +import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
 +
 +/**
 + * ReferenceConfig
 + *
 + * @export
 + */
 +public class ReferenceConfig<T> extends AbstractReferenceConfig {
 +
 +    private static final long serialVersionUID = -5864351140409987595L;
 +
 +    /**
 +     * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios.
 +     * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}.
 +     * For example:
 +     *
 +     * <li>when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample,
 +     * then the protocol is <b>RegistryProtocol</b></li>
 +     *
 +     * <li>when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then
 +     * the protocol is <b>DubboProtocol</b></li>
 +     * <p>
 +     * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two
 +     * layers, and eventually will get a <b>ProtocolFilterWrapper</b> or <b>ProtocolListenerWrapper</b>
 +     */
 +    private static final Protocol REF_PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
 +
 +    /**
 +     * The {@link Cluster}'s implementation with adaptive functionality, and actually it will get a {@link Cluster}'s
 +     * specific implementation who is wrapped with <b>MockClusterInvoker</b>
 +     */
 +    private static final Cluster CLUSTER = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension();
 +
 +    /**
 +     * A {@link ProxyFactory} implementation that will generate a reference service's proxy,the JavassistProxyFactory is
 +     * its default implementation
 +     */
 +    private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
 +
 +    /**
 +     * The url of the reference service
 +     */
 +    private final List<URL> urls = new ArrayList<URL>();
 +
 +    /**
 +     * The interface name of the reference service
 +     */
 +    private String interfaceName;
 +
 +    /**
 +     * The interface class of the reference service
 +     */
 +    private Class<?> interfaceClass;
 +
 +    /**
 +     * client type
 +     */
 +    private String client;
 +
 +    /**
 +     * The url for peer-to-peer invocation
 +     */
 +    private String url;
 +
 +    /**
 +     * The method configs
 +     */
 +    private List<MethodConfig> methods;
 +
 +    /**
 +     * The consumer config (default)
 +     */
 +    private ConsumerConfig consumer;
 +
 +    /**
 +     * Only the service provider of the specified protocol is invoked, and other protocols are ignored.
 +     */
 +    private String protocol;
 +
 +    /**
 +     * The interface proxy reference
 +     */
 +    private transient volatile T ref;
 +
 +    /**
 +     * The invoker of the reference service
 +     */
 +    private transient volatile Invoker<?> invoker;
 +
 +    /**
 +     * The flag whether the ReferenceConfig has been initialized
 +     */
 +    private transient volatile boolean initialized;
 +
 +    /**
 +     * whether this ReferenceConfig has been destroyed
 +     */
 +    private transient volatile boolean destroyed;
 +
 +    /**
 +     * The {@link EventDispatcher}
 +     *
 +     * @since 2.7.4
 +     */
 +    private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
 +
 +    @SuppressWarnings("unused")
 +    private final Object finalizerGuardian = new Object() {
 +        @Override
 +        protected void finalize() throws Throwable {
 +            super.finalize();
 +
 +            if (!ReferenceConfig.this.destroyed) {
 +                logger.warn("ReferenceConfig(" + url + ") is not DESTROYED when FINALIZE");
 +
 +        /* don't destroy for now
 +        try {
 +            ReferenceConfig.this.destroy();
 +        } catch (Throwable t) {
 +                logger.warn("Unexpected err when destroy invoker of ReferenceConfig(" + url + ") in finalize method!", t);
 +        }
 +        */
 +            }
 +        }
 +    };
 +
 +    public ReferenceConfig() {
 +    }
 +
 +    public ReferenceConfig(Reference reference) {
 +        appendAnnotation(Reference.class, reference);
 +        setMethods(MethodConfig.constructMethodConfig(reference.methods()));
 +    }
 +
 +    public URL toUrl() {
 +        return urls.isEmpty() ? null : urls.iterator().next();
 +    }
 +
 +    public List<URL> toUrls() {
 +        return urls;
 +    }
 +
 +    /**
 +     * This method should be called right after the creation of this class's instance, before any property in other config modules is used.
 +     * Check each config modules are created properly and override their properties if necessary.
 +     */
 +    public void checkAndUpdateSubConfigs() {
 +        if (StringUtils.isEmpty(interfaceName)) {
 +            throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
 +        }
 +        completeCompoundConfigs();
 +        // get consumer's global configuration
 +        checkDefault();
 +        this.refresh();
 +        if (getGeneric() == null && getConsumer() != null) {
 +            setGeneric(getConsumer().getGeneric());
 +        }
 +        if (ProtocolUtils.isGeneric(getGeneric())) {
 +            interfaceClass = GenericService.class;
 +        } else {
 +            try {
 +                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
 +                        .getContextClassLoader());
 +            } catch (ClassNotFoundException e) {
 +                throw new IllegalStateException(e.getMessage(), e);
 +            }
 +            checkInterfaceAndMethods(interfaceClass, methods);
 +        }
 +        resolveFile();
 +        checkApplication();
 +        checkMetadataReport();
 +    }
 +
 +    public synchronized T get() {
 +        checkAndUpdateSubConfigs();
 +
 +        if (destroyed) {
 +            throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
 +        }
 +        if (ref == null) {
 +            init();
 +        }
 +        return ref;
 +    }
 +
 +    public synchronized void destroy() {
 +        if (ref == null) {
 +            return;
 +        }
 +        if (destroyed) {
 +            return;
 +        }
 +        destroyed = true;
 +        try {
 +            invoker.destroy();
 +        } catch (Throwable t) {
 +            logger.warn("Unexpected error occured when destroy invoker of ReferenceConfig(" + url + ").", t);
 +        }
 +        invoker = null;
 +        ref = null;
 +
 +        // dispatch a ReferenceConfigDestroyedEvent since 2.7.4
 +        dispatch(new ReferenceConfigDestroyedEvent(this));
 +    }
 +
 +    private void init() {
 +        if (initialized) {
 +            return;
 +        }
 +        checkStubAndLocal(interfaceClass);
 +        checkMock(interfaceClass);
 +        Map<String, String> map = new HashMap<String, String>();
 +
 +        map.put(SIDE_KEY, CONSUMER_SIDE);
 +
 +        appendRuntimeParameters(map);
 +        if (!isGeneric()) {
 +            String revision = Version.getVersion(interfaceClass, version);
 +            if (revision != null && revision.length() > 0) {
 +                map.put(REVISION_KEY, revision);
 +            }
 +
 +            String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
 +            if (methods.length == 0) {
 +                logger.warn("No method found in service interface " + interfaceClass.getName());
 +                map.put(METHODS_KEY, ANY_VALUE);
 +            } else {
 +                map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), COMMA_SEPARATOR));
 +            }
 +        }
 +        map.put(INTERFACE_KEY, interfaceName);
 +        appendParameters(map, metrics);
 +        appendParameters(map, application);
 +        appendParameters(map, module);
 +        // remove 'default.' prefix for configs from ConsumerConfig
 +        // appendParameters(map, consumer, Constants.DEFAULT_KEY);
 +        appendParameters(map, consumer);
 +        appendParameters(map, this);
 +        Map<String, Object> attributes = null;
 +        if (CollectionUtils.isNotEmpty(methods)) {
 +            attributes = new HashMap<String, Object>();
 +            for (MethodConfig methodConfig : methods) {
 +                appendParameters(map, methodConfig, methodConfig.getName());
 +                String retryKey = methodConfig.getName() + ".retry";
 +                if (map.containsKey(retryKey)) {
 +                    String retryValue = map.remove(retryKey);
 +                    if ("false".equals(retryValue)) {
 +                        map.put(methodConfig.getName() + ".retries", "0");
 +                    }
 +                }
-                 attributes.put(methodConfig.getName(), convertMethodConfig2AyncInfo(methodConfig));
++                attributes.put(methodConfig.getName(), convertMethodConfig2AsyncInfo(methodConfig));
 +            }
 +        }
 +
 +        String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);
 +        if (StringUtils.isEmpty(hostToRegistry)) {
 +            hostToRegistry = NetUtils.getLocalHost();
 +        } else if (isInvalidLocalHost(hostToRegistry)) {
 +            throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
 +        }
 +        map.put(REGISTER_IP_KEY, hostToRegistry);
 +
 +        String serviceKey = URL.buildKey(interfaceName, group, version);
 +        ApplicationModel.initConsumerModel(serviceKey, buildConsumerModel(serviceKey, attributes));
 +        ref = createProxy(map);
 +        ApplicationModel.getConsumerModel(serviceKey).setProxyObject(ref);
 +
 +        initialized = true;
 +
 +        // dispatch a ReferenceConfigInitializedEvent since 2.7.4
 +        dispatch(new ReferenceConfigInitializedEvent(this, invoker));
 +    }
 +
 +    private ConsumerModel buildConsumerModel(String serviceKey, Map<String, Object> attributes) {
 +        Method[] methods = interfaceClass.getMethods();
 +        Class serviceInterface = interfaceClass;
 +        if (interfaceClass == GenericService.class) {
 +            try {
 +                serviceInterface = Class.forName(interfaceName);
 +                methods = serviceInterface.getMethods();
 +            } catch (ClassNotFoundException e) {
 +                methods = interfaceClass.getMethods();
 +            }
 +        }
 +        return new ConsumerModel(serviceKey, serviceInterface, ref, methods, attributes);
 +    }
 +
 +    @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
 +    private T createProxy(Map<String, String> map) {
 +        if (shouldJvmRefer(map)) {
 +            URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
 +            invoker = REF_PROTOCOL.refer(interfaceClass, url);
 +            if (logger.isInfoEnabled()) {
 +                logger.info("Using injvm service " + interfaceClass.getName());
 +            }
 +        } else {
 +            urls.clear(); // reference retry init will add url to urls, lead to OOM
 +            if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address.
 +                String[] us = SEMICOLON_SPLIT_PATTERN.split(url);
 +                if (us != null && us.length > 0) {
 +                    for (String u : us) {
 +                        URL url = URL.valueOf(u);
 +                        if (StringUtils.isEmpty(url.getPath())) {
 +                            url = url.setPath(interfaceName);
 +                        }
 +                        if (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
 +                            urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
 +                        } else {
 +                            urls.add(ClusterUtils.mergeUrl(url, map));
 +                        }
 +                    }
 +                }
 +            } else { // assemble URL from register center's configuration
 +                // if protocols not injvm checkRegistry
 +                if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())) {
 +                    checkRegistry();
 +                    List<URL> us = loadRegistries(false);
 +                    if (CollectionUtils.isNotEmpty(us)) {
 +                        for (URL u : us) {
 +                            URL monitorUrl = loadMonitor(u);
 +                            if (monitorUrl != null) {
 +                                map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
 +                            }
 +                            urls.add(u.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
 +                        }
 +                    }
 +                    if (urls.isEmpty()) {
 +                        throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config.");
 +                    }
 +                }
 +            }
 +
 +            if (urls.size() == 1) {
 +                invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));
 +            } else {
 +                List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
 +                URL registryURL = null;
 +                for (URL url : urls) {
 +                    invokers.add(REF_PROTOCOL.refer(interfaceClass, url));
 +                    if (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
 +                        registryURL = url; // use last registry url
 +                    }
 +                }
 +                if (registryURL != null) { // registry url is available
 +                    // use RegistryAwareCluster only when register's CLUSTER is available
 +                    URL u = registryURL.addParameter(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, must be direct invoke.
 +                    invoker = CLUSTER.join(new StaticDirectory(invokers));
 +                }
 +            }
 +        }
 +
 +        if (shouldCheck() && !invoker.isAvailable()) {
 +            throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());
 +        }
 +        if (logger.isInfoEnabled()) {
 +            logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
 +        }
 +        /**
 +         * @since 2.7.0
 +         * ServiceData Store
 +         */
 +        String metadata = map.get(METADATA_KEY);
 +        WritableMetadataService metadataService = WritableMetadataService.getExtension(metadata == null ? METADATA_DEFAULT : metadata);
 +        if (metadataService != null) {
 +            URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map);
 +            metadataService.publishServiceDefinition(consumerURL);
 +        }
 +        // create service proxy
 +        return (T) PROXY_FACTORY.getProxy(invoker);
 +    }
 +
 +    /**
 +     * Figure out should refer the service in the same JVM from configurations. The default behavior is true
 +     * 1. if injvm is specified, then use it
 +     * 2. then if a url is specified, then assume it's a remote call
 +     * 3. otherwise, check scope parameter
 +     * 4. if scope is not specified but the target service is provided in the same JVM, then prefer to make the local
 +     * call, which is the default behavior
 +     */
 +    protected boolean shouldJvmRefer(Map<String, String> map) {
 +        URL tmpUrl = new URL("temp", "localhost", 0, map);
 +        boolean isJvmRefer;
 +        if (isInjvm() == null) {
 +            // if a url is specified, don't do local reference
 +            if (url != null && url.length() > 0) {
 +                isJvmRefer = false;
 +            } else {
 +                // by default, reference local service if there is
 +                isJvmRefer = InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl);
 +            }
 +        } else {
 +            isJvmRefer = isInjvm();
 +        }
 +        return isJvmRefer;
 +    }
 +
 +    protected boolean shouldCheck() {
 +        Boolean shouldCheck = isCheck();
 +        if (shouldCheck == null && getConsumer() != null) {
 +            shouldCheck = getConsumer().isCheck();
 +        }
 +        if (shouldCheck == null) {
 +            // default true
 +            shouldCheck = true;
 +        }
 +        return shouldCheck;
 +    }
 +
 +    protected boolean shouldInit() {
 +        Boolean shouldInit = isInit();
 +        if (shouldInit == null && getConsumer() != null) {
 +            shouldInit = getConsumer().isInit();
 +        }
 +        if (shouldInit == null) {
 +            // default is false
 +            return false;
 +        }
 +        return shouldInit;
 +    }
 +
 +    private void checkDefault() {
 +        if (consumer != null) {
 +            return;
 +        }
 +        setConsumer(ConfigManager.getInstance().getDefaultConsumer().orElseGet(() -> {
 +            ConsumerConfig consumerConfig = new ConsumerConfig();
 +            consumerConfig.refresh();
 +            return consumerConfig;
 +        }));
 +    }
 +
 +    private void completeCompoundConfigs() {
 +        if (consumer != null) {
 +            if (application == null) {
 +                setApplication(consumer.getApplication());
 +            }
 +            if (module == null) {
 +                setModule(consumer.getModule());
 +            }
 +            if (registries == null) {
 +                setRegistries(consumer.getRegistries());
 +            }
 +            if (monitor == null) {
 +                setMonitor(consumer.getMonitor());
 +            }
 +        }
 +        if (module != null) {
 +            if (registries == null) {
 +                setRegistries(module.getRegistries());
 +            }
 +            if (monitor == null) {
 +                setMonitor(module.getMonitor());
 +            }
 +        }
 +        if (application != null) {
 +            if (registries == null) {
 +                setRegistries(application.getRegistries());
 +            }
 +            if (monitor == null) {
 +                setMonitor(application.getMonitor());
 +            }
 +        }
 +    }
 +
 +    public Class<?> getInterfaceClass() {
 +        if (interfaceClass != null) {
 +            return interfaceClass;
 +        }
 +        if (isGeneric()
 +                || (getConsumer() != null && getConsumer().isGeneric())) {
 +            return GenericService.class;
 +        }
 +        try {
 +            if (interfaceName != null && interfaceName.length() > 0) {
 +                this.interfaceClass = Class.forName(interfaceName, true, ClassUtils.getClassLoader());
 +            }
 +        } catch (ClassNotFoundException t) {
 +            throw new IllegalStateException(t.getMessage(), t);
 +        }
 +        return interfaceClass;
 +    }
 +
 +    /**
 +     * @param interfaceClass
 +     * @see #setInterface(Class)
 +     * @deprecated
 +     */
 +    @Deprecated
 +    public void setInterfaceClass(Class<?> interfaceClass) {
 +        setInterface(interfaceClass);
 +    }
 +
 +    public String getInterface() {
 +        return interfaceName;
 +    }
 +
 +    public void setInterface(String interfaceName) {
 +        this.interfaceName = interfaceName;
 +        if (StringUtils.isEmpty(id)) {
 +            id = interfaceName;
 +        }
 +    }
 +
 +    public void setInterface(Class<?> interfaceClass) {
 +        if (interfaceClass != null && !interfaceClass.isInterface()) {
 +            throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
 +        }
 +        this.interfaceClass = interfaceClass;
 +        setInterface(interfaceClass == null ? null : interfaceClass.getName());
 +    }
 +
 +    public String getClient() {
 +        return client;
 +    }
 +
 +    public void setClient(String client) {
 +        checkName(Constants.CLIENT_KEY, client);
 +        this.client = client;
 +    }
 +
 +    @Parameter(excluded = true)
 +    public String getUrl() {
 +        return url;
 +    }
 +
 +    public void setUrl(String url) {
 +        this.url = url;
 +    }
 +
 +    public List<MethodConfig> getMethods() {
 +        return methods;
 +    }
 +
 +    @SuppressWarnings("unchecked")
 +    public void setMethods(List<? extends MethodConfig> methods) {
 +        this.methods = (List<MethodConfig>) methods;
 +    }
 +
 +    public ConsumerConfig getConsumer() {
 +        return consumer;
 +    }
 +
 +    public void setConsumer(ConsumerConfig consumer) {
 +        ConfigManager.getInstance().addConsumer(consumer);
 +        this.consumer = consumer;
 +    }
 +
 +    public String getProtocol() {
 +        return protocol;
 +    }
 +
 +    public void setProtocol(String protocol) {
 +        this.protocol = protocol;
 +    }
 +
 +    // just for test
 +    Invoker<?> getInvoker() {
 +        return invoker;
 +    }
 +
 +    @Override
 +    @Parameter(excluded = true)
 +    public String getPrefix() {
 +        return DUBBO + ".reference." + interfaceName;
 +    }
 +
 +    private void resolveFile() {
 +        String resolve = System.getProperty(interfaceName);
 +        String resolveFile = null;
 +        if (StringUtils.isEmpty(resolve)) {
 +            resolveFile = System.getProperty("dubbo.resolve.file");
 +            if (StringUtils.isEmpty(resolveFile)) {
 +                File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties");
 +                if (userResolveFile.exists()) {
 +                    resolveFile = userResolveFile.getAbsolutePath();
 +                }
 +            }
 +            if (resolveFile != null && resolveFile.length() > 0) {
 +                Properties properties = new Properties();
 +                try (FileInputStream fis = new FileInputStream(new File(resolveFile))) {
 +                    properties.load(fis);
 +                } catch (IOException e) {
 +                    throw new IllegalStateException("Failed to load " + resolveFile + ", cause: " + e.getMessage(), e);
 +                }
 +
 +                resolve = properties.getProperty(interfaceName);
 +            }
 +        }
 +        if (resolve != null && resolve.length() > 0) {
 +            url = resolve;
 +            if (logger.isWarnEnabled()) {
 +                if (resolveFile != null) {
 +                    logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service.");
 +                } else {
 +                    logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service.");
 +                }
 +            }
 +        }
 +    }
 +
 +    /**
 +     * Dispatch an {@link Event event}
 +     *
 +     * @param event an {@link Event event}
 +     * @since 2.7.4
 +     */
 +    protected void dispatch(Event event) {
 +        eventDispatcher.dispatch(event);
 +    }
 +}
diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
index fb9d247,c0bd1e8..dd161ff
--- 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
@@@ -1,1064 -1,1054 +1,1064 @@@
 -/*
 - * 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.URL;
 -import org.apache.dubbo.common.URLBuilder;
 -import org.apache.dubbo.common.Version;
 -import org.apache.dubbo.common.bytecode.Wrapper;
 -import org.apache.dubbo.common.config.Environment;
 -import org.apache.dubbo.common.extension.ExtensionLoader;
 -import org.apache.dubbo.common.utils.ClassUtils;
 -import org.apache.dubbo.common.utils.CollectionUtils;
 -import org.apache.dubbo.common.utils.ConfigUtils;
 -import org.apache.dubbo.common.utils.NamedThreadFactory;
 -import org.apache.dubbo.common.utils.StringUtils;
 -import org.apache.dubbo.config.annotation.Service;
 -import org.apache.dubbo.config.context.ConfigManager;
 -import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker;
 -import org.apache.dubbo.config.support.Parameter;
 -import org.apache.dubbo.metadata.integration.MetadataReportService;
 -import org.apache.dubbo.remoting.Constants;
 -import org.apache.dubbo.rpc.Exporter;
 -import org.apache.dubbo.rpc.Invoker;
 -import org.apache.dubbo.rpc.Protocol;
 -import org.apache.dubbo.rpc.ProxyFactory;
 -import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
 -import org.apache.dubbo.rpc.model.ApplicationModel;
 -import org.apache.dubbo.rpc.model.ProviderModel;
 -import org.apache.dubbo.rpc.service.GenericService;
 -import org.apache.dubbo.rpc.support.ProtocolUtils;
 -
 -import java.lang.reflect.Method;
 -import java.net.InetAddress;
 -import java.net.InetSocketAddress;
 -import java.net.Socket;
 -import java.net.SocketAddress;
 -import java.net.UnknownHostException;
 -import java.util.ArrayList;
 -import java.util.Arrays;
 -import java.util.HashMap;
 -import java.util.HashSet;
 -import java.util.List;
 -import java.util.Map;
 -import java.util.Optional;
 -import java.util.UUID;
 -import java.util.concurrent.Executors;
 -import java.util.concurrent.ScheduledExecutorService;
 -import java.util.concurrent.TimeUnit;
 -
 -import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
 -import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
 -import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
 -import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
 -import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
 -import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
 -import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
 -import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
 -import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;
 -import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
 -import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
 -import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
 -import static org.apache.dubbo.config.Constants.DUBBO_PORT_TO_BIND;
 -import static org.apache.dubbo.config.Constants.DUBBO_PORT_TO_REGISTRY;
 -import static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;
 -import static org.apache.dubbo.config.Constants.MULTICAST;
 -import static org.apache.dubbo.config.Constants.PROTOCOLS_SUFFIX;
 -import static org.apache.dubbo.rpc.Constants.SCOPE_KEY;
 -import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
 -import static org.apache.dubbo.config.Constants.SCOPE_NONE;
 -import static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;
 -import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
 -import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;
 -import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
 -import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
 -import static org.apache.dubbo.rpc.Constants.PROXY_KEY;
 -import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
 -import static org.apache.dubbo.common.utils.NetUtils.getAvailablePort;
 -import static org.apache.dubbo.common.utils.NetUtils.getLocalHost;
 -import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost;
 -import static org.apache.dubbo.common.utils.NetUtils.isInvalidPort;
 -
 -/**
 - * ServiceConfig
 - *
 - * @export
 - */
 -public class ServiceConfig<T> extends AbstractServiceConfig {
 -
 -    private static final long serialVersionUID = 3033787999037024738L;
 -
 -    /**
 -     * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios.
 -     * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}.
 -     * For example:
 -     *
 -     * <li>when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample,
 -     * then the protocol is <b>RegistryProtocol</b></li>
 -     *
 -     * <li>when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then
 -     * the protocol is <b>DubboProtocol</b></li>
 -     * <p>
 -     * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two
 -     * layers, and eventually will get a <b>ProtocolFilterWrapper</b> or <b>ProtocolListenerWrapper</b>
 -     */
 -    private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
 -
 -    /**
 -     * A {@link ProxyFactory} implementation that will generate a exported service proxy,the JavassistProxyFactory is its
 -     * default implementation
 -     */
 -    private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
 -
 -    /**
 -     * A random port cache, the different protocols who has no port specified have different random port
 -     */
 -    private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap<String, Integer>();
 -
 -    /**
 -     * A delayed exposure service timer
 -     */
 -    private static final ScheduledExecutorService DELAY_EXPORT_EXECUTOR = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));
 -
 -    /**
 -     * The urls of the services exported
 -     */
 -    private final List<URL> urls = new ArrayList<URL>();
 -
 -    /**
 -     * The exported services
 -     */
 -    private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>();
 -
 -    /**
 -     * The interface name of the exported service
 -     */
 -    private String interfaceName;
 -
 -    /**
 -     * The interface class of the exported service
 -     */
 -    private Class<?> interfaceClass;
 -
 -    /**
 -     * The reference of the interface implementation
 -     */
 -    private T ref;
 -
 -    /**
 -     * The service name
 -     */
 -    private String path;
 -
 -    /**
 -     * The method configuration
 -     */
 -    private List<MethodConfig> methods;
 -
 -    /**
 -     * The provider configuration
 -     */
 -    private ProviderConfig provider;
 -
 -    /**
 -     * The providerIds
 -     */
 -    private String providerIds;
 -
 -    /**
 -     * Whether the provider has been exported
 -     */
 -    private transient volatile boolean exported;
 -
 -    /**
 -     * The flag whether a service has unexported ,if the method unexported is invoked, the value is true
 -     */
 -    private transient volatile boolean unexported;
 -
 -    /**
 -     * whether it is a GenericService
 -     */
 -    private volatile String generic;
 -
 -    public ServiceConfig() {
 -    }
 -
 -    public ServiceConfig(Service service) {
 -        appendAnnotation(Service.class, service);
 -        setMethods(MethodConfig.constructMethodConfig(service.methods()));
 -    }
 -
 -    @Deprecated
 -    private static List<ProtocolConfig> convertProviderToProtocol(List<ProviderConfig> providers) {
 -        if (CollectionUtils.isEmpty(providers)) {
 -            return null;
 -        }
 -        List<ProtocolConfig> protocols = new ArrayList<ProtocolConfig>(providers.size());
 -        for (ProviderConfig provider : providers) {
 -            protocols.add(convertProviderToProtocol(provider));
 -        }
 -        return protocols;
 -    }
 -
 -    @Deprecated
 -    private static List<ProviderConfig> convertProtocolToProvider(List<ProtocolConfig> protocols) {
 -        if (CollectionUtils.isEmpty(protocols)) {
 -            return null;
 -        }
 -        List<ProviderConfig> providers = new ArrayList<ProviderConfig>(protocols.size());
 -        for (ProtocolConfig provider : protocols) {
 -            providers.add(convertProtocolToProvider(provider));
 -        }
 -        return providers;
 -    }
 -
 -    @Deprecated
 -    private static ProtocolConfig convertProviderToProtocol(ProviderConfig provider) {
 -        ProtocolConfig protocol = new ProtocolConfig();
 -        protocol.setName(provider.getProtocol().getName());
 -        protocol.setServer(provider.getServer());
 -        protocol.setClient(provider.getClient());
 -        protocol.setCodec(provider.getCodec());
 -        protocol.setHost(provider.getHost());
 -        protocol.setPort(provider.getPort());
 -        protocol.setPath(provider.getPath());
 -        protocol.setPayload(provider.getPayload());
 -        protocol.setThreads(provider.getThreads());
 -        protocol.setParameters(provider.getParameters());
 -        return protocol;
 -    }
 -
 -    @Deprecated
 -    private static ProviderConfig convertProtocolToProvider(ProtocolConfig protocol) {
 -        ProviderConfig provider = new ProviderConfig();
 -        provider.setProtocol(protocol);
 -        provider.setServer(protocol.getServer());
 -        provider.setClient(protocol.getClient());
 -        provider.setCodec(protocol.getCodec());
 -        provider.setHost(protocol.getHost());
 -        provider.setPort(protocol.getPort());
 -        provider.setPath(protocol.getPath());
 -        provider.setPayload(protocol.getPayload());
 -        provider.setThreads(protocol.getThreads());
 -        provider.setParameters(protocol.getParameters());
 -        return provider;
 -    }
 -
 -    private static Integer getRandomPort(String protocol) {
 -        protocol = protocol.toLowerCase();
 -        return RANDOM_PORT_MAP.getOrDefault(protocol, Integer.MIN_VALUE);
 -    }
 -
 -    private static void putRandomPort(String protocol, Integer port) {
 -        protocol = protocol.toLowerCase();
 -        if (!RANDOM_PORT_MAP.containsKey(protocol)) {
 -            RANDOM_PORT_MAP.put(protocol, port);
 -            logger.warn("Use random available port(" + port + ") for protocol " + protocol);
 -        }
 -    }
 -
 -    public URL toUrl() {
 -        return urls.isEmpty() ? null : urls.iterator().next();
 -    }
 -
 -    public List<URL> toUrls() {
 -        return urls;
 -    }
 -
 -    @Parameter(excluded = true)
 -    public boolean isExported() {
 -        return exported;
 -    }
 -
 -    @Parameter(excluded = true)
 -    public boolean isUnexported() {
 -        return unexported;
 -    }
 -
 -    public void checkAndUpdateSubConfigs() {
 -        // Use default configs defined explicitly on global configs
 -        completeCompoundConfigs();
 -        // Config Center should always being started first.
 -        startConfigCenter();
 -        checkDefault();
 -        checkProtocol();
 -        checkApplication();
 -        // if protocol is not injvm checkRegistry
 -        if (!isOnlyInJvm()) {
 -            checkRegistry();
 -        }
 -        this.refresh();
 -        checkMetadataReport();
 -
 -        if (StringUtils.isEmpty(interfaceName)) {
 -            throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
 -        }
 -
 -        if (ref instanceof GenericService) {
 -            interfaceClass = GenericService.class;
 -            if (StringUtils.isEmpty(generic)) {
 -                generic = Boolean.TRUE.toString();
 -            }
 -        } else {
 -            try {
 -                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
 -                        .getContextClassLoader());
 -            } catch (ClassNotFoundException e) {
 -                throw new IllegalStateException(e.getMessage(), e);
 -            }
 -            checkInterfaceAndMethods(interfaceClass, methods);
 -            checkRef();
 -            generic = Boolean.FALSE.toString();
 -        }
 -        if (local != null) {
 -            if ("true".equals(local)) {
 -                local = interfaceName + "Local";
 -            }
 -            Class<?> localClass;
 -            try {
 -                localClass = ClassUtils.forNameWithThreadContextClassLoader(local);
 -            } catch (ClassNotFoundException e) {
 -                throw new IllegalStateException(e.getMessage(), e);
 -            }
 -            if (!interfaceClass.isAssignableFrom(localClass)) {
 -                throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
 -            }
 -        }
 -        if (stub != null) {
 -            if ("true".equals(stub)) {
 -                stub = interfaceName + "Stub";
 -            }
 -            Class<?> stubClass;
 -            try {
 -                stubClass = ClassUtils.forNameWithThreadContextClassLoader(stub);
 -            } catch (ClassNotFoundException e) {
 -                throw new IllegalStateException(e.getMessage(), e);
 -            }
 -            if (!interfaceClass.isAssignableFrom(stubClass)) {
 -                throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
 -            }
 -        }
 -        checkStubAndLocal(interfaceClass);
 -        checkMock(interfaceClass);
 -    }
 -
 -    /**
 -     * Determine if it is injvm
 -     *
 -     * @return
 -     */
 -    private boolean isOnlyInJvm() {
 -        return getProtocols().size() == 1 && LOCAL_PROTOCOL.equalsIgnoreCase(getProtocols().get(0).getName());
 -    }
 -
 -    public synchronized void export() {
 -        checkAndUpdateSubConfigs();
 -
 -        if (!shouldExport()) {
 -            return;
 -        }
 -
 -        if (shouldDelay()) {
 -            DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
 -        } else {
 -            doExport();
 -        }
 -    }
 -
 -    private boolean shouldExport() {
 -        Boolean export = getExport();
 -        // default value is true
 -        return export == null ? true : export;
 -    }
 -
 -    @Override
 -    public Boolean getExport() {
 -        return (export == null && provider != null) ? provider.getExport() : export;
 -    }
 -
 -    private boolean shouldDelay() {
 -        Integer delay = getDelay();
 -        return delay != null && delay > 0;
 -    }
 -
 -    @Override
 -    public Integer getDelay() {
 -        return (delay == null && provider != null) ? provider.getDelay() : delay;
 -    }
 -
 -    protected synchronized void doExport() {
 -        if (unexported) {
 -            throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!");
 -        }
 -        if (exported) {
 -            return;
 -        }
 -        exported = true;
 -
 -        if (StringUtils.isEmpty(path)) {
 -            path = interfaceName;
 -        }
 -        doExportUrls();
 -    }
 -
 -    private void checkRef() {
 -        // reference should not be null, and is the implementation of the given interface
 -        if (ref == null) {
 -            throw new IllegalStateException("ref not allow null!");
 -        }
 -        if (!interfaceClass.isInstance(ref)) {
 -            throw new IllegalStateException("The class "
 -                    + ref.getClass().getName() + " unimplemented interface "
 -                    + interfaceClass + "!");
 -        }
 -    }
 -
 -    public synchronized void unexport() {
 -        if (!exported) {
 -            return;
 -        }
 -        if (unexported) {
 -            return;
 -        }
 -        if (!exporters.isEmpty()) {
 -            for (Exporter<?> exporter : exporters) {
 -                try {
 -                    exporter.unexport();
 -                } catch (Throwable t) {
 -                    logger.warn("Unexpected error occured when unexport " + exporter, t);
 -                }
 -            }
 -            exporters.clear();
 -        }
 -        unexported = true;
 -    }
 -
 -    @SuppressWarnings({"unchecked", "rawtypes"})
 -    private void doExportUrls() {
 -        List<URL> registryURLs = loadRegistries(true);
 -        for (ProtocolConfig protocolConfig : protocols) {
 -            String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);
 -            ProviderModel providerModel = new ProviderModel(pathKey, ref, interfaceClass);
 -            ApplicationModel.initProviderModel(pathKey, providerModel);
 -            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
 -        }
 -    }
 -
 -    private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
 -        String name = protocolConfig.getName();
 -        if (StringUtils.isEmpty(name)) {
 -            name = DUBBO;
 -        }
 -
 -        Map<String, String> map = new HashMap<String, String>();
 -        map.put(SIDE_KEY, PROVIDER_SIDE);
 -
 -        appendRuntimeParameters(map);
 -        appendParameters(map, metrics);
 -        appendParameters(map, application);
 -        appendParameters(map, module);
 -        // remove 'default.' prefix for configs from ProviderConfig
 -        // appendParameters(map, provider, Constants.DEFAULT_KEY);
 -        appendParameters(map, provider);
 -        appendParameters(map, protocolConfig);
 -        appendParameters(map, this);
 -        if (CollectionUtils.isNotEmpty(methods)) {
 -            for (MethodConfig method : methods) {
 -                appendParameters(map, method, method.getName());
 -                String retryKey = method.getName() + ".retry";
 -                if (map.containsKey(retryKey)) {
 -                    String retryValue = map.remove(retryKey);
 -                    if ("false".equals(retryValue)) {
 -                        map.put(method.getName() + ".retries", "0");
 -                    }
 -                }
 -                List<ArgumentConfig> arguments = method.getArguments();
 -                if (CollectionUtils.isNotEmpty(arguments)) {
 -                    for (ArgumentConfig argument : arguments) {
 -                        // convert argument type
 -                        if (argument.getType() != null && argument.getType().length() > 0) {
 -                            Method[] methods = interfaceClass.getMethods();
 -                            // visit all methods
 -                            if (methods != null && methods.length > 0) {
 -                                for (int i = 0; i < methods.length; i++) {
 -                                    String methodName = methods[i].getName();
 -                                    // target the method, and get its signature
 -                                    if (methodName.equals(method.getName())) {
 -                                        Class<?>[] argtypes = methods[i].getParameterTypes();
 -                                        // one callback in the method
 -                                        if (argument.getIndex() != -1) {
 -                                            if (argtypes[argument.getIndex()].getName().equals(argument.getType())) {
 -                                                appendParameters(map, argument, method.getName() + "." + argument.getIndex());
 -                                            } else {
 -                                                throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
 -                                            }
 -                                        } else {
 -                                            // multiple callbacks in the method
 -                                            for (int j = 0; j < argtypes.length; j++) {
 -                                                Class<?> argclazz = argtypes[j];
 -                                                if (argclazz.getName().equals(argument.getType())) {
 -                                                    appendParameters(map, argument, method.getName() + "." + j);
 -                                                    if (argument.getIndex() != -1 && argument.getIndex() != j) {
 -                                                        throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
 -                                                    }
 -                                                }
 -                                            }
 -                                        }
 -                                    }
 -                                }
 -                            }
 -                        } else if (argument.getIndex() != -1) {
 -                            appendParameters(map, argument, method.getName() + "." + argument.getIndex());
 -                        } else {
 -                            throw new IllegalArgumentException("Argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
 -                        }
 -
 -                    }
 -                }
 -            } // end of methods for
 -        }
 -
 -        if (ProtocolUtils.isGeneric(generic)) {
 -            map.put(GENERIC_KEY, generic);
 -            map.put(METHODS_KEY, ANY_VALUE);
 -        } else {
 -            String revision = Version.getVersion(interfaceClass, version);
 -            if (revision != null && revision.length() > 0) {
 -                map.put(REVISION_KEY, revision);
 -            }
 -
 -            String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
 -            if (methods.length == 0) {
 -                logger.warn("No method found in service interface " + interfaceClass.getName());
 -                map.put(METHODS_KEY, ANY_VALUE);
 -            } else {
 -                map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
 -            }
 -        }
 -        if (!ConfigUtils.isEmpty(token)) {
 -            if (ConfigUtils.isDefault(token)) {
 -                map.put(TOKEN_KEY, UUID.randomUUID().toString());
 -            } else {
 -                map.put(TOKEN_KEY, token);
 -            }
 -        }
 -        // export service
 -        String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
 -        Integer port = this.findConfigedPorts(protocolConfig, name, map);
 -        URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
 -
 -        if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
 -                .hasExtension(url.getProtocol())) {
 -            url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
 -                    .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
 -        }
 -
 -        String scope = url.getParameter(SCOPE_KEY);
 -        // don't export when none is configured
 -        if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
 -
 -            // export to local if the config is not remote (export to remote only when config is remote)
 -            if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
 -                exportLocal(url);
 -            }
 -            // export to remote if the config is not local (export to local only when config is local)
 -            if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
 -                if (!isOnlyInJvm() && logger.isInfoEnabled()) {
 -                    logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
 -                }
 -                if (CollectionUtils.isNotEmpty(registryURLs)) {
 -                    for (URL registryURL : registryURLs) {
 -                        //if protocol is only injvm ,not register
 -                        if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
 -                            continue;
 -                        }
 -                        url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
 -                        URL monitorUrl = loadMonitor(registryURL);
 -                        if (monitorUrl != null) {
 -                            url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());
 -                        }
 -                        if (logger.isInfoEnabled()) {
 -                            logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
 -                        }
 -
 -                        // For providers, this is used to enable custom proxy to generate invoker
 -                        String proxy = url.getParameter(PROXY_KEY);
 -                        if (StringUtils.isNotEmpty(proxy)) {
 -                            registryURL = registryURL.addParameter(PROXY_KEY, proxy);
 -                        }
 -
 -                        Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
 -                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
 -
 -                        Exporter<?> exporter = protocol.export(wrapperInvoker);
 -                        exporters.add(exporter);
 -                    }
 -                } else {
 -                    Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);
 -                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
 -
 -                    Exporter<?> exporter = protocol.export(wrapperInvoker);
 -                    exporters.add(exporter);
 -                }
 -                /**
 -                 * @since 2.7.0
 -                 * ServiceData Store
 -                 */
 -                MetadataReportService metadataReportService = null;
 -                if ((metadataReportService = getMetadataReportService()) != null) {
 -                    metadataReportService.publishProvider(url);
 -                }
 -            }
 -        }
 -        this.urls.add(url);
 -    }
 -
 -    @SuppressWarnings({"unchecked", "rawtypes"})
 -    /**
 -     * always export injvm
 -     */
 -    private void exportLocal(URL url) {
 -        URL local = URLBuilder.from(url)
 -                .setProtocol(LOCAL_PROTOCOL)
 -                .setHost(LOCALHOST_VALUE)
 -                .setPort(0)
 -                .build();
 -        Exporter<?> exporter = protocol.export(
 -                PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));
 -        exporters.add(exporter);
 -        logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local);
 -    }
 -
 -    private Optional<String> getContextPath(ProtocolConfig protocolConfig) {
 -        String contextPath = protocolConfig.getContextpath();
 -        if (StringUtils.isEmpty(contextPath) && provider != null) {
 -            contextPath = provider.getContextpath();
 -        }
 -        return Optional.ofNullable(contextPath);
 -    }
 -
 -    protected Class getServiceClass(T ref) {
 -        return ref.getClass();
 -    }
 -
 -    /**
 -     * Register & bind IP address for service provider, can be configured separately.
 -     * Configuration priority: environment variables -> java system properties -> host property in config file ->
 -     * /etc/hosts -> default network address -> first available network address
 -     *
 -     * @param protocolConfig
 -     * @param registryURLs
 -     * @param map
 -     * @return
 -     */
 -    private String findConfigedHosts(ProtocolConfig protocolConfig, List<URL> registryURLs, Map<String, String> map) {
 -        boolean anyhost = false;
 -
 -        String hostToBind = getValueFromConfig(protocolConfig, DUBBO_IP_TO_BIND);
 -        if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) {
 -            throw new IllegalArgumentException("Specified invalid bind ip from property:" + DUBBO_IP_TO_BIND + ", value:" + hostToBind);
 -        }
 -
 -        // if bind ip is not found in environment, keep looking up
 -        if (StringUtils.isEmpty(hostToBind)) {
 -            hostToBind = protocolConfig.getHost();
 -            if (provider != null && StringUtils.isEmpty(hostToBind)) {
 -                hostToBind = provider.getHost();
 -            }
 -            if (isInvalidLocalHost(hostToBind)) {
 -                anyhost = true;
 -                try {
 -                    hostToBind = InetAddress.getLocalHost().getHostAddress();
 -                } catch (UnknownHostException e) {
 -                    logger.warn(e.getMessage(), e);
 -                }
 -                if (isInvalidLocalHost(hostToBind)) {
 -                    if (CollectionUtils.isNotEmpty(registryURLs)) {
 -                        for (URL registryURL : registryURLs) {
 -                            if (MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) {
 -                                // skip multicast registry since we cannot connect to it via Socket
 -                                continue;
 -                            }
 -                            try (Socket socket = new Socket()) {
 -                                SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
 -                                socket.connect(addr, 1000);
 -                                hostToBind = socket.getLocalAddress().getHostAddress();
 -                                break;
 -                            } catch (Exception e) {
 -                                logger.warn(e.getMessage(), e);
 -                            }
 -                        }
 -                    }
 -                    if (isInvalidLocalHost(hostToBind)) {
 -                        hostToBind = getLocalHost();
 -                    }
 -                }
 -            }
 -        }
 -
 -        map.put(Constants.BIND_IP_KEY, hostToBind);
 -
 -        // registry ip is not used for bind ip by default
 -        String hostToRegistry = getValueFromConfig(protocolConfig, DUBBO_IP_TO_REGISTRY);
 -        if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) {
 -            throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
 -        } else if (StringUtils.isEmpty(hostToRegistry)) {
 -            // bind ip is used as registry ip by default
 -            hostToRegistry = hostToBind;
 -        }
 -
 -        map.put(ANYHOST_KEY, String.valueOf(anyhost));
 -
 -        return hostToRegistry;
 -    }
 -
 -    /**
 -     * Register port and bind port for the provider, can be configured separately
 -     * Configuration priority: environment variable -> java system properties -> port property in protocol config file
 -     * -> protocol default port
 -     *
 -     * @param protocolConfig
 -     * @param name
 -     * @return
 -     */
 -    private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
 -        Integer portToBind = null;
 -
 -        // parse bind port from environment
 -        String port = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_BIND);
 -        portToBind = parsePort(port);
 -
 -        // if there's no bind port found from environment, keep looking up.
 -        if (portToBind == null) {
 -            portToBind = protocolConfig.getPort();
 -            if (provider != null && (portToBind == null || portToBind == 0)) {
 -                portToBind = provider.getPort();
 -            }
 -            final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
 -            if (portToBind == null || portToBind == 0) {
 -                portToBind = defaultPort;
 -            }
 -            if (portToBind <= 0) {
 -                portToBind = getRandomPort(name);
 -                if (portToBind == null || portToBind < 0) {
 -                    portToBind = getAvailablePort(defaultPort);
 -                    putRandomPort(name, portToBind);
 -                }
 -            }
 -        }
 -
 -        // save bind port, used as url's key later
 -        map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind));
 -
 -        // registry port, not used as bind port by default
 -        String portToRegistryStr = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_REGISTRY);
 -        Integer portToRegistry = parsePort(portToRegistryStr);
 -        if (portToRegistry == null) {
 -            portToRegistry = portToBind;
 -        }
 -
 -        return portToRegistry;
 -    }
 -
 -    private Integer parsePort(String configPort) {
 -        Integer port = null;
 -        if (configPort != null && configPort.length() > 0) {
 -            try {
 -                Integer intPort = Integer.parseInt(configPort);
 -                if (isInvalidPort(intPort)) {
 -                    throw new IllegalArgumentException("Specified invalid port from env value:" + configPort);
 -                }
 -                port = intPort;
 -            } catch (Exception e) {
 -                throw new IllegalArgumentException("Specified invalid port from env value:" + configPort);
 -            }
 -        }
 -        return port;
 -    }
 -
 -    private String getValueFromConfig(ProtocolConfig protocolConfig, String key) {
 -        String protocolPrefix = protocolConfig.getName().toUpperCase() + "_";
 -        String port = ConfigUtils.getSystemProperty(protocolPrefix + key);
 -        if (StringUtils.isEmpty(port)) {
 -            port = ConfigUtils.getSystemProperty(key);
 -        }
 -        return port;
 -    }
 -
 -    private void completeCompoundConfigs() {
 -        if (provider != null) {
 -            if (application == null) {
 -                setApplication(provider.getApplication());
 -            }
 -            if (module == null) {
 -                setModule(provider.getModule());
 -            }
 -            if (registries == null) {
 -                setRegistries(provider.getRegistries());
 -            }
 -            if (monitor == null) {
 -                setMonitor(provider.getMonitor());
 -            }
 -            if (protocols == null) {
 -                setProtocols(provider.getProtocols());
 -            }
 -            if (configCenter == null) {
 -                setConfigCenter(provider.getConfigCenter());
 -            }
 -        }
 -        if (module != null) {
 -            if (registries == null) {
 -                setRegistries(module.getRegistries());
 -            }
 -            if (monitor == null) {
 -                setMonitor(module.getMonitor());
 -            }
 -        }
 -        if (application != null) {
 -            if (registries == null) {
 -                setRegistries(application.getRegistries());
 -            }
 -            if (monitor == null) {
 -                setMonitor(application.getMonitor());
 -            }
 -        }
 -    }
 -
 -    private void checkDefault() {
 -        createProviderIfAbsent();
 -    }
 -
 -    private void createProviderIfAbsent() {
 -        if (provider != null) {
 -            return;
 -        }
 -        setProvider(
 -                ConfigManager.getInstance()
 -                        .getDefaultProvider()
 -                        .orElseGet(() -> {
 -                            ProviderConfig providerConfig = new ProviderConfig();
 -                            providerConfig.refresh();
 -                            return providerConfig;
 -                        })
 -        );
 -    }
 -
 -    private void checkProtocol() {
 -        if (CollectionUtils.isEmpty(protocols) && provider != null) {
 -            setProtocols(provider.getProtocols());
 -        }
 -        convertProtocolIdsToProtocols();
 -    }
 -
 -    private void convertProtocolIdsToProtocols() {
 -        if (StringUtils.isEmpty(protocolIds) && CollectionUtils.isEmpty(protocols)) {
 -            List<String> configedProtocols = new ArrayList<>();
 -            configedProtocols.addAll(getSubProperties(Environment.getInstance()
 -                    .getExternalConfigurationMap(), PROTOCOLS_SUFFIX));
 -            configedProtocols.addAll(getSubProperties(Environment.getInstance()
 -                    .getAppExternalConfigurationMap(), PROTOCOLS_SUFFIX));
 -
 -            protocolIds = String.join(",", configedProtocols);
 -        }
 -
 -        if (StringUtils.isEmpty(protocolIds)) {
 -            if (CollectionUtils.isEmpty(protocols)) {
 -                setProtocols(
 -                        ConfigManager.getInstance().getDefaultProtocols()
 -                                .filter(CollectionUtils::isNotEmpty)
 -                                .orElseGet(() -> {
 -                                    ProtocolConfig protocolConfig = new ProtocolConfig();
 -                                    protocolConfig.refresh();
 -                                    return new ArrayList<>(Arrays.asList(protocolConfig));
 -                                })
 -                );
 -            }
 -        } else {
 -            String[] arr = COMMA_SPLIT_PATTERN.split(protocolIds);
 -            List<ProtocolConfig> tmpProtocols = CollectionUtils.isNotEmpty(protocols) ? protocols : new ArrayList<>();
 -            Arrays.stream(arr).forEach(id -> {
 -                if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) {
 -                    tmpProtocols.add(ConfigManager.getInstance().getProtocol(id).orElseGet(() -> {
 -                        ProtocolConfig protocolConfig = new ProtocolConfig();
 -                        protocolConfig.setId(id);
 -                        protocolConfig.refresh();
 -                        return protocolConfig;
 -                    }));
 -                }
 -            });
 -            if (tmpProtocols.size() > arr.length) {
 -                throw new IllegalStateException("Too much protocols found, the protocols comply to this service are :" + protocolIds + " but got " + protocols
 -                        .size() + " registries!");
 -            }
 -            setProtocols(tmpProtocols);
 -        }
 -    }
 -
 -    public Class<?> getInterfaceClass() {
 -        if (interfaceClass != null) {
 -            return interfaceClass;
 -        }
 -        if (ref instanceof GenericService) {
 -            return GenericService.class;
 -        }
 -        try {
 -            if (interfaceName != null && interfaceName.length() > 0) {
 -                this.interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
 -                        .getContextClassLoader());
 -            }
 -        } catch (ClassNotFoundException t) {
 -            throw new IllegalStateException(t.getMessage(), t);
 -        }
 -        return interfaceClass;
 -    }
 -
 -    /**
 -     * @param interfaceClass
 -     * @see #setInterface(Class)
 -     * @deprecated
 -     */
 -    public void setInterfaceClass(Class<?> interfaceClass) {
 -        setInterface(interfaceClass);
 -    }
 -
 -    public String getInterface() {
 -        return interfaceName;
 -    }
 -
 -    public void setInterface(Class<?> interfaceClass) {
 -        if (interfaceClass != null && !interfaceClass.isInterface()) {
 -            throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
 -        }
 -        this.interfaceClass = interfaceClass;
 -        setInterface(interfaceClass == null ? null : interfaceClass.getName());
 -    }
 -
 -    public void setInterface(String interfaceName) {
 -        this.interfaceName = interfaceName;
 -        if (StringUtils.isEmpty(id)) {
 -            id = interfaceName;
 -        }
 -    }
 -
 -    public T getRef() {
 -        return ref;
 -    }
 -
 -    public void setRef(T ref) {
 -        this.ref = ref;
 -    }
 -
 -    @Parameter(excluded = true)
 -    public String getPath() {
 -        return path;
 -    }
 -
 -    public void setPath(String path) {
 -        checkPathName(PATH_KEY, path);
 -        this.path = path;
 -    }
 -
 -    public List<MethodConfig> getMethods() {
 -        return methods;
 -    }
 -
 -    // ======== Deprecated ========
 -
 -    @SuppressWarnings("unchecked")
 -    public void setMethods(List<? extends MethodConfig> methods) {
 -        this.methods = (List<MethodConfig>) methods;
 -    }
 -
 -    public ProviderConfig getProvider() {
 -        return provider;
 -    }
 -
 -    public void setProvider(ProviderConfig provider) {
 -        ConfigManager.getInstance().addProvider(provider);
 -        this.provider = provider;
 -    }
 -
 -    @Parameter(excluded = true)
 -    public String getProviderIds() {
 -        return providerIds;
 -    }
 -
 -    public void setProviderIds(String providerIds) {
 -        this.providerIds = providerIds;
 -    }
 -
 -    public String getGeneric() {
 -        return generic;
 -    }
 -
 -    public void setGeneric(String generic) {
 -        if (StringUtils.isEmpty(generic)) {
 -            return;
 -        }
 -        if (ProtocolUtils.isGeneric(generic)) {
 -            this.generic = generic;
 -        } else {
 -            throw new IllegalArgumentException("Unsupported generic type " + generic);
 -        }
 -    }
 -
 -    @Override
 -    public void setMock(Boolean mock) {
 -        throw new IllegalArgumentException("mock doesn't support on provider side");
 -    }
 -
 -    @Override
 -    public void setMock(String mock) {
 -        throw new IllegalArgumentException("mock doesn't support on provider side");
 -    }
 -
 -    public List<URL> getExportedUrls() {
 -        return urls;
 -    }
 -
 -    /**
 -     * @deprecated Replace to getProtocols()
 -     */
 -    @Deprecated
 -    public List<ProviderConfig> getProviders() {
 -        return convertProtocolToProvider(protocols);
 -    }
 -
 -    /**
 -     * @deprecated Replace to setProtocols()
 -     */
 -    @Deprecated
 -    public void setProviders(List<ProviderConfig> providers) {
 -        this.protocols = convertProviderToProtocol(providers);
 -    }
 -
 -    @Override
 -    @Parameter(excluded = true)
 -    public String getPrefix() {
 -        return DUBBO + ".service." + interfaceName;
 -    }
 -}
 +
 +/*
 + * 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.URL;
 +import org.apache.dubbo.common.URLBuilder;
 +import org.apache.dubbo.common.Version;
 +import org.apache.dubbo.common.bytecode.Wrapper;
 +import org.apache.dubbo.common.extension.ExtensionLoader;
 +import org.apache.dubbo.common.utils.ClassUtils;
 +import org.apache.dubbo.common.utils.CollectionUtils;
 +import org.apache.dubbo.common.utils.ConfigUtils;
 +import org.apache.dubbo.common.utils.NamedThreadFactory;
 +import org.apache.dubbo.common.utils.StringUtils;
 +import org.apache.dubbo.config.annotation.Service;
 +import org.apache.dubbo.config.context.ConfigManager;
 +import org.apache.dubbo.config.event.ServiceConfigExportedEvent;
 +import org.apache.dubbo.config.event.ServiceConfigUnexportedEvent;
 +import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker;
 +import org.apache.dubbo.config.support.Parameter;
 +import org.apache.dubbo.event.Event;
 +import org.apache.dubbo.event.EventDispatcher;
 +import org.apache.dubbo.metadata.WritableMetadataService;
 +import org.apache.dubbo.remoting.Constants;
 +import org.apache.dubbo.rpc.Exporter;
 +import org.apache.dubbo.rpc.Invoker;
 +import org.apache.dubbo.rpc.Protocol;
 +import org.apache.dubbo.rpc.ProxyFactory;
 +import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
 +import org.apache.dubbo.rpc.model.ApplicationModel;
 +import org.apache.dubbo.rpc.model.ProviderModel;
 +import org.apache.dubbo.rpc.service.GenericService;
 +import org.apache.dubbo.rpc.support.ProtocolUtils;
 +
 +import java.lang.reflect.Method;
 +import java.net.InetAddress;
 +import java.net.InetSocketAddress;
 +import java.net.Socket;
 +import java.net.SocketAddress;
 +import java.net.UnknownHostException;
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Optional;
 +import java.util.UUID;
 +import java.util.concurrent.Executors;
 +import java.util.concurrent.ScheduledExecutorService;
 +import java.util.concurrent.TimeUnit;
 +
 +import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
 +import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
 +import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
 +import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
 +import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
 +import static org.apache.dubbo.common.constants.CommonConstants.METADATA_DEFAULT;
 +import static org.apache.dubbo.common.constants.CommonConstants.METADATA_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
 +import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;
 +import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
 +import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;
 +import static org.apache.dubbo.common.utils.NetUtils.getAvailablePort;
 +import static org.apache.dubbo.common.utils.NetUtils.getLocalHost;
 +import static org.apache.dubbo.common.utils.NetUtils.isInvalidLocalHost;
 +import static org.apache.dubbo.common.utils.NetUtils.isInvalidPort;
 +import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
 +import static org.apache.dubbo.config.Constants.DUBBO_PORT_TO_BIND;
 +import static org.apache.dubbo.config.Constants.DUBBO_PORT_TO_REGISTRY;
 +import static org.apache.dubbo.config.Constants.MULTICAST;
 +import static org.apache.dubbo.config.Constants.SCOPE_NONE;
 +import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
 +import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
 +import static org.apache.dubbo.rpc.Constants.PROXY_KEY;
 +import static org.apache.dubbo.rpc.Constants.SCOPE_KEY;
 +import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
 +import static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;
 +import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
 +import static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;
 +
 +/**
 + * ServiceConfig
 + *
 + * @export
 + */
 +public class ServiceConfig<T> extends AbstractServiceConfig {
 +
 +    private static final long serialVersionUID = 3033787999037024738L;
 +
 +    /**
 +     * The {@link Protocol} implementation with adaptive functionality,it will be different in different scenarios.
 +     * A particular {@link Protocol} implementation is determined by the protocol attribute in the {@link URL}.
 +     * For example:
 +     *
 +     * <li>when the url is registry://224.5.6.7:1234/org.apache.dubbo.registry.RegistryService?application=dubbo-sample,
 +     * then the protocol is <b>RegistryProtocol</b></li>
 +     *
 +     * <li>when the url is dubbo://224.5.6.7:1234/org.apache.dubbo.config.api.DemoService?application=dubbo-sample, then
 +     * the protocol is <b>DubboProtocol</b></li>
 +     * <p>
 +     * Actually,when the {@link ExtensionLoader} init the {@link Protocol} instants,it will automatically wraps two
 +     * layers, and eventually will get a <b>ProtocolFilterWrapper</b> or <b>ProtocolListenerWrapper</b>
 +     */
 +    private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
 +
 +    /**
 +     * A {@link ProxyFactory} implementation that will generate a exported service proxy,the JavassistProxyFactory is its
 +     * default implementation
 +     */
 +    private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
 +
 +    /**
 +     * A random port cache, the different protocols who has no port specified have different random port
 +     */
 +    private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap<String, Integer>();
 +
 +    /**
 +     * A delayed exposure service timer
 +     */
 +    private static final ScheduledExecutorService DELAY_EXPORT_EXECUTOR = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));
 +
 +    /**
 +     * The urls of the services exported
 +     */
 +    private final List<URL> urls = new ArrayList<URL>();
 +
 +    /**
 +     * The exported services
 +     */
 +    private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>();
 +
 +    /**
 +     * The interface name of the exported service
 +     */
 +    private String interfaceName;
 +
 +    /**
 +     * The interface class of the exported service
 +     */
 +    private Class<?> interfaceClass;
 +
 +    /**
 +     * The reference of the interface implementation
 +     */
 +    private T ref;
 +
 +    /**
 +     * The service name
 +     */
 +    private String path;
 +
 +    /**
 +     * The method configuration
 +     */
 +    private List<MethodConfig> methods;
 +
 +    /**
 +     * The provider configuration
 +     */
 +    private ProviderConfig provider;
 +
 +    /**
 +     * The providerIds
 +     */
 +    private String providerIds;
 +
 +    /**
 +     * Whether the provider has been exported
 +     */
 +    private transient volatile boolean exported;
 +
 +    /**
 +     * The flag whether a service has unexported ,if the method unexported is invoked, the value is true
 +     */
 +    private transient volatile boolean unexported;
 +
 +    /**
 +     * whether it is a GenericService
 +     */
 +    private volatile String generic;
 +
 +    /**
 +     * @since 2.7.4
 +     */
 +    private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
 +
 +
 +    public ServiceConfig() {
 +    }
 +
 +    public ServiceConfig(Service service) {
 +        appendAnnotation(Service.class, service);
 +        setMethods(MethodConfig.constructMethodConfig(service.methods()));
 +    }
 +
 +    @Deprecated
 +    private static List<ProtocolConfig> convertProviderToProtocol(List<ProviderConfig> providers) {
 +        if (CollectionUtils.isEmpty(providers)) {
 +            return null;
 +        }
 +        List<ProtocolConfig> protocols = new ArrayList<ProtocolConfig>(providers.size());
 +        for (ProviderConfig provider : providers) {
 +            protocols.add(convertProviderToProtocol(provider));
 +        }
 +        return protocols;
 +    }
 +
 +    @Deprecated
 +    private static List<ProviderConfig> convertProtocolToProvider(List<ProtocolConfig> protocols) {
 +        if (CollectionUtils.isEmpty(protocols)) {
 +            return null;
 +        }
 +        List<ProviderConfig> providers = new ArrayList<ProviderConfig>(protocols.size());
 +        for (ProtocolConfig provider : protocols) {
 +            providers.add(convertProtocolToProvider(provider));
 +        }
 +        return providers;
 +    }
 +
 +    @Deprecated
 +    private static ProtocolConfig convertProviderToProtocol(ProviderConfig provider) {
 +        ProtocolConfig protocol = new ProtocolConfig();
 +        protocol.setName(provider.getProtocol().getName());
 +        protocol.setServer(provider.getServer());
 +        protocol.setClient(provider.getClient());
 +        protocol.setCodec(provider.getCodec());
 +        protocol.setHost(provider.getHost());
 +        protocol.setPort(provider.getPort());
 +        protocol.setPath(provider.getPath());
 +        protocol.setPayload(provider.getPayload());
 +        protocol.setThreads(provider.getThreads());
 +        protocol.setParameters(provider.getParameters());
 +        return protocol;
 +    }
 +
 +    @Deprecated
 +    private static ProviderConfig convertProtocolToProvider(ProtocolConfig protocol) {
 +        ProviderConfig provider = new ProviderConfig();
 +        provider.setProtocol(protocol);
 +        provider.setServer(protocol.getServer());
 +        provider.setClient(protocol.getClient());
 +        provider.setCodec(protocol.getCodec());
 +        provider.setHost(protocol.getHost());
 +        provider.setPort(protocol.getPort());
 +        provider.setPath(protocol.getPath());
 +        provider.setPayload(protocol.getPayload());
 +        provider.setThreads(protocol.getThreads());
 +        provider.setParameters(protocol.getParameters());
 +        return provider;
 +    }
 +
 +    private static Integer getRandomPort(String protocol) {
 +        protocol = protocol.toLowerCase();
 +        return RANDOM_PORT_MAP.getOrDefault(protocol, Integer.MIN_VALUE);
 +    }
 +
 +    private static void putRandomPort(String protocol, Integer port) {
 +        protocol = protocol.toLowerCase();
 +        if (!RANDOM_PORT_MAP.containsKey(protocol)) {
 +            RANDOM_PORT_MAP.put(protocol, port);
 +            logger.warn("Use random available port(" + port + ") for protocol " + protocol);
 +        }
 +    }
 +
 +    public URL toUrl() {
 +        return urls.isEmpty() ? null : urls.iterator().next();
 +    }
 +
 +    public List<URL> toUrls() {
 +        return urls;
 +    }
 +
 +    @Parameter(excluded = true)
 +    public boolean isExported() {
 +        return exported;
 +    }
 +
 +    @Parameter(excluded = true)
 +    public boolean isUnexported() {
 +        return unexported;
 +    }
 +
 +    public void checkAndUpdateSubConfigs() {
 +        // Use default configs defined explicitly on global scope
 +        completeCompoundConfigs();
 +        checkDefault();
 +        checkProtocol();
 +        checkApplication();
 +        // if protocol is not injvm checkRegistry
 +        if (!isOnlyInJvm()) {
 +            checkRegistry();
 +        }
 +        this.refresh();
 +        checkMetadataReport();
 +
 +        if (StringUtils.isEmpty(interfaceName)) {
 +            throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
 +        }
 +
 +        if (ref instanceof GenericService) {
 +            interfaceClass = GenericService.class;
 +            if (StringUtils.isEmpty(generic)) {
 +                generic = Boolean.TRUE.toString();
 +            }
 +        } else {
 +            try {
 +                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
 +                        .getContextClassLoader());
 +            } catch (ClassNotFoundException e) {
 +                throw new IllegalStateException(e.getMessage(), e);
 +            }
 +            checkInterfaceAndMethods(interfaceClass, methods);
 +            checkRef();
 +            generic = Boolean.FALSE.toString();
 +        }
 +        if (local != null) {
 +            if ("true".equals(local)) {
 +                local = interfaceName + "Local";
 +            }
 +            Class<?> localClass;
 +            try {
 +                localClass = ClassUtils.forNameWithThreadContextClassLoader(local);
 +            } catch (ClassNotFoundException e) {
 +                throw new IllegalStateException(e.getMessage(), e);
 +            }
 +            if (!interfaceClass.isAssignableFrom(localClass)) {
 +                throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
 +            }
 +        }
 +        if (stub != null) {
 +            if ("true".equals(stub)) {
 +                stub = interfaceName + "Stub";
 +            }
 +            Class<?> stubClass;
 +            try {
 +                stubClass = ClassUtils.forNameWithThreadContextClassLoader(stub);
 +            } catch (ClassNotFoundException e) {
 +                throw new IllegalStateException(e.getMessage(), e);
 +            }
 +            if (!interfaceClass.isAssignableFrom(stubClass)) {
 +                throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
 +            }
 +        }
 +        checkStubAndLocal(interfaceClass);
 +        checkMock(interfaceClass);
 +    }
 +
 +    /**
 +     * Determine if it is injvm
 +     *
 +     * @return
 +     */
 +    private boolean isOnlyInJvm() {
 +        return getProtocols().size() == 1 && LOCAL_PROTOCOL.equalsIgnoreCase(getProtocols().get(0).getName());
 +    }
 +
 +    public synchronized void export() {
 +        checkAndUpdateSubConfigs();
 +
 +        if (!shouldExport()) {
 +            return;
 +        }
 +
 +        if (shouldDelay()) {
 +            DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
 +        } else {
 +            doExport();
 +        }
 +    }
 +
 +    private boolean shouldExport() {
 +        Boolean export = getExport();
 +        // default value is true
 +        return export == null ? true : export;
 +    }
 +
 +    @Override
 +    public Boolean getExport() {
 +        return (export == null && provider != null) ? provider.getExport() : export;
 +    }
 +
 +    private boolean shouldDelay() {
 +        Integer delay = getDelay();
 +        return delay != null && delay > 0;
 +    }
 +
 +    @Override
 +    public Integer getDelay() {
 +        return (delay == null && provider != null) ? provider.getDelay() : delay;
 +    }
 +
 +    protected synchronized void doExport() {
 +        if (unexported) {
 +            throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!");
 +        }
 +        if (exported) {
 +            return;
 +        }
 +        exported = true;
 +
 +        if (StringUtils.isEmpty(path)) {
 +            path = interfaceName;
 +        }
 +        doExportUrls();
 +
 +        // dispatch a ServiceConfigExportedEvent since 2.7.4
 +        dispatch(new ServiceConfigExportedEvent(this));
 +    }
 +
 +    private void checkRef() {
 +        // reference should not be null, and is the implementation of the given interface
 +        if (ref == null) {
 +            throw new IllegalStateException("ref not allow null!");
 +        }
 +        if (!interfaceClass.isInstance(ref)) {
 +            throw new IllegalStateException("The class "
 +                    + ref.getClass().getName() + " unimplemented interface "
 +                    + interfaceClass + "!");
 +        }
 +    }
 +
 +    public synchronized void unexport() {
 +        if (!exported) {
 +            return;
 +        }
 +        if (unexported) {
 +            return;
 +        }
 +        if (!exporters.isEmpty()) {
 +            for (Exporter<?> exporter : exporters) {
 +                try {
 +                    exporter.unexport();
 +                } catch (Throwable t) {
 +                    logger.warn("Unexpected error occured when unexport " + exporter, t);
 +                }
 +            }
 +            exporters.clear();
 +        }
 +        unexported = true;
 +
 +        // dispatch a ServiceConfigUnExportedEvent since 2.7.4
 +        dispatch(new ServiceConfigUnexportedEvent(this));
 +    }
 +
 +    @SuppressWarnings({"unchecked", "rawtypes"})
 +    private void doExportUrls() {
 +        List<URL> registryURLs = loadRegistries(true);
 +        for (ProtocolConfig protocolConfig : protocols) {
 +            String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version);
 +            ProviderModel providerModel = new ProviderModel(pathKey, ref, interfaceClass);
 +            ApplicationModel.initProviderModel(pathKey, providerModel);
 +            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
 +        }
 +    }
 +
 +    private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
 +        String name = protocolConfig.getName();
 +        if (StringUtils.isEmpty(name)) {
 +            name = DUBBO;
 +        }
 +
 +        Map<String, String> map = new HashMap<String, String>();
 +        map.put(SIDE_KEY, PROVIDER_SIDE);
 +
 +        appendRuntimeParameters(map);
 +        appendParameters(map, metrics);
 +        appendParameters(map, application);
 +        appendParameters(map, module);
 +        // remove 'default.' prefix for configs from ProviderConfig
 +        // appendParameters(map, provider, Constants.DEFAULT_KEY);
 +        appendParameters(map, provider);
 +        appendParameters(map, protocolConfig);
 +        appendParameters(map, this);
 +        if (CollectionUtils.isNotEmpty(methods)) {
 +            for (MethodConfig method : methods) {
 +                appendParameters(map, method, method.getName());
 +                String retryKey = method.getName() + ".retry";
 +                if (map.containsKey(retryKey)) {
 +                    String retryValue = map.remove(retryKey);
 +                    if ("false".equals(retryValue)) {
 +                        map.put(method.getName() + ".retries", "0");
 +                    }
 +                }
 +                List<ArgumentConfig> arguments = method.getArguments();
 +                if (CollectionUtils.isNotEmpty(arguments)) {
 +                    for (ArgumentConfig argument : arguments) {
 +                        // convert argument type
 +                        if (argument.getType() != null && argument.getType().length() > 0) {
 +                            Method[] methods = interfaceClass.getMethods();
 +                            // visit all methods
 +                            if (methods != null && methods.length > 0) {
 +                                for (int i = 0; i < methods.length; i++) {
 +                                    String methodName = methods[i].getName();
 +                                    // target the method, and get its signature
 +                                    if (methodName.equals(method.getName())) {
 +                                        Class<?>[] argtypes = methods[i].getParameterTypes();
 +                                        // one callback in the method
 +                                        if (argument.getIndex() != -1) {
 +                                            if (argtypes[argument.getIndex()].getName().equals(argument.getType())) {
 +                                                appendParameters(map, argument, method.getName() + "." + argument.getIndex());
 +                                            } else {
 +                                                throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
 +                                            }
 +                                        } else {
 +                                            // multiple callbacks in the method
 +                                            for (int j = 0; j < argtypes.length; j++) {
 +                                                Class<?> argclazz = argtypes[j];
 +                                                if (argclazz.getName().equals(argument.getType())) {
 +                                                    appendParameters(map, argument, method.getName() + "." + j);
 +                                                    if (argument.getIndex() != -1 && argument.getIndex() != j) {
 +                                                        throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
 +                                                    }
 +                                                }
 +                                            }
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                        } else if (argument.getIndex() != -1) {
 +                            appendParameters(map, argument, method.getName() + "." + argument.getIndex());
 +                        } else {
 +                            throw new IllegalArgumentException("Argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
 +                        }
 +
 +                    }
 +                }
 +            } // end of methods for
 +        }
 +
 +        if (ProtocolUtils.isGeneric(generic)) {
 +            map.put(GENERIC_KEY, generic);
 +            map.put(METHODS_KEY, ANY_VALUE);
 +        } else {
 +            String revision = Version.getVersion(interfaceClass, version);
 +            if (revision != null && revision.length() > 0) {
 +                map.put(REVISION_KEY, revision);
 +            }
 +
 +            String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
 +            if (methods.length == 0) {
 +                logger.warn("No method found in service interface " + interfaceClass.getName());
 +                map.put(METHODS_KEY, ANY_VALUE);
 +            } else {
 +                map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
 +            }
 +        }
 +        if (!ConfigUtils.isEmpty(token)) {
 +            if (ConfigUtils.isDefault(token)) {
 +                map.put(TOKEN_KEY, UUID.randomUUID().toString());
 +            } else {
 +                map.put(TOKEN_KEY, token);
 +            }
 +        }
 +        // export service
 +        String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
 +        Integer port = this.findConfigedPorts(protocolConfig, name, map);
 +        URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
 +
 +        if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
 +                .hasExtension(url.getProtocol())) {
 +            url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
 +                    .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
 +        }
 +
 +        String scope = url.getParameter(SCOPE_KEY);
 +        // don't export when none is configured
 +        if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
 +
 +            // export to local if the config is not remote (export to remote only when config is remote)
 +            if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
 +                exportLocal(url);
 +            }
 +            // export to remote if the config is not local (export to local only when config is local)
 +            if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
 +                if (!isOnlyInJvm() && logger.isInfoEnabled()) {
 +                    logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
 +                }
 +                if (CollectionUtils.isNotEmpty(registryURLs)) {
 +                    for (URL registryURL : registryURLs) {
 +                        //if protocol is only injvm ,not register
 +                        if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
 +                            continue;
 +                        }
 +                        url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
 +                        URL monitorUrl = loadMonitor(registryURL);
 +                        if (monitorUrl != null) {
 +                            url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());
 +                        }
 +                        if (logger.isInfoEnabled()) {
 +                            logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
 +                        }
 +
 +                        // For providers, this is used to enable custom proxy to generate invoker
 +                        String proxy = url.getParameter(PROXY_KEY);
 +                        if (StringUtils.isNotEmpty(proxy)) {
 +                            registryURL = registryURL.addParameter(PROXY_KEY, proxy);
 +                        }
 +
 +                        Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
 +                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
 +
 +                        Exporter<?> exporter = protocol.export(wrapperInvoker);
 +                        exporters.add(exporter);
 +                    }
 +                } else {
 +                    Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);
 +                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
 +
 +                    Exporter<?> exporter = protocol.export(wrapperInvoker);
 +                    exporters.add(exporter);
 +                }
 +                /**
 +                 * @since 2.7.0
 +                 * ServiceData Store
 +                 */
 +                WritableMetadataService metadataService = WritableMetadataService.getExtension(url.getParameter(METADATA_KEY, METADATA_DEFAULT));
 +                if (metadataService != null) {
 +                    metadataService.publishServiceDefinition(url);
 +                }
 +            }
 +        }
 +        this.urls.add(url);
 +    }
 +
 +    @SuppressWarnings({"unchecked", "rawtypes"})
 +    /**
 +     * always export injvm
 +     */
 +    private void exportLocal(URL url) {
 +        URL local = URLBuilder.from(url)
 +                .setProtocol(LOCAL_PROTOCOL)
 +                .setHost(LOCALHOST_VALUE)
 +                .setPort(0)
 +                .build();
 +        Exporter<?> exporter = protocol.export(
 +                PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));
 +        exporters.add(exporter);
 +        logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local);
 +    }
 +
 +    private Optional<String> getContextPath(ProtocolConfig protocolConfig) {
 +        String contextPath = protocolConfig.getContextpath();
 +        if (StringUtils.isEmpty(contextPath) && provider != null) {
 +            contextPath = provider.getContextpath();
 +        }
 +        return Optional.ofNullable(contextPath);
 +    }
 +
 +    protected Class getServiceClass(T ref) {
 +        return ref.getClass();
 +    }
 +
 +    /**
 +     * Register & bind IP address for service provider, can be configured separately.
 +     * Configuration priority: environment variables -> java system properties -> host property in config file ->
 +     * /etc/hosts -> default network address -> first available network address
 +     *
 +     * @param protocolConfig
 +     * @param registryURLs
 +     * @param map
 +     * @return
 +     */
 +    private String findConfigedHosts(ProtocolConfig protocolConfig, List<URL> registryURLs, Map<String, String> map) {
 +        boolean anyhost = false;
 +
 +        String hostToBind = getValueFromConfig(protocolConfig, DUBBO_IP_TO_BIND);
 +        if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) {
 +            throw new IllegalArgumentException("Specified invalid bind ip from property:" + DUBBO_IP_TO_BIND + ", value:" + hostToBind);
 +        }
 +
 +        // if bind ip is not found in environment, keep looking up
 +        if (StringUtils.isEmpty(hostToBind)) {
 +            hostToBind = protocolConfig.getHost();
 +            if (provider != null && StringUtils.isEmpty(hostToBind)) {
 +                hostToBind = provider.getHost();
 +            }
 +            if (isInvalidLocalHost(hostToBind)) {
 +                anyhost = true;
 +                try {
 +                    hostToBind = InetAddress.getLocalHost().getHostAddress();
 +                } catch (UnknownHostException e) {
 +                    logger.warn(e.getMessage(), e);
 +                }
 +                if (isInvalidLocalHost(hostToBind)) {
 +                    if (CollectionUtils.isNotEmpty(registryURLs)) {
 +                        for (URL registryURL : registryURLs) {
 +                            if (MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) {
 +                                // skip multicast registry since we cannot connect to it via Socket
 +                                continue;
 +                            }
 +                            try (Socket socket = new Socket()) {
 +                                SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
 +                                socket.connect(addr, 1000);
 +                                hostToBind = socket.getLocalAddress().getHostAddress();
 +                                break;
 +                            } catch (Exception e) {
 +                                logger.warn(e.getMessage(), e);
 +                            }
 +                        }
 +                    }
 +                    if (isInvalidLocalHost(hostToBind)) {
 +                        hostToBind = getLocalHost();
 +                    }
 +                }
 +            }
 +        }
 +
 +        map.put(Constants.BIND_IP_KEY, hostToBind);
 +
 +        // registry ip is not used for bind ip by default
 +        String hostToRegistry = getValueFromConfig(protocolConfig, DUBBO_IP_TO_REGISTRY);
 +        if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) {
 +            throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
 +        } else if (StringUtils.isEmpty(hostToRegistry)) {
 +            // bind ip is used as registry ip by default
 +            hostToRegistry = hostToBind;
 +        }
 +
 +        map.put(ANYHOST_KEY, String.valueOf(anyhost));
 +
 +        return hostToRegistry;
 +    }
 +
 +    /**
 +     * Register port and bind port for the provider, can be configured separately
 +     * Configuration priority: environment variable -> java system properties -> port property in protocol config file
 +     * -> protocol default port
 +     *
 +     * @param protocolConfig
 +     * @param name
 +     * @return
 +     */
 +    private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
 +        Integer portToBind = null;
 +
 +        // parse bind port from environment
 +        String port = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_BIND);
 +        portToBind = parsePort(port);
 +
 +        // if there's no bind port found from environment, keep looking up.
 +        if (portToBind == null) {
 +            portToBind = protocolConfig.getPort();
 +            if (provider != null && (portToBind == null || portToBind == 0)) {
 +                portToBind = provider.getPort();
 +            }
 +            final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
 +            if (portToBind == null || portToBind == 0) {
 +                portToBind = defaultPort;
 +            }
-             if (portToBind == null || portToBind <= 0) {
++            if (portToBind <= 0) {
 +                portToBind = getRandomPort(name);
 +                if (portToBind == null || portToBind < 0) {
 +                    portToBind = getAvailablePort(defaultPort);
 +                    putRandomPort(name, portToBind);
 +                }
 +            }
 +        }
 +
 +        // save bind port, used as url's key later
 +        map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind));
 +
 +        // registry port, not used as bind port by default
 +        String portToRegistryStr = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_REGISTRY);
 +        Integer portToRegistry = parsePort(portToRegistryStr);
 +        if (portToRegistry == null) {
 +            portToRegistry = portToBind;
 +        }
 +
 +        return portToRegistry;
 +    }
 +
 +    private Integer parsePort(String configPort) {
 +        Integer port = null;
 +        if (configPort != null && configPort.length() > 0) {
 +            try {
 +                Integer intPort = Integer.parseInt(configPort);
 +                if (isInvalidPort(intPort)) {
 +                    throw new IllegalArgumentException("Specified invalid port from env value:" + configPort);
 +                }
 +                port = intPort;
 +            } catch (Exception e) {
 +                throw new IllegalArgumentException("Specified invalid port from env value:" + configPort);
 +            }
 +        }
 +        return port;
 +    }
 +
 +    private String getValueFromConfig(ProtocolConfig protocolConfig, String key) {
 +        String protocolPrefix = protocolConfig.getName().toUpperCase() + "_";
 +        String port = ConfigUtils.getSystemProperty(protocolPrefix + key);
 +        if (StringUtils.isEmpty(port)) {
 +            port = ConfigUtils.getSystemProperty(key);
 +        }
 +        return port;
 +    }
 +
 +    private void completeCompoundConfigs() {
 +        if (provider != null) {
 +            if (application == null) {
 +                setApplication(provider.getApplication());
 +            }
 +            if (module == null) {
 +                setModule(provider.getModule());
 +            }
 +            if (registries == null) {
 +                setRegistries(provider.getRegistries());
 +            }
 +            if (monitor == null) {
 +                setMonitor(provider.getMonitor());
 +            }
 +            if (protocols == null) {
 +                setProtocols(provider.getProtocols());
 +            }
 +            if (configCenter == null) {
 +                setConfigCenter(provider.getConfigCenter());
 +            }
 +        }
 +        if (module != null) {
 +            if (registries == null) {
 +                setRegistries(module.getRegistries());
 +            }
 +            if (monitor == null) {
 +                setMonitor(module.getMonitor());
 +            }
 +        }
 +        if (application != null) {
 +            if (registries == null) {
 +                setRegistries(application.getRegistries());
 +            }
 +            if (monitor == null) {
 +                setMonitor(application.getMonitor());
 +            }
 +        }
 +    }
 +
 +    private void checkDefault() {
 +        createProviderIfAbsent();
 +    }
 +
 +    private void createProviderIfAbsent() {
 +        if (provider != null) {
 +            return;
 +        }
 +        setProvider(
 +                ConfigManager.getInstance()
 +                        .getDefaultProvider()
 +                        .orElseGet(() -> {
 +                            ProviderConfig providerConfig = new ProviderConfig();
 +                            providerConfig.refresh();
 +                            return providerConfig;
 +                        })
 +        );
 +    }
 +
 +    private void checkProtocol() {
 +        if (CollectionUtils.isEmpty(protocols) && provider != null) {
 +            setProtocols(provider.getProtocols());
 +        }
 +        convertProtocolIdsToProtocols();
 +    }
 +
 +    private void convertProtocolIdsToProtocols() {
 +        if (StringUtils.isEmpty(protocolIds)) {
 +            if (CollectionUtils.isEmpty(protocols)) {
 +                setProtocols(
 +                        ConfigManager.getInstance().getDefaultProtocols()
 +                                .filter(CollectionUtils::isNotEmpty)
 +                                .orElseGet(() -> {
 +                                    ProtocolConfig protocolConfig = new ProtocolConfig();
 +                                    protocolConfig.refresh();
 +                                    return new ArrayList<>(Arrays.asList(protocolConfig));
 +                                })
 +                );
 +            }
 +        } else {
 +            String[] arr = COMMA_SPLIT_PATTERN.split(protocolIds);
 +            List<ProtocolConfig> tmpProtocols = CollectionUtils.isNotEmpty(protocols) ? protocols : new ArrayList<>();
 +            Arrays.stream(arr).forEach(id -> {
 +                if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) {
 +                    ConfigManager.getInstance().getProtocol(id).ifPresent(tmpProtocols::add);
 +                }
 +            });
 +            if (tmpProtocols.size() > arr.length) {
 +                throw new IllegalStateException("Too much protocols found, the protocols comply to this service are :" + protocolIds + " but got " + protocols
 +                        .size() + " registries!");
 +            }
 +            setProtocols(tmpProtocols);
 +        }
 +    }
 +
 +    public Class<?> getInterfaceClass() {
 +        if (interfaceClass != null) {
 +            return interfaceClass;
 +        }
 +        if (ref instanceof GenericService) {
 +            return GenericService.class;
 +        }
 +        try {
 +            if (interfaceName != null && interfaceName.length() > 0) {
 +                this.interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
 +                        .getContextClassLoader());
 +            }
 +        } catch (ClassNotFoundException t) {
 +            throw new IllegalStateException(t.getMessage(), t);
 +        }
 +        return interfaceClass;
 +    }
 +
 +    /**
 +     * @param interfaceClass
 +     * @see #setInterface(Class)
 +     * @deprecated
 +     */
 +    public void setInterfaceClass(Class<?> interfaceClass) {
 +        setInterface(interfaceClass);
 +    }
 +
 +    public String getInterface() {
 +        return interfaceName;
 +    }
 +
 +    public void setInterface(Class<?> interfaceClass) {
 +        if (interfaceClass != null && !interfaceClass.isInterface()) {
 +            throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
 +        }
 +        this.interfaceClass = interfaceClass;
 +        setInterface(interfaceClass == null ? null : interfaceClass.getName());
 +    }
 +
 +    public void setInterface(String interfaceName) {
 +        this.interfaceName = interfaceName;
 +        if (StringUtils.isEmpty(id)) {
 +            id = interfaceName;
 +        }
 +    }
 +
 +    public T getRef() {
 +        return ref;
 +    }
 +
 +    public void setRef(T ref) {
 +        this.ref = ref;
 +    }
 +
 +    @Parameter(excluded = true)
 +    public String getPath() {
 +        return path;
 +    }
 +
 +    public void setPath(String path) {
 +        checkPathName(PATH_KEY, path);
 +        this.path = path;
 +    }
 +
 +    public List<MethodConfig> getMethods() {
 +        return methods;
 +    }
 +
 +    // ======== Deprecated ========
 +
 +    @SuppressWarnings("unchecked")
 +    public void setMethods(List<? extends MethodConfig> methods) {
 +        this.methods = (List<MethodConfig>) methods;
 +    }
 +
 +    public ProviderConfig getProvider() {
 +        return provider;
 +    }
 +
 +    public void setProvider(ProviderConfig provider) {
 +        ConfigManager.getInstance().addProvider(provider);
 +        this.provider = provider;
 +    }
 +
 +    @Parameter(excluded = true)
 +    public String getProviderIds() {
 +        return providerIds;
 +    }
 +
 +    public void setProviderIds(String providerIds) {
 +        this.providerIds = providerIds;
 +    }
 +
 +    public String getGeneric() {
 +        return generic;
 +    }
 +
 +    public void setGeneric(String generic) {
 +        if (StringUtils.isEmpty(generic)) {
 +            return;
 +        }
 +        if (ProtocolUtils.isGeneric(generic)) {
 +            this.generic = generic;
 +        } else {
 +            throw new IllegalArgumentException("Unsupported generic type " + generic);
 +        }
 +    }
 +
 +    @Override
 +    public void setMock(Boolean mock) {
 +        throw new IllegalArgumentException("mock doesn't support on provider side");
 +    }
 +
 +    @Override
 +    public void setMock(String mock) {
 +        throw new IllegalArgumentException("mock doesn't support on provider side");
 +    }
 +
 +    public List<URL> getExportedUrls() {
 +        return urls;
 +    }
 +
 +    /**
 +     * @deprecated Replace to getProtocols()
 +     */
 +    @Deprecated
 +    public List<ProviderConfig> getProviders() {
 +        return convertProtocolToProvider(protocols);
 +    }
 +
 +    /**
 +     * @deprecated Replace to setProtocols()
 +     */
 +    @Deprecated
 +    public void setProviders(List<ProviderConfig> providers) {
 +        this.protocols = convertProviderToProtocol(providers);
 +    }
 +
 +    @Override
 +    @Parameter(excluded = true)
 +    public String getPrefix() {
 +        return DUBBO + ".service." + interfaceName;
 +    }
 +
 +    /**
 +     * Dispatch an {@link Event event}
 +     *
 +     * @param event an {@link Event event}
 +     * @since 2.7.4
 +     */
 +    protected void dispatch(Event event) {
 +        eventDispatcher.dispatch(event);
 +    }
 +}
diff --cc dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
index f9afb35,b77a33c..cb4d7fd
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
@@@ -169,18 -133,18 +169,18 @@@ public class ReferenceConfigTest 
      public void testConstructWithReferenceAnnotation() throws NoSuchFieldException {
          Reference reference = getClass().getDeclaredField("innerTest").getAnnotation(Reference.class);
          ReferenceConfig referenceConfig = new ReferenceConfig(reference);
-         Assertions.assertTrue(referenceConfig.getMethods().size() == 1);
-         assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getName(), "sayHello");
-         Assertions.assertTrue(((MethodConfig) referenceConfig.getMethods().get(0)).getTimeout() == 1300);
-         Assertions.assertTrue(((MethodConfig) referenceConfig.getMethods().get(0)).getRetries() == 4);
-         assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getLoadbalance(), "random");
-         Assertions.assertTrue(((MethodConfig) referenceConfig.getMethods().get(0)).getActives() == 3);
-         Assertions.assertTrue(((MethodConfig) referenceConfig.getMethods().get(0)).getExecutes() == 5);
+         Assertions.assertEquals(1, referenceConfig.getMethods().size());
+         Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getName(), "sayHello");
+         Assertions.assertEquals(1300, (int)((MethodConfig)referenceConfig.getMethods().get(0)).getTimeout());
+         Assertions.assertEquals(4, (int)((MethodConfig)referenceConfig.getMethods().get(0)).getRetries());
+         Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getLoadbalance(), "random");
+         Assertions.assertEquals(3, (int)((MethodConfig)referenceConfig.getMethods().get(0)).getActives());
+         Assertions.assertEquals(5, (int)((MethodConfig)referenceConfig.getMethods().get(0)).getExecutes());
          Assertions.assertTrue(((MethodConfig) referenceConfig.getMethods().get(0)).isAsync());
 -        Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOninvoke(), "i");
 -        Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOnreturn(), "r");
 -        Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOnthrow(), "t");
 -        Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getCache(), "c");
 +        assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOninvoke(), "i");
 +        assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOnreturn(), "r");
 +        assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOnthrow(), "t");
 +        assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getCache(), "c");
      }
  
  
diff --cc dubbo-configcenter/dubbo-configcenter-consul/src/main/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfiguration.java
index 0303984,f57f639..26f9cac
--- a/dubbo-configcenter/dubbo-configcenter-consul/src/main/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfiguration.java
+++ b/dubbo-configcenter/dubbo-configcenter-consul/src/main/java/org/apache/dubbo/configcenter/consul/ConsulDynamicConfiguration.java
@@@ -39,9 -39,9 +39,11 @@@ import java.util.concurrent.ConcurrentM
  import java.util.concurrent.ExecutorService;
  
  import static java.util.concurrent.Executors.newCachedThreadPool;
 +import static org.apache.dubbo.common.config.configcenter.ConfigChangeType.ADDED;
 +import static org.apache.dubbo.common.config.configcenter.Constants.CONFIG_NAMESPACE_KEY;
  import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
+ import static org.apache.dubbo.configcenter.ConfigChangeType.ADDED;
+ import static org.apache.dubbo.configcenter.Constants.CONFIG_NAMESPACE_KEY;
  
  /**
   * config center implementation for consul
diff --cc dubbo-configcenter/dubbo-configcenter-etcd/src/test/java/org/apache/dubbo/configcenter/support/etcd/EtcdDynamicConfigurationTest.java
index 8b4f739,6cd1058..bc4fd68
--- a/dubbo-configcenter/dubbo-configcenter-etcd/src/test/java/org/apache/dubbo/configcenter/support/etcd/EtcdDynamicConfigurationTest.java
+++ b/dubbo-configcenter/dubbo-configcenter-etcd/src/test/java/org/apache/dubbo/configcenter/support/etcd/EtcdDynamicConfigurationTest.java
@@@ -18,8 -18,9 +18,9 @@@
  package org.apache.dubbo.configcenter.support.etcd;
  
  import org.apache.dubbo.common.URL;
 -import org.apache.dubbo.configcenter.ConfigChangeEvent;
 -import org.apache.dubbo.configcenter.ConfigurationListener;
 -import org.apache.dubbo.configcenter.DynamicConfiguration;
 +import org.apache.dubbo.common.config.configcenter.ConfigChangeEvent;
 +import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
++import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
  
  import io.etcd.jetcd.ByteSequence;
  import io.etcd.jetcd.Client;
diff --cc dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java
index e48699c,78c1211..df3f5e2
--- a/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java
+++ b/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java
@@@ -18,9 -18,13 +18,13 @@@
  package org.apache.dubbo.configcenter.support.nacos;
  
  import org.apache.dubbo.common.URL;
 -import org.apache.dubbo.configcenter.ConfigChangeEvent;
 -import org.apache.dubbo.configcenter.ConfigurationListener;
 -import org.apache.dubbo.configcenter.DynamicConfiguration;
 +import org.apache.dubbo.common.config.configcenter.ConfigChangeEvent;
 +import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
++import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
  
+ import com.alibaba.nacos.api.NacosFactory;
+ import com.alibaba.nacos.api.config.ConfigService;
+ import com.alibaba.nacos.api.exception.NacosException;
  import org.junit.jupiter.api.AfterAll;
  import org.junit.jupiter.api.Assertions;
  import org.junit.jupiter.api.BeforeAll;
diff --cc dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
index 8ee4581,096b71c..2dd32fc
--- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
+++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
@@@ -99,70 -97,20 +103,68 @@@ public class ZookeeperDynamicConfigurat
      }
  
      @Override
-     public String getConfig(String key, String group, long timeout) throws IllegalStateException {
-         String path = buildPath(key, group);
-         return (String) getInternalProperty(path);
+     public String getRule(String key, String group, long timeout) throws IllegalStateException {
+         return (String) getInternalProperty(getPathKey(group, key));
      }
  
-     /**
-      * For zookeeper, {@link #getConfig(String, String, long)} and {@link #getConfigs(String, String, long)} have the same meaning.
-      *
-      * @param key
-      * @param group
-      * @param timeout
-      * @return
-      * @throws IllegalStateException
-      */
      @Override
-     public String getConfigs(String key, String group, long timeout) throws IllegalStateException {
-         return getConfig(key, group, timeout);
+     public String getProperties(String key, String group, long timeout) throws IllegalStateException {
+         // use global group 'dubbo' if no group specified
+         if (StringUtils.isEmpty(group)) {
+             group = DEFAULT_GROUP;
+         }
+         return (String) getInternalProperty(getPathKey(group, key));
      }
  
 +    @Override
 +    public boolean publishConfig(String key, String group, String content) {
 +        String path = buildPath(key, group);
 +        zkClient.create(path, content, true);
 +        return true;
 +    }
 +
 +    @Override
 +    public SortedSet<String> getConfigKeys(String group) {
 +        String path = buildPath(group);
 +        List<String> nodes = zkClient.getChildren(path);
 +        return isEmpty(nodes) ? emptySortedSet() : unmodifiableSortedSet(new TreeSet<>(nodes));
 +    }
 +
+     private String getPathKey(String group, String key) {
+         return rootPath + PATH_SEPARATOR + group + PATH_SEPARATOR + key;
+     }
++
 +    /**
 +     * Build the config node path by the specified <code>key</code> and <code>group</code>
 +     *
 +     * @param key   the key to represent a configuration
 +     * @param group the group where the key belongs to
 +     * @return
 +     */
 +    protected String buildPath(String key, String group) {
 +        String path = null;
 +        /**
 +         * when group is not null, we are getting startup configs from Config Center, for example:
 +         * group=dubbo, key=dubbo.properties
 +         */
 +        if (StringUtils.isNotEmpty(group)) {
 +            path = group + "/" + key;
 +        }
 +        /**
 +         * when group is null, we are fetching governance rules, for example:
 +         * 1. key=org.apache.dubbo.DemoService.configurators
 +         * 2. key = org.apache.dubbo.DemoService.condition-router
 +         */
 +        else {
 +            int i = key.lastIndexOf(".");
 +            path = key.substring(0, i) + "/" + key.substring(i + 1);
 +        }
 +        return buildPath(path);
 +    }
 +
 +    protected String buildPath(String relativePath) {
 +        String path = rootPath + "/" + relativePath;
 +        return path;
 +    }
 +
  }
diff --cc dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/model/MethodDefinition.java
index 3635621,01be977..932af2b
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/model/MethodDefinition.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/definition/model/MethodDefinition.java
@@@ -16,10 -16,7 +16,9 @@@
   */
  package org.apache.dubbo.metadata.definition.model;
  
 +import java.io.Serializable;
 +import java.util.ArrayList;
  import java.util.Arrays;
- import java.util.List;
  import java.util.Objects;
  
  /**
diff --cc dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java
index 7ffa2a9,6c79a67..1e70a1d
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java
@@@ -68,11 -67,7 +68,11 @@@ public class MetadataIdentifier 
      }
  
      public String getIdentifierKey() {
 -        return serviceInterface + SEPARATOR + (version == null ? "" : version) + SEPARATOR + (group == null ? "" : group) + SEPARATOR + side + SEPARATOR + application;
 +        return serviceInterface
-                 + (version == null ? "" : (SEPARATOR + version))
-                 + (group == null ? "" : (SEPARATOR + version))
-                 + (side == null ? "" : (SEPARATOR + side))
-                 + (getApplication() == null ? "" : (SEPARATOR + getApplication()));
++                + SEPARATOR + (version == null ? "" : version)
++                + SEPARATOR + (group == null ? "" : group)
++                + SEPARATOR + (side == null ? "" : side)
++                + SEPARATOR + application;
      }
  
      private String getFilePathKey() {
diff --cc dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifierTest.java
index c85ee48,3a54e72..c104c76
--- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifierTest.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifierTest.java
@@@ -16,8 -16,7 +16,9 @@@
   */
  package org.apache.dubbo.metadata.identifier;
  
 -import org.apache.dubbo.metadata.identifier.MetadataIdentifier.KeyTypeEnum;
 +import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
++import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier.KeyTypeEnum;
 +
  import org.junit.jupiter.api.Assertions;
  import org.junit.jupiter.api.Test;
  
diff --cc dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
index 846bc74,b12e4f0..1f3fc1a
--- a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
+++ b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java
@@@ -21,24 -24,20 +21,25 @@@ 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.metadata.identifier.MetadataIdentifier;
 -import org.apache.dubbo.metadata.support.AbstractMetadataReport;
 +import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
 +import org.apache.dubbo.metadata.report.support.AbstractMetadataReport;
  import org.apache.dubbo.rpc.RpcException;
  
 +import com.alibaba.nacos.api.NacosFactory;
 +import com.alibaba.nacos.api.config.ConfigService;
 +import com.alibaba.nacos.api.exception.NacosException;
 +
 +import java.util.List;
  import java.util.Properties;
  
 -import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
 -import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
  import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
 +import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
  import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
  import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
 -import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
 +import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
 +import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
  import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME;
+ import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
  import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;
  
  /**
@@@ -113,34 -121,9 +123,34 @@@ public class NacosMetadataReport extend
          this.storeMetadata(consumerMetadataIdentifier, value);
      }
  
 +    @Override
 +    protected void doSaveMetadata(URL url) {
 +        throw new UnsupportedOperationException("This extension does not support working as a remote metadata center.");
 +    }
 +
 +    @Override
 +    protected void doRemoveMetadata(URL url) {
 +        throw new UnsupportedOperationException("This extension does not support working as a remote metadata center.");
 +    }
 +
 +    @Override
 +    protected List<String> doGetExportedURLs() {
 +        throw new UnsupportedOperationException("This extension does not support working as a remote metadata center.");
 +    }
 +
 +    @Override
 +    protected List<String> doGetSubscribedURLs() {
 +        throw new UnsupportedOperationException("This extension does not support working as a remote metadata center.");
 +    }
 +
 +    @Override
 +    public String getServiceDefinition(MetadataIdentifier consumerMetadataIdentifier) {
 +        throw new UnsupportedOperationException("This extension does not support working as a remote metadata center.");
 +    }
 +
      private void storeMetadata(MetadataIdentifier identifier, String value) {
          try {
-             boolean publishResult = configService.publishConfig(identifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), identifier.getGroup(), value);
+             boolean publishResult = configService.publishConfig(identifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), group, value);
              if (!publishResult) {
                  throw new RuntimeException("publish nacos metadata failed");
              }
diff --cc dubbo-metadata/pom.xml
index 2c8bb6b,cbc11f5..9f09ca5
--- a/dubbo-metadata/pom.xml
+++ b/dubbo-metadata/pom.xml
@@@ -25,12 -22,14 +25,14 @@@
      </parent>
      <modelVersion>4.0.0</modelVersion>
  
 -    <artifactId>dubbo-metadata-report</artifactId>
 +    <artifactId>dubbo-metadata</artifactId>
      <packaging>pom</packaging>
      <modules>
 -        <module>dubbo-metadata-report-api</module>
 +        <module>dubbo-metadata-api</module>
          <module>dubbo-metadata-report-zookeeper</module>
          <module>dubbo-metadata-report-redis</module>
+         <module>dubbo-metadata-definition</module>
+         <module>dubbo-metadata-definition-protobuf</module>
          <module>dubbo-metadata-report-consul</module>
          <module>dubbo-metadata-report-etcd</module>
          <module>dubbo-metadata-report-nacos</module>