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/06/17 03:13:05 UTC

[dubbo] branch cloud-native updated: Introduce new Service Discovery model (#4223)

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


The following commit(s) were added to refs/heads/cloud-native by this push:
     new 5fb8dc0  Introduce new Service Discovery model (#4223)
5fb8dc0 is described below

commit 5fb8dc07a85faf7c31bd8d2cf84c2d598784d1e9
Author: Mercy Ma <me...@gmail.com>
AuthorDate: Mon Jun 17 11:12:47 2019 +0800

    Introduce new Service Discovery model (#4223)
---
 dubbo-all/pom.xml                                  |   34 +
 dubbo-bootstrap/pom.xml                            |   94 +
 .../apache/dubbo/bootstrap/AbstractSettings.java   |   29 +-
 .../dubbo/bootstrap/ApplicationSettings.java       |  127 ++
 .../org/apache/dubbo/bootstrap/DubboBootstrap.java |  644 ++++++
 .../apache/dubbo/bootstrap/ProtocolSettings.java   |  215 ++
 .../apache/dubbo/bootstrap/ReferenceSettings.java  |  334 +++
 .../apache/dubbo/bootstrap/RegistrySettings.java   |  164 ++
 .../apache/dubbo/bootstrap/ServiceSettings.java    |  384 ++++
 .../java/org/apache/dubbo/bootstrap/Settings.java  |   31 +-
 .../apache/dubbo/bootstrap/DubboBootstrapTest.java |   96 +
 .../bootstrap/DubboServiceConsumerBootstrap.java   |   58 +
 .../bootstrap/DubboServiceProviderBootstrap.java   |   52 +
 .../org/apache/dubbo/bootstrap/EchoService.java    |   24 +-
 .../apache/dubbo/bootstrap/EchoServiceImpl.java    |   31 +-
 .../src/test/resources/log4j.properties            |    7 +
 .../cluster/router/condition/ConditionRouter.java  |   10 +-
 .../dubbo/rpc/cluster/support/ClusterUtils.java    |    2 +-
 .../rpc/cluster/support/ClusterUtilsTest.java      |    2 +-
 .../src/main/java/org/apache/dubbo/common/URL.java |   58 +-
 .../dubbo/common/constants/RegistryConstants.java  |   34 +
 .../dubbo/common/function/ThrowableConsumer.java   |   66 +
 .../dubbo/common/function/ThrowableFunction.java   |   71 +
 .../org/apache/dubbo/common/utils/DefaultPage.java |   82 +
 .../org/apache/dubbo/common/utils/NetUtils.java    |    2 +-
 .../java/org/apache/dubbo/common/utils/Page.java   |   87 +
 .../apache/dubbo/common/utils/ReflectUtils.java    | 2307 ++++++++++----------
 .../org/apache/dubbo/common/utils/UrlUtils.java    |   10 +-
 .../apache/dubbo/common/utils/DefaultPageTest.java |   30 +-
 .../org/apache/dubbo/filter/LegacyInvocation.java  |    4 +-
 dubbo-config/dubbo-config-api/pom.xml              |   48 +-
 .../dubbo/config/AbstractInterfaceConfig.java      |   20 +-
 .../org/apache/dubbo/config/DubboShutdownHook.java |    8 +-
 .../org/apache/dubbo/config/ProtocolConfig.java    |    4 +-
 .../org/apache/dubbo/config/ReferenceConfig.java   | 1355 ++++++------
 .../org/apache/dubbo/config/RegistryConfig.java    |    4 +-
 .../org/apache/dubbo/config/ServiceConfig.java     | 2135 +++++++++---------
 .../dubbo/config/builders/AbstractBuilder.java     |   13 +-
 .../dubbo/config/builders/ProtocolBuilder.java     |    8 +-
 .../dubbo/config/builders/ReferenceBuilder.java    |    4 +
 .../dubbo/config/builders/RegistryBuilder.java     |    8 +-
 .../dubbo/config/builders/ServiceBuilder.java      |   10 +-
 .../config/event/DubboServiceDestroyedEvent.java}  |   27 +-
 .../event/ReferenceConfigDestroyedEvent.java}      |   30 +-
 .../event/ReferenceConfigInitializedEvent.java}    |   45 +-
 .../config/event/ServiceConfigExportedEvent.java}  |   29 +-
 .../event/ServiceConfigUnexportedEvent.java}       |   29 +-
 .../event/listener/LoggingEventListener.java       |   51 +
 .../event/listener/ServiceNameMappingListener.java |   55 +
 .../ConfigurableMetadataServiceExporter.java       |  131 ++
 .../metadata/ServiceInstancePortCustomizer.java    |   53 +
 .../services/org.apache.dubbo.event.EventListener  |    2 +
 ...dubbo.registry.client.ServiceInstanceCustomizer |    1 +
 .../dubbo/config/DubboConsumerBootstrap.java       |   63 +
 .../dubbo/config/DubboProviderBootstrap.java       |   84 +
 .../apache/dubbo/config/ReferenceConfigTest.java   |   48 +-
 .../apache/dubbo/config/RegistryConfigTest.java    |    2 +-
 .../org/apache/dubbo/config/ServiceConfigTest.java |   47 +-
 .../org/apache/dubbo/config/api/DemoService.java   |    3 +
 .../listener/ServiceNameMappingListenerTest.java   |   63 +
 .../ConfigurableMetadataServiceExporterTest.java   |   88 +
 .../config/provider/impl/DemoServiceImpl.java      |   17 +-
 .../config/spring/SimpleRegistryExporter.java      |    4 +-
 .../dubbo/configcenter/DynamicConfiguration.java   |   72 +-
 .../support/nop/NopDynamicConfiguration.java       |   21 +-
 .../support/nop/NopDynamicConfigurationTest.java   |   70 +
 .../zookeeper/ZookeeperDynamicConfiguration.java   |   73 +-
 .../ZookeeperDynamicConfigurationTest.java         |   39 +
 dubbo-dependencies-bom/pom.xml                     |   13 +-
 .../dubbo-dependencies-zookeeper/pom.xml           |    2 +-
 .../pom.xml                                        |   37 +-
 .../dubbo/event/AbstractEventDispatcher.java       |  155 ++
 .../apache/dubbo/event/DirectEventDispatcher.java  |   27 +-
 .../main/java/org/apache/dubbo/event/Event.java    |   54 +-
 .../org/apache/dubbo/event/EventDispatcher.java    |   66 +
 .../java/org/apache/dubbo/event/EventListener.java |  124 ++
 .../java/org/apache/dubbo/event/GenericEvent.java  |   29 +-
 .../apache/dubbo/event/GenericEventListener.java   |  130 ++
 .../java/org/apache/dubbo/event/Listenable.java    |  131 ++
 .../dubbo/event/ParallelEventDispatcher.java       |   27 +-
 .../org.apache.dubbo.event.EventDispatcher         |    2 +
 .../apache/dubbo/event/AbstractEventListener.java  |   29 +-
 .../dubbo/event/DirectEventDispatcherTest.java     |  153 ++
 .../java/org/apache/dubbo/event/EchoEvent.java     |   26 +-
 .../org/apache/dubbo/event/EchoEventListener.java  |   25 +-
 .../org/apache/dubbo/event/EchoEventListener2.java |   61 +
 .../apache/dubbo/event/EventDispatcherTest.java    |   44 +-
 .../org/apache/dubbo/event/EventListenerTest.java  |   39 +-
 .../dubbo/event/GenericEventListenerTest.java      |   77 +
 .../org/apache/dubbo/event/GenericEventTest.java   |   28 +-
 .../dubbo/event/ParallelEventDispatcherTest.java   |   59 +
 .../services/org.apache.dubbo.event.EventListener  |    1 +
 .../identifier/MetadataIdentifierTest.java         |    1 -
 .../metadata/store/redis/RedisMetadataReport.java  |    2 +-
 .../pom.xml                                        |   40 +-
 .../DynamicConfigurationServiceNameMapping.java    |  103 +
 .../metadata/InMemoryLocalMetadataService.java     |  192 ++
 .../dubbo/metadata/LocalMetadataService.java       |   88 +
 .../org/apache/dubbo/metadata/MetadataService.java |  151 ++
 .../dubbo/metadata/MetadataServiceExporter.java    |   39 +-
 .../apache/dubbo/metadata/ServiceNameMapping.java  |   64 +
 .../org.apache.dubbo.metadata.LocalMetadataService |    1 +
 .../org.apache.dubbo.metadata.ServiceNameMapping   |    1 +
 ...DynamicConfigurationServiceNameMappingTest.java |  114 +
 .../metadata/InMemoryLocalMetadataServiceTest.java |  140 ++
 .../dubbo/metadata/LocalMetadataServiceTest.java   |   27 +-
 .../dubbo/monitor/support/MonitorFilter.java       |    2 +-
 .../dubbo/monitor/dubbo/DubboMonitorFactory.java   |    2 +-
 dubbo-registry/dubbo-registry-api/pom.xml          |   15 +-
 .../registry/client/DefaultServiceInstance.java    |  142 ++
 .../client/EventPublishingServiceDiscovery.java    |  293 +++
 .../EventPublishingServiceDiscoveryFactory.java    |   47 +
 .../dubbo/registry/client/ServiceDiscovery.java    |  201 ++
 .../registry/client/ServiceDiscoveryFactory.java   |   49 +
 .../dubbo/registry/client/ServiceInstance.java     |   94 +
 .../registry/client/ServiceInstanceCustomizer.java |   49 +-
 .../client/ServiceInstanceMetadataCustomizer.java  |   73 +
 .../client/event/ServiceDiscoveryStartedEvent.java |   49 +
 .../event/ServiceDiscoveryStartingEvent.java       |   48 +
 .../client/event/ServiceDiscoveryStoppedEvent.java |   48 +
 .../event/ServiceDiscoveryStoppingEvent.java       |   48 +
 .../client/event/ServiceInstanceEvent.java         |   48 +-
 .../event/ServiceInstancePreRegisteredEvent.java   |   27 +-
 .../event/ServiceInstancePreUnregisteredEvent.java |   27 +-
 .../event/ServiceInstanceRegisteredEvent.java      |   27 +-
 .../event/ServiceInstanceUnregisteredEvent.java    |   28 +-
 .../client/event/ServiceInstancesChangedEvent.java |   64 +
 .../CustomizableServiceInstanceListener.java       |   54 +
 .../event/listener/LoggingEventListener.java       |   85 +
 .../listener/ServiceInstancesChangedListener.java  |   33 +-
 .../DefaultMetadataServiceProxyFactory.java        |   31 +-
 ...ExportedServicesRevisionMetadataCustomizer.java |   69 +
 .../client/metadata/MetadataServiceProxy.java      |  114 +
 .../metadata/MetadataServiceProxyFactory.java      |   51 +
 .../client/metadata/MetadataServiceURLBuilder.java |   81 +
 ...MetadataServiceURLParamsMetadataCustomizer.java |   60 +
 .../metadata/ServiceInstanceMetadataUtils.java     |  172 ++
 .../apache/dubbo/registry/client/package-info.java |   24 +-
 .../selector/RandomServiceInstanceSelector.java    |   48 +-
 .../client/selector/ServiceInstanceSelector.java   |   43 +
 .../registry/integration/RegistryDirectory.java    |   10 +-
 .../registry/integration/RegistryProtocol.java     |   36 +-
 .../registry/support/AbstractRegistryFactory.java  |    9 +-
 .../registry/support/ServiceOrientedRegistry.java  |  472 ++++
 ...e.dubbo.registry.client.ServiceDiscoveryFactory |    1 +
 ...try.client.metadata.MetadataServiceProxyFactory |    1 +
 ...egistry.client.selector.ServiceInstanceSelector |    1 +
 .../services/org.apache.dubbo.event.EventListener  |    2 +
 ...dubbo.registry.client.ServiceInstanceCustomizer |    2 +
 .../client/DefaultServiceInstanceTest.java         |   60 +
 .../EventPublishingServiceDiscoveryTest.java       |  164 ++
 .../registry/client/InMemoryServiceDiscovery.java  |  110 +
 .../client/InMemoryServiceDiscoveryFactory.java    |   28 +-
 .../client/ServiceDiscoveryFactoryTest.java        |   55 +
 .../registry/client/ServiceDiscoveryTest.java      |  264 +++
 .../metadata/ServiceInstanceMetadataUtilsTest.java |   74 +
 .../support/ServiceOrientedRegistryTest.java       |  173 ++
 ...e.dubbo.registry.client.ServiceDiscoveryFactory |    1 +
 .../dubbo/registry/dubbo/DubboRegistryFactory.java |   10 +-
 .../registry/dubbo/RegistryDirectoryTest.java      |   14 +-
 .../registry/dubbo/SimpleRegistryExporter.java     |    4 +-
 .../apache/dubbo/registry/nacos/NacosRegistry.java |    2 +-
 .../dubbo/registry/nacos/NacosRegistryFactory.java |   70 +-
 .../registry/nacos/NacosServiceDiscovery.java      |  136 ++
 .../nacos/NacosServiceDiscoveryFactory.java        |   34 +-
 .../NacosNamingServiceUtils.java}                  |   88 +-
 ...e.dubbo.registry.client.ServiceDiscoveryFactory |    1 +
 dubbo-registry/dubbo-registry-zookeeper/pom.xml    |    4 +
 .../registry/zookeeper/ZookeeperInstance.java      |   77 +
 .../zookeeper/ZookeeperServiceDiscovery.java       |  159 ++
 .../ZookeeperServiceDiscoveryChangeWatcher.java    |   68 +
 .../ZookeeperServiceDiscoveryFactory.java          |   36 +-
 .../zookeeper/util/CuratorFrameworkParams.java     |  102 +
 .../zookeeper/util/CuratorFrameworkUtils.java      |  122 ++
 ...e.dubbo.registry.client.ServiceDiscoveryFactory |    1 +
 ...e.dubbo.registry.client.ServiceDiscoveryFactory |    1 +
 .../registry/zookeeper/ZookeeperRegistryTest.java  |    2 +-
 .../zookeeper/ZookeeperServiceDiscoveryTest.java   |  206 ++
 .../support/header/HeaderExchangeClient.java       |    4 +-
 .../exchange/support/header/HeartBeatTaskTest.java |    1 +
 .../remoting/transport/netty4/NettyClient.java     |    4 +-
 .../transport/netty4/ClientReconnectTest.java      |    1 +
 .../org/apache/dubbo/rpc/filter/ContextFilter.java |    2 +-
 .../org/apache/dubbo/rpc/support/MockInvoker.java  |    6 +-
 .../apache/dubbo/rpc/filter/GenericFilterTest.java |    6 +-
 .../dubbo/rpc/filter/GenericImplFilterTest.java    |    5 +-
 .../rpc/protocol/dubbo/CallbackServiceCodec.java   |    6 +-
 .../protocol/dubbo/DecodeableRpcInvocation.java    |    2 +-
 .../dubbo/rpc/protocol/dubbo/DubboCodec.java       |    2 +-
 .../dubbo/rpc/protocol/dubbo/DubboProtocol.java    |   20 +-
 .../dubbo/ReferenceCountExchangeClientTest.java    |    2 +-
 .../dubbo/rpc/protocol/http/HttpProtocol.java      |    2 +-
 dubbo-rpc/dubbo-rpc-xml/README.md                  |    2 +-
 .../xml/rpc/protocol/xmlrpc/XmlRpcProtocol.java    |   18 +-
 pom.xml                                            |    5 +-
 195 files changed, 13322 insertions(+), 3767 deletions(-)

diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml
index d8c8949..eaf1772 100644
--- a/dubbo-all/pom.xml
+++ b/dubbo-all/pom.xml
@@ -507,6 +507,23 @@
             <optional>true</optional>
         </dependency>
 
+        <!-- 2.7.3 new modules -->
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-event</artifactId>
+            <version>${project.version}</version>
+            <scope>compile</scope>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-metadata</artifactId>
+            <version>${project.version}</version>
+            <scope>compile</scope>
+            <optional>true</optional>
+        </dependency>
+
         <!-- Transitive dependencies -->
         <dependency>
             <groupId>org.springframework</groupId>
@@ -639,6 +656,10 @@
                                     <include>org.apache.dubbo:dubbo-metadata-report-nacos</include>
                                     <include>org.apache.dubbo:dubbo-serialization-native-hession</include>
                                     <include>org.apache.dubbo:dubbo-rpc-native-thrift</include>
+
+                                    <!-- 2.7.3 new modules -->
+                                    <include>org.apache.dubbo:dubbo-event</include>
+                                    <include>org.apache.dubbo:dubbo-metadata</include>
                                 </includes>
                             </artifactSet>
                             <transformers>
@@ -764,6 +785,19 @@
                                     <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory
                                     </resource>
                                 </transformer>
+                                <!-- @since 2.7.3 -->
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+                                    <resource>META-INF/dubbo/internal/org.apache.dubbo.event.EventDispatcher
+                                    </resource>
+                                </transformer>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+                                    <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter
+                                    </resource>
+                                </transformer>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+                                    <resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.LocalMetadataService
+                                    </resource>
+                                </transformer>
                             </transformers>
                             <filters>
                                 <filter>
diff --git a/dubbo-bootstrap/pom.xml b/dubbo-bootstrap/pom.xml
new file mode 100644
index 0000000..ef3cad3
--- /dev/null
+++ b/dubbo-bootstrap/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-parent</artifactId>
+        <version>${revision}</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>dubbo-bootstrap</artifactId>
+    <packaging>jar</packaging>
+
+    <name>dubbo-bootstrap</name>
+    <description>The bootstrap module of Dubbo project</description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-config-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+
+        <!-- Test dependencies -->
+
+        <!-- Zookeeper dependencies for testing -->
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-registry-zookeeper</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-configcenter-zookeeper</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Nacos dependencies for testing -->
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-registry-nacos</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-configcenter-nacos</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.nacos</groupId>
+            <artifactId>nacos-client</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-rpc-dubbo</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-remoting-netty4</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-serialization-hessian2</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java
similarity index 67%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java
index c5bc722..6bb9c97 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java
@@ -14,24 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.api;
-
-import java.util.List;
-
+package org.apache.dubbo.bootstrap;
 
 /**
- * DemoService
+ * Abstract {@link Settings}
+ *
+ * @since 2.7.3
  */
-public interface DemoService {
-
-    String sayName(String name);
-
-    Box getBox();
-
-    void throwDemoException() throws DemoException;
+public class AbstractSettings implements Settings {
 
-    List<User> getUsers(List<User> users);
+    private final DubboBootstrap dubboBootstrap;
 
-    int echo(int i);
+    public AbstractSettings(DubboBootstrap dubboBootstrap) {
+        this.dubboBootstrap = dubboBootstrap;
+    }
 
-}
\ No newline at end of file
+    @Override
+    public DubboBootstrap next() {
+        return dubboBootstrap;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java
new file mode 100644
index 0000000..a9bc9c9
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java
@@ -0,0 +1,127 @@
+/*
+ * 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.bootstrap;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.builders.ApplicationBuilder;
+
+import java.util.Map;
+
+/**
+ * {@link ApplicationConfig Application} settings
+ *
+ * @since 2.7.3
+ */
+public class ApplicationSettings extends AbstractSettings {
+
+    private final ApplicationBuilder builder;
+
+    public ApplicationSettings(ApplicationBuilder builder, DubboBootstrap dubboBootstrap) {
+        super(dubboBootstrap);
+        this.builder = builder;
+    }
+
+    public ApplicationSettings version(String version) {
+        builder.version(version);
+        return this;
+    }
+
+    public ApplicationSettings owner(String owner) {
+        builder.owner(owner);
+        return this;
+    }
+
+    public ApplicationSettings organization(String organization) {
+        builder.organization(organization);
+        return this;
+    }
+
+    public ApplicationSettings architecture(String architecture) {
+        builder.architecture(architecture);
+        return this;
+    }
+
+    public ApplicationSettings environment(String environment) {
+        builder.environment(environment);
+        return this;
+    }
+
+    public ApplicationSettings compiler(String compiler) {
+        builder.compiler(compiler);
+        return this;
+    }
+
+    public ApplicationSettings logger(String logger) {
+        builder.logger(logger);
+        return this;
+    }
+
+    public ApplicationSettings monitor(MonitorConfig monitor) {
+        builder.monitor(monitor);
+        return this;
+    }
+
+    public ApplicationSettings monitor(String monitor) {
+        builder.monitor(monitor);
+        return this;
+    }
+
+    public ApplicationSettings isDefault(Boolean isDefault) {
+        builder.isDefault(isDefault);
+        return this;
+    }
+
+    public ApplicationSettings dumpDirectory(String dumpDirectory) {
+        builder.dumpDirectory(dumpDirectory);
+        return this;
+    }
+
+    public ApplicationSettings qosEnable(Boolean qosEnable) {
+        builder.qosEnable(qosEnable);
+        return this;
+    }
+
+    public ApplicationSettings qosPort(Integer qosPort) {
+        builder.qosPort(qosPort);
+        return this;
+    }
+
+    public ApplicationSettings qosAcceptForeignIp(Boolean qosAcceptForeignIp) {
+        builder.qosAcceptForeignIp(qosAcceptForeignIp);
+        return this;
+    }
+
+    public ApplicationSettings shutwait(String shutwait) {
+        builder.shutwait(shutwait);
+        return this;
+    }
+
+    public ApplicationSettings appendParameter(String key, String value) {
+        builder.appendParameter(key, value);
+        return this;
+    }
+
+    public ApplicationSettings appendParameters(Map<String, String> appendParameters) {
+        builder.appendParameters(appendParameters);
+        return this;
+    }
+
+    ApplicationConfig build() {
+        return builder.build();
+    }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java
new file mode 100644
index 0000000..c6c2606
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java
@@ -0,0 +1,644 @@
+/*
+ * 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.bootstrap;
+
+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.CollectionUtils;
+import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.config.AbstractInterfaceConfig;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.builders.AbstractBuilder;
+import org.apache.dubbo.config.builders.ApplicationBuilder;
+import org.apache.dubbo.config.builders.ProtocolBuilder;
+import org.apache.dubbo.config.builders.ReferenceBuilder;
+import org.apache.dubbo.config.builders.RegistryBuilder;
+import org.apache.dubbo.config.builders.ServiceBuilder;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter;
+import org.apache.dubbo.event.EventDispatcher;
+import org.apache.dubbo.event.EventListener;
+import org.apache.dubbo.metadata.MetadataServiceExporter;
+import org.apache.dubbo.registry.client.DefaultServiceInstance;
+import org.apache.dubbo.registry.client.ServiceDiscovery;
+import org.apache.dubbo.registry.client.ServiceInstance;
+import org.apache.dubbo.registry.support.ServiceOrientedRegistry;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+import static java.util.Collections.emptyMap;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
+import static org.apache.dubbo.common.utils.StringUtils.isBlank;
+import static org.apache.dubbo.common.utils.StringUtils.split;
+import static org.apache.dubbo.common.utils.StringUtils.trim;
+import static org.apache.dubbo.registry.support.AbstractRegistryFactory.getRegistries;
+
+/**
+ * The bootstrap class of Dubbo
+ *
+ * @since 2.7.3
+ */
+public class DubboBootstrap {
+
+    public static final String DEFAULT_REGISTRY_ID = "REGISTRY#DEFAULT";
+
+    public static final String DEFAULT_PROTOCOL_ID = "PROTOCOL#DEFAULT";
+
+    public static final String DEFAULT_SERVICE_ID = "SERVICE#DEFAULT";
+
+    public static final String DEFAULT_REFERENCE_ID = "REFERENCE#DEFAULT";
+
+    private static final String NAME = DubboBootstrap.class.getSimpleName();
+
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+
+    private final MetadataServiceExporter metadataServiceExporter = new ConfigurableMetadataServiceExporter();
+
+    private final AtomicBoolean awaited = new AtomicBoolean(false);
+
+    private final Lock lock = new ReentrantLock();
+
+    private final Condition condition = lock.newCondition();
+
+    private final ExecutorService executorService = newSingleThreadExecutor();
+
+    private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
+
+    /**
+     * Is provider or not
+     */
+    private boolean isProvider;
+
+    private boolean initialized = false;
+
+    private boolean started = false;
+
+    /**
+     * Only Provider Register
+     */
+    private boolean onlyRegisterProvider = false;
+
+    private ServiceInstance serviceInstance;
+
+    private ApplicationBuilder applicationBuilder;
+
+    private Map<String, RegistryBuilder> registryBuilders = new HashMap<>();
+
+    private Map<String, ProtocolBuilder> protocolBuilders = new HashMap<>();
+
+    private Map<String, ServiceBuilder<?>> serviceBuilders = new HashMap<>();
+
+    private Map<String, ReferenceBuilder<?>> referenceBuilders = new HashMap<>();
+
+    /**
+     * The global {@link ApplicationConfig}
+     */
+    private ApplicationConfig applicationConfig;
+
+    /**
+     * the global {@link RegistryConfig registries}
+     */
+    private Map<String, RegistryConfig> registryConfigs = emptyMap();
+
+    /**
+     * the global {@link RegistryConfig registries}
+     */
+    private Map<String, ProtocolConfig> protocolConfigs = emptyMap();
+
+    /**
+     * the global {@link ServiceConfig services}
+     */
+    private Map<String, ServiceConfig<?>> serviceConfigs = emptyMap();
+
+    /**
+     * the global {@link ReferenceConfig references}
+     */
+    private Map<String, ReferenceConfig<?>> referenceConfigs = new HashMap<>();
+
+    public ApplicationSettings application(String name) {
+        return new ApplicationSettings(initApplicationBuilder(name), this);
+    }
+
+    public RegistrySettings registry() {
+        return registry(DEFAULT_REGISTRY_ID);
+    }
+
+    public RegistrySettings registry(String id) {
+        return new RegistrySettings(initRegistryBuilder(id), this);
+    }
+
+    public ProtocolSettings protocol() {
+        return protocol(DEFAULT_PROTOCOL_ID);
+    }
+
+    public ProtocolSettings protocol(String id) {
+        return new ProtocolSettings(initProtocolBuilder(id), this);
+    }
+
+    public <S> ServiceSettings<S> service(String id) {
+        return new ServiceSettings(initServiceBuilder(id), this);
+    }
+
+    public <S> ReferenceSettings<S> reference(String id) {
+        return new ReferenceSettings<>(initReferenceBuilder(id), this);
+    }
+
+    /**
+     * Set only register provider or not
+     *
+     * @param onlyRegisterProvider if <code>true</code>, only register the provider and reduce the registries' load.
+     * @return {@link DubboBootstrap}
+     */
+    public DubboBootstrap onlyRegisterProvider(boolean onlyRegisterProvider) {
+        this.onlyRegisterProvider = onlyRegisterProvider;
+        return this;
+    }
+
+    public DubboBootstrap application(String name, Consumer<ApplicationBuilder> builder) {
+        initApplicationBuilder(name);
+        builder.accept(applicationBuilder);
+        return this;
+    }
+
+    public DubboBootstrap registry(String id, Consumer<RegistryBuilder> builder) {
+        builder.accept(initRegistryBuilder(id));
+        return this;
+    }
+
+    public DubboBootstrap protocol(String id, Consumer<ProtocolBuilder> builder) {
+        builder.accept(initProtocolBuilder(id));
+        return this;
+    }
+
+    public <S> DubboBootstrap service(String id, Consumer<ServiceBuilder<S>> builder) {
+        builder.accept(initServiceBuilder(id));
+        return this;
+    }
+
+    public <S> DubboBootstrap reference(String id, Consumer<ReferenceBuilder<S>> builder) {
+        builder.accept(initReferenceBuilder(id));
+        return this;
+    }
+
+    /**
+     * Initialize
+     */
+    public void init() {
+
+        if (isInitialized()) {
+            return;
+        }
+
+        initApplicationConfig();
+
+        initRegistryConfigs();
+
+        initProtocolConfigs();
+
+        initServiceConfigs();
+
+        initReferenceConfigs();
+
+        clearBuilders();
+
+        initialized = true;
+
+        if (logger.isInfoEnabled()) {
+            logger.info(NAME + " has been initialized!");
+        }
+    }
+
+    /**
+     * Get the {@link ServiceConfig} by specified id
+     *
+     * @param id  The {@link ServiceConfig#getId() id} of {@link ServiceConfig}
+     * @param <S> the type of service interface
+     * @return <code>null</code> if not found
+     */
+    public <S> ServiceConfig<S> serviceConfig(String id) {
+        return (ServiceConfig<S>) serviceConfigs.get(id);
+    }
+
+    /**
+     * Get the {@link ReferenceConfig} by specified id
+     *
+     * @param id  The {@link ReferenceConfig#getId() id} of {@link ReferenceConfig}
+     * @param <S> the type of service interface
+     * @return <code>null</code> if not found
+     */
+    public <S> ReferenceConfig<S> referenceConfig(String id) {
+        return (ReferenceConfig<S>) referenceConfigs.get(id);
+    }
+
+    private List<ServiceDiscovery> getServiceDiscoveries() {
+        return getRegistries()
+                .stream()
+                .filter(registry -> ServiceOrientedRegistry.class.isInstance(registry))
+                .map(registry -> ServiceOrientedRegistry.class.cast(registry))
+                .map(ServiceOrientedRegistry::getServiceDiscovery)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Start the bootstrap
+     */
+    public DubboBootstrap start() {
+
+        if (!isStarted()) {
+            if (!isInitialized()) {
+                init();
+            }
+
+            exportServices();
+
+            // Not only provider register and some services are exported
+            if (!onlyRegisterProvider && !serviceConfigs.isEmpty()) {
+                /**
+                 * export {@link MetadataService}
+                 */
+                List<URL> exportedURLs = exportMetadataService(applicationConfig, registryConfigs, protocolConfigs);
+
+                /**
+                 * Register the local {@link ServiceInstance}
+                 */
+                registerServiceInstance(exportedURLs);
+            }
+
+            started = true;
+
+            if (logger.isInfoEnabled()) {
+                logger.info(NAME + " is starting...");
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Block current thread to be await.
+     *
+     * @return {@link DubboBootstrap}
+     */
+    public DubboBootstrap await() {
+        // has been waited, return immediately
+        if (!awaited.get()) {
+            if (!executorService.isShutdown()) {
+                executorService.execute(() -> executeMutually(() -> {
+                    while (!awaited.get()) {
+                        if (logger.isInfoEnabled()) {
+                            logger.info(NAME + " is awaiting...");
+                        }
+                        try {
+                            condition.await();
+                        } catch (InterruptedException e) {
+                            Thread.currentThread().interrupt();
+                        }
+                    }
+                }));
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Stop the bootstrap
+     */
+    public void stop() {
+
+        if (!isInitialized() || !isStarted()) {
+            return;
+        }
+
+        unregisterServiceInstance();
+
+        destroy();
+
+        clear();
+
+        release();
+
+        shutdown();
+    }
+
+    public boolean isInitialized() {
+        return initialized;
+    }
+
+    public boolean isStarted() {
+        return started;
+    }
+
+    private ApplicationBuilder initApplicationBuilder(String name) {
+        applicationBuilder = new ApplicationBuilder().name(name);
+        return applicationBuilder;
+    }
+
+    private RegistryBuilder createRegistryBuilder(String id) {
+        return new RegistryBuilder().id(id);
+    }
+
+    private ProtocolBuilder createProtocolBuilder(String id) {
+        return new ProtocolBuilder().id(id);
+    }
+
+    private ServiceBuilder createServiceBuilder(String id) {
+        return new ServiceBuilder().id(id);
+    }
+
+    private ReferenceBuilder createReferenceBuilder(String id) {
+        return new ReferenceBuilder().id(id);
+    }
+
+    private RegistryBuilder initRegistryBuilder(String id) {
+        return registryBuilders.computeIfAbsent(id, this::createRegistryBuilder);
+    }
+
+    private ProtocolBuilder initProtocolBuilder(String id) {
+        return protocolBuilders.computeIfAbsent(id, this::createProtocolBuilder);
+    }
+
+    private ServiceBuilder initServiceBuilder(String id) {
+        return serviceBuilders.computeIfAbsent(id, this::createServiceBuilder);
+    }
+
+    private ReferenceBuilder initReferenceBuilder(String id) {
+        return referenceBuilders.computeIfAbsent(id, this::createReferenceBuilder);
+    }
+
+    private void initApplicationConfig() {
+        this.applicationConfig = buildApplicationConfig();
+    }
+
+    private void initRegistryConfigs() {
+        this.registryConfigs = buildRegistryConfigs();
+    }
+
+    private void initProtocolConfigs() {
+        this.protocolConfigs = buildProtocolConfigs();
+    }
+
+    private void initReferenceConfigs() {
+        this.referenceConfigs = buildReferenceConfigs();
+        this.referenceConfigs.values().forEach(this::initReferenceConfig);
+    }
+
+    /**
+     * Add an instance of {@link EventListener}
+     *
+     * @param listener {@link EventListener}
+     * @return {@link DubboBootstrap}
+     */
+    public DubboBootstrap addEventListener(EventListener<?> listener) {
+        eventDispatcher.addEventListener(listener);
+        return this;
+    }
+
+    private void initServiceConfigs() {
+        this.serviceConfigs = buildServiceConfigs();
+        this.serviceConfigs.values().forEach(this::initServiceConfig);
+    }
+
+    private List<URL> exportMetadataService(ApplicationConfig applicationConfig,
+                                            Map<String, RegistryConfig> globalRegistryConfigs,
+                                            Map<String, ProtocolConfig> globalProtocolConfigs) {
+        ConfigurableMetadataServiceExporter exporter = new ConfigurableMetadataServiceExporter();
+        exporter.setApplicationConfig(applicationConfig);
+        exporter.setRegistries(globalRegistryConfigs.values());
+        exporter.setProtocols(globalProtocolConfigs.values());
+        return exporter.export();
+    }
+
+    private ApplicationConfig buildApplicationConfig() {
+        return applicationBuilder.build();
+    }
+
+    private Map<String, ProtocolConfig> buildProtocolConfigs() {
+        return buildConfigs(protocolBuilders);
+    }
+
+    private Map<String, RegistryConfig> buildRegistryConfigs() {
+        return buildConfigs(registryBuilders);
+    }
+
+    private Map<String, ServiceConfig<?>> buildServiceConfigs() {
+        return buildConfigs(serviceBuilders);
+    }
+
+    private Map<String, ReferenceConfig<?>> buildReferenceConfigs() {
+        return buildConfigs(referenceBuilders);
+    }
+
+    private void exportServices() {
+        serviceConfigs.values().forEach(this::exportServiceConfig);
+    }
+
+    private void initServiceConfig(ServiceConfig<?> serviceConfig) {
+        initConfig(serviceConfig);
+        initProtocols(serviceConfig);
+    }
+
+    private void initReferenceConfig(ReferenceConfig<?> referenceConfig) {
+        initConfig(referenceConfig);
+    }
+
+    private void initConfig(AbstractInterfaceConfig config) {
+        initApplication(config);
+        initRegistries(config);
+    }
+
+    private void initApplication(AbstractInterfaceConfig config) {
+        if (config.getApplication() == null) {
+            config.setApplication(applicationConfig);
+        }
+    }
+
+    private void initRegistries(AbstractInterfaceConfig config) {
+        List<RegistryConfig> registries = config.getRegistries();
+        if (CollectionUtils.isEmpty(registries)) { // If no registry present
+            registries = new LinkedList<>();
+            String registerIds = config.getRegistryIds();
+            if (!isBlank(registerIds)) {
+                for (String id : split(registerIds, ',')) {
+                    RegistryConfig registryConfig = registryConfigs.get(trim(id));
+                    registries.add(registryConfig);
+                }
+            }
+            if (registries.isEmpty()) { // If empty, add all global registries
+                registries.addAll(registryConfigs.values());
+            }
+
+            config.setRegistries(registries);
+        }
+    }
+
+    private void initProtocols(ServiceConfig<?> serviceConfig) {
+        List<ProtocolConfig> protocols = serviceConfig.getProtocols();
+        if (CollectionUtils.isEmpty(protocols)) { // If no protocols present
+            protocols = new LinkedList<>();
+            String protocolIds = serviceConfig.getProtocolIds();
+            if (!isBlank(protocolIds)) {
+                for (String id : split(protocolIds, ',')) {
+                    ProtocolConfig protocol = protocolConfigs.get(trim(id));
+                    protocols.add(protocol);
+                }
+            }
+            if (protocols.isEmpty()) { // If empty, add all global protocols
+                protocols.addAll(protocolConfigs.values());
+            }
+            serviceConfig.setProtocols(protocols);
+        }
+    }
+
+    private void exportServiceConfig(ServiceConfig<?> serviceConfig) {
+        serviceConfig.export();
+    }
+
+    private void registerServiceInstance(List<URL> exportedURLs) {
+
+        exportedURLs
+                .stream()
+                .findFirst()
+                .ifPresent(url -> {
+                    String serviceName = url.getParameter(APPLICATION_KEY);
+                    String host = url.getHost();
+                    int port = url.getPort();
+
+                    ServiceInstance serviceInstance = initServiceInstance(serviceName, host, port);
+
+                    getServiceDiscoveries().forEach(serviceDiscovery -> serviceDiscovery.register(serviceInstance));
+
+                });
+    }
+
+    private void unregisterServiceInstance() {
+
+        if (serviceInstance != null) {
+            getServiceDiscoveries().forEach(serviceDiscovery -> {
+                serviceDiscovery.unregister(serviceInstance);
+            });
+        }
+
+    }
+
+    private ServiceInstance initServiceInstance(String serviceName, String host, int port) {
+        this.serviceInstance = new DefaultServiceInstance(serviceName, host, port);
+        return this.serviceInstance;
+    }
+
+    private void destroy() {
+
+        destroyProtocolConfigs();
+
+        destroyReferenceConfigs();
+
+    }
+
+    private void destroyProtocolConfigs() {
+        protocolConfigs.values().forEach(ProtocolConfig::destroy);
+        if (logger.isDebugEnabled()) {
+            logger.debug(NAME + "'s all ProtocolConfigs have been destroyed.");
+        }
+    }
+
+    private void destroyReferenceConfigs() {
+        referenceConfigs.values().forEach(ReferenceConfig::destroy);
+        if (logger.isDebugEnabled()) {
+            logger.debug(NAME + "'s all ReferenceConfigs have been destroyed.");
+        }
+    }
+
+    private void clear() {
+
+        clearBuilders();
+
+        clearConfigs();
+
+        ConfigManager.getInstance().clear();
+    }
+
+    private void clearConfigs() {
+        this.applicationConfig = null;
+        this.registryConfigs.clear();
+        this.protocolConfigs.clear();
+        this.serviceConfigs.clear();
+        this.referenceConfigs.clear();
+        if (logger.isDebugEnabled()) {
+            logger.debug(NAME + "'s configs have been clear.");
+        }
+    }
+
+    private void clearBuilders() {
+        this.applicationBuilder = null;
+        this.registryBuilders.clear();
+        this.protocolBuilders.clear();
+        this.serviceBuilders.clear();
+        this.referenceBuilders.clear();
+        if (logger.isDebugEnabled()) {
+            logger.debug(NAME + "'s builders have been clear.");
+        }
+    }
+
+    private void release() {
+        executeMutually(() -> {
+            while (awaited.compareAndSet(false, true)) {
+                if (logger.isInfoEnabled()) {
+                    logger.info(NAME + " is about to shutdown...");
+                }
+                condition.signalAll();
+            }
+        });
+    }
+
+    private void shutdown() {
+        if (!executorService.isShutdown()) {
+            // Shutdown executorService
+            executorService.shutdown();
+        }
+    }
+
+    private void executeMutually(Runnable runnable) {
+        try {
+            lock.lock();
+            runnable.run();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    private static <C extends AbstractConfig, B extends AbstractBuilder> Map<String, C> buildConfigs(Map<String, B> map) {
+        Map<String, C> configs = new HashMap<>();
+        map.entrySet().forEach(entry -> {
+            configs.put(entry.getKey(), (C) entry.getValue().build());
+        });
+        return configs;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java
new file mode 100644
index 0000000..dc0169b
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java
@@ -0,0 +1,215 @@
+/*
+ * 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.bootstrap;
+
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.builders.ProtocolBuilder;
+
+import java.util.Map;
+
+/**
+ * The settings of {@link ProtocolConfig protcol}
+ *
+ * @see ProtocolBuilder
+ * @since 2.7.3
+ */
+public class ProtocolSettings extends AbstractSettings {
+
+    private final ProtocolBuilder builder;
+
+    public ProtocolSettings(ProtocolBuilder builder, DubboBootstrap dubboBootstrap) {
+        super(dubboBootstrap);
+        this.builder = builder;
+    }
+
+    public ProtocolSettings name(String name) {
+        builder.name(name);
+        return this;
+    }
+
+    public ProtocolSettings host(String host) {
+        builder.host(host);
+        return this;
+    }
+
+    public ProtocolSettings port(Integer port) {
+        builder.port(port);
+        return this;
+    }
+
+    public ProtocolSettings contextpath(String contextpath) {
+        builder.contextpath(contextpath);
+        return this;
+    }
+
+    @Deprecated
+    public ProtocolSettings path(String path) {
+        builder.path(path);
+        return this;
+    }
+
+    public ProtocolSettings threadpool(String threadpool) {
+        builder.threadpool(threadpool);
+        return this;
+    }
+
+    public ProtocolSettings corethreads(Integer corethreads) {
+        builder.corethreads(corethreads);
+        return this;
+    }
+
+    public ProtocolSettings threads(Integer threads) {
+        builder.threads(threads);
+        return this;
+    }
+
+    public ProtocolSettings iothreads(Integer iothreads) {
+        builder.iothreads(iothreads);
+        return this;
+    }
+
+    public ProtocolSettings queues(Integer queues) {
+        builder.queues(queues);
+        return this;
+    }
+
+    public ProtocolSettings accepts(Integer accepts) {
+        builder.accepts(accepts);
+        return this;
+    }
+
+    public ProtocolSettings codec(String codec) {
+        builder.codec(codec);
+        return this;
+    }
+
+    public ProtocolSettings serialization(String serialization) {
+        builder.serialization(serialization);
+        return this;
+    }
+
+    public ProtocolSettings charset(String charset) {
+        builder.charset(charset);
+        return this;
+    }
+
+    public ProtocolSettings payload(Integer payload) {
+        builder.payload(payload);
+        return this;
+    }
+
+    public ProtocolSettings buffer(Integer buffer) {
+        builder.buffer(buffer);
+        return this;
+    }
+
+    public ProtocolSettings heartbeat(Integer heartbeat) {
+        builder.heartbeat(heartbeat);
+        return this;
+    }
+
+    public ProtocolSettings accesslog(String accesslog) {
+        builder.accesslog(accesslog);
+        return this;
+    }
+
+    public ProtocolSettings transporter(String transporter) {
+        builder.transporter(transporter);
+        return this;
+    }
+
+    public ProtocolSettings exchanger(String exchanger) {
+        builder.exchanger(exchanger);
+        return this;
+    }
+
+    public ProtocolSettings dispatcher(String dispatcher) {
+        builder.dispatcher(dispatcher);
+        return this;
+    }
+
+    @Deprecated
+    public ProtocolSettings dispather(String dispather) {
+        builder.dispather(dispather);
+        return this;
+    }
+
+    public ProtocolSettings networker(String networker) {
+        builder.networker(networker);
+        return this;
+    }
+
+    public ProtocolSettings server(String server) {
+        builder.server(server);
+        return this;
+    }
+
+    public ProtocolSettings client(String client) {
+        builder.client(client);
+        return this;
+    }
+
+    public ProtocolSettings telnet(String telnet) {
+        builder.telnet(telnet);
+        return this;
+    }
+
+    public ProtocolSettings prompt(String prompt) {
+        builder.prompt(prompt);
+        return this;
+    }
+
+    public ProtocolSettings status(String status) {
+        builder.status(status);
+        return this;
+    }
+
+    public ProtocolSettings register(Boolean register) {
+        builder.register(register);
+        return this;
+    }
+
+    public ProtocolSettings keepAlive(Boolean keepAlive) {
+        builder.keepAlive(keepAlive);
+        return this;
+    }
+
+    public ProtocolSettings optimizer(String optimizer) {
+        builder.optimizer(optimizer);
+        return this;
+    }
+
+    public ProtocolSettings extension(String extension) {
+        builder.extension(extension);
+        return this;
+    }
+
+    public ProtocolSettings appendParameter(String key, String value) {
+        builder.appendParameter(key, value);
+        return this;
+    }
+
+    public ProtocolSettings appendParameters(Map<String, String> appendParameters) {
+        builder.appendParameters(appendParameters);
+        return this;
+    }
+
+    public ProtocolSettings isDefault(Boolean isDefault) {
+        builder.isDefault(isDefault);
+        return this;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java
new file mode 100644
index 0000000..b38ae05
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java
@@ -0,0 +1,334 @@
+/*
+ * 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.bootstrap;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ConfigCenterConfig;
+import org.apache.dubbo.config.ConsumerConfig;
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.ModuleConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.builders.ReferenceBuilder;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The settings of {@link ReferenceConfig}
+ *
+ * @since 2.7.3
+ */
+public class ReferenceSettings<S> extends AbstractSettings {
+
+    private final ReferenceBuilder<S> builder;
+
+    public ReferenceSettings(ReferenceBuilder<S> builder, DubboBootstrap dubboBootstrap) {
+        super(dubboBootstrap);
+        this.builder = builder;
+    }
+
+    public ReferenceSettings<S> interfaceName(String interfaceName) {
+        builder.interfaceName(interfaceName);
+        return this;
+    }
+
+    public ReferenceSettings<S> interfaceClass(Class<?> interfaceClass) {
+        builder.interfaceClass(interfaceClass);
+        return this;
+    }
+
+    public ReferenceSettings<S> client(String client) {
+        builder.client(client);
+        return this;
+    }
+
+    public ReferenceSettings<S> url(String url) {
+        builder.url(url);
+        return this;
+    }
+
+    public ReferenceSettings<S> addMethods(List<MethodConfig> methods) {
+        builder.addMethods(methods);
+        return this;
+    }
+
+    public ReferenceSettings<S> addMethod(MethodConfig method) {
+        builder.addMethod(method);
+        return this;
+    }
+
+    public ReferenceSettings<S> consumer(ConsumerConfig consumer) {
+        builder.consumer(consumer);
+        return this;
+    }
+
+    public ReferenceSettings<S> protocol(String protocol) {
+        builder.protocol(protocol);
+        return this;
+    }
+
+    public ReferenceSettings<S> check(Boolean check) {
+        builder.check(check);
+        return this;
+    }
+
+    public ReferenceSettings<S> init(Boolean init) {
+        builder.init(init);
+        return this;
+    }
+
+    public ReferenceSettings<S> generic(String generic) {
+        builder.generic(generic);
+        return this;
+    }
+
+    public ReferenceSettings<S> generic(Boolean generic) {
+        builder.generic(generic);
+        return this;
+    }
+
+    @Deprecated
+    public ReferenceSettings<S> injvm(Boolean injvm) {
+        builder.injvm(injvm);
+        return this;
+    }
+
+    public ReferenceSettings<S> lazy(Boolean lazy) {
+        builder.lazy(lazy);
+        return this;
+    }
+
+    public ReferenceSettings<S> reconnect(String reconnect) {
+        builder.reconnect(reconnect);
+        return this;
+    }
+
+    public ReferenceSettings<S> sticky(Boolean sticky) {
+        builder.sticky(sticky);
+        return this;
+    }
+
+    public ReferenceSettings<S> version(String version) {
+        builder.version(version);
+        return this;
+    }
+
+    public ReferenceSettings<S> group(String group) {
+        builder.group(group);
+        return this;
+    }
+
+    @Deprecated
+    public ReferenceSettings<S> local(String local) {
+        builder.local(local);
+        return this;
+    }
+
+    @Deprecated
+    public ReferenceSettings<S> local(Boolean local) {
+        builder.local(local);
+        return this;
+    }
+
+    public ReferenceSettings<S> stub(String stub) {
+        builder.stub(stub);
+        return this;
+    }
+
+    public ReferenceSettings<S> stub(Boolean stub) {
+        builder.stub(stub);
+        return this;
+    }
+
+    public ReferenceSettings<S> monitor(MonitorConfig monitor) {
+        builder.monitor(monitor);
+        return this;
+    }
+
+    public ReferenceSettings<S> monitor(String monitor) {
+        builder.monitor(monitor);
+        return this;
+    }
+
+    public ReferenceSettings<S> proxy(String proxy) {
+        builder.proxy(proxy);
+        return this;
+    }
+
+    public ReferenceSettings<S> cluster(String cluster) {
+        builder.cluster(cluster);
+        return this;
+    }
+
+    public ReferenceSettings<S> filter(String filter) {
+        builder.filter(filter);
+        return this;
+    }
+
+    public ReferenceSettings<S> listener(String listener) {
+        builder.listener(listener);
+        return this;
+    }
+
+    public ReferenceSettings<S> owner(String owner) {
+        builder.owner(owner);
+        return this;
+    }
+
+    public ReferenceSettings<S> connections(Integer connections) {
+        builder.connections(connections);
+        return this;
+    }
+
+    public ReferenceSettings<S> layer(String layer) {
+        builder.layer(layer);
+        return this;
+    }
+
+    public ReferenceSettings<S> application(ApplicationConfig application) {
+        builder.application(application);
+        return this;
+    }
+
+    public ReferenceSettings<S> module(ModuleConfig module) {
+        builder.module(module);
+        return this;
+    }
+
+    public ReferenceSettings<S> addRegistries(List<RegistryConfig> registries) {
+        builder.addRegistries(registries);
+        return this;
+    }
+
+    public ReferenceSettings<S> addRegistry(RegistryConfig registry) {
+        builder.addRegistry(registry);
+        return this;
+    }
+
+    public ReferenceSettings<S> registryIds(String registryIds) {
+        builder.registryIds(registryIds);
+        return this;
+    }
+
+    public ReferenceSettings<S> onconnect(String onconnect) {
+        builder.onconnect(onconnect);
+        return this;
+    }
+
+    public ReferenceSettings<S> ondisconnect(String ondisconnect) {
+        builder.ondisconnect(ondisconnect);
+        return this;
+    }
+
+    public ReferenceSettings<S> metadataReportConfig(MetadataReportConfig metadataReportConfig) {
+        builder.metadataReportConfig(metadataReportConfig);
+        return this;
+    }
+
+    public ReferenceSettings<S> configCenter(ConfigCenterConfig configCenter) {
+        builder.configCenter(configCenter);
+        return this;
+    }
+
+    public ReferenceSettings<S> callbacks(Integer callbacks) {
+        builder.callbacks(callbacks);
+        return this;
+    }
+
+    public ReferenceSettings<S> scope(String scope) {
+        builder.scope(scope);
+        return this;
+    }
+
+    public ReferenceSettings<S> tag(String tag) {
+        builder.tag(tag);
+        return this;
+    }
+
+    public ReferenceSettings<S> timeout(Integer timeout) {
+        builder.timeout(timeout);
+        return this;
+    }
+
+    public ReferenceSettings<S> retries(Integer retries) {
+        builder.retries(retries);
+        return this;
+    }
+
+    public ReferenceSettings<S> actives(Integer actives) {
+        builder.actives(actives);
+        return this;
+    }
+
+    public ReferenceSettings<S> loadbalance(String loadbalance) {
+        builder.loadbalance(loadbalance);
+        return this;
+    }
+
+    public ReferenceSettings<S> async(Boolean async) {
+        builder.async(async);
+        return this;
+    }
+
+    public ReferenceSettings<S> sent(Boolean sent) {
+        builder.sent(sent);
+        return this;
+    }
+
+    public ReferenceSettings<S> mock(String mock) {
+        builder.mock(mock);
+        return this;
+    }
+
+    public ReferenceSettings<S> mock(Boolean mock) {
+        builder.mock(mock);
+        return this;
+    }
+
+    public ReferenceSettings<S> merger(String merger) {
+        builder.merger(merger);
+        return this;
+    }
+
+    public ReferenceSettings<S> cache(String cache) {
+        builder.cache(cache);
+        return this;
+    }
+
+    public ReferenceSettings<S> validation(String validation) {
+        builder.validation(validation);
+        return this;
+    }
+
+    public ReferenceSettings<S> appendParameters(Map<String, String> appendParameters) {
+        builder.appendParameters(appendParameters);
+        return this;
+    }
+
+    public ReferenceSettings<S> appendParameter(String key, String value) {
+        builder.appendParameter(key, value);
+        return this;
+    }
+
+    public ReferenceSettings<S> forks(Integer forks) {
+        builder.forks(forks);
+        return this;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java
new file mode 100644
index 0000000..40331ae
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java
@@ -0,0 +1,164 @@
+/*
+ * 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.bootstrap;
+
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.builders.RegistryBuilder;
+
+import java.util.Map;
+
+/**
+ * The settings of {@link RegistryConfig}
+ *
+ * @since 2.7.3
+ */
+public class RegistrySettings extends AbstractSettings {
+
+    private final RegistryBuilder builder;
+
+    public RegistrySettings(RegistryBuilder builder, DubboBootstrap dubboBootstrap) {
+        super(dubboBootstrap);
+        this.builder = builder;
+    }
+
+    public RegistrySettings address(String address) {
+        builder.address(address);
+        return this;
+    }
+
+    public RegistrySettings username(String username) {
+        builder.username(username);
+        return this;
+    }
+
+    public RegistrySettings password(String password) {
+        builder.password(password);
+        return this;
+    }
+
+    public RegistrySettings port(Integer port) {
+        builder.port(port);
+        return this;
+    }
+
+    public RegistrySettings protocol(String protocol) {
+        builder.protocol(protocol);
+        return this;
+    }
+
+    public RegistrySettings transporter(String transporter) {
+        builder.transporter(transporter);
+        return this;
+    }
+
+    @Deprecated
+    public RegistrySettings transport(String transport) {
+        builder.transport(transport);
+        return this;
+    }
+
+    public RegistrySettings server(String server) {
+        builder.server(server);
+        return this;
+    }
+
+    public RegistrySettings client(String client) {
+        builder.client(client);
+        return this;
+    }
+
+    public RegistrySettings cluster(String cluster) {
+        builder.cluster(cluster);
+        return this;
+    }
+
+    public RegistrySettings group(String group) {
+        builder.group(group);
+        return this;
+    }
+
+    public RegistrySettings version(String version) {
+        builder.version(version);
+        return this;
+    }
+
+    public RegistrySettings timeout(Integer timeout) {
+        builder.timeout(timeout);
+        return this;
+    }
+
+    public RegistrySettings session(Integer session) {
+        builder.session(session);
+        return this;
+    }
+
+    public RegistrySettings file(String file) {
+        builder.file(file);
+        return this;
+    }
+
+    @Deprecated
+    public RegistrySettings wait(Integer wait) {
+        builder.wait(wait);
+        return this;
+    }
+
+    public RegistrySettings isCheck(Boolean check) {
+        builder.isCheck(check);
+        return this;
+    }
+
+    public RegistrySettings isDynamic(Boolean dynamic) {
+        builder.isDynamic(dynamic);
+        return this;
+    }
+
+    public RegistrySettings register(Boolean register) {
+        builder.register(register);
+        return this;
+    }
+
+    public RegistrySettings subscribe(Boolean subscribe) {
+        builder.subscribe(subscribe);
+        return this;
+    }
+
+    public RegistrySettings appendParameter(String key, String value) {
+        builder.appendParameter(key, value);
+        return this;
+    }
+
+    public RegistrySettings appendParameters(Map<String, String> appendParameters) {
+        builder.appendParameters(appendParameters);
+        return this;
+    }
+
+    public RegistrySettings isDefault(Boolean isDefault) {
+        builder.isDefault(isDefault);
+        return this;
+    }
+
+    public RegistrySettings simplified(Boolean simplified) {
+        builder.simplified(simplified);
+        return this;
+    }
+
+    public RegistrySettings extraKeys(String extraKeys) {
+        builder.extraKeys(extraKeys);
+        return this;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java
new file mode 100644
index 0000000..314482e
--- /dev/null
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java
@@ -0,0 +1,384 @@
+/*
+ * 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.bootstrap;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ConfigCenterConfig;
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.ModuleConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.ProviderConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.builders.ServiceBuilder;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The settings of {@link ServiceConfig Dubbo service}
+ *
+ * @since 2.7.3
+ */
+public class ServiceSettings<S> extends AbstractSettings {
+
+    private final ServiceBuilder<S> builder;
+
+    public ServiceSettings(ServiceBuilder<S> builder, DubboBootstrap dubboBootstrap) {
+        super(dubboBootstrap);
+        this.builder = builder;
+    }
+
+    public ServiceSettings<S> interfaceName(String interfaceName) {
+        builder.interfaceName(interfaceName);
+        return this;
+    }
+
+    public ServiceSettings<S> interfaceClass(Class<?> interfaceClass) {
+        builder.interfaceClass(interfaceClass);
+        return this;
+    }
+
+    public ServiceSettings<S> ref(S ref) {
+        builder.ref(ref);
+        return this;
+    }
+
+    public ServiceSettings<S> path(String path) {
+        builder.path(path);
+        return this;
+    }
+
+    public ServiceSettings<S> addMethod(MethodConfig method) {
+        builder.addMethod(method);
+        return this;
+    }
+
+    public ServiceSettings<S> addMethods(List<? extends MethodConfig> methods) {
+        builder.addMethods(methods);
+        return this;
+    }
+
+    public ServiceSettings<S> provider(ProviderConfig provider) {
+        builder.provider(provider);
+        return this;
+    }
+
+    public ServiceSettings<S> providerIds(String providerIds) {
+        builder.providerIds(providerIds);
+        return this;
+    }
+
+    public ServiceSettings<S> generic(String generic) {
+        builder.generic(generic);
+        return this;
+    }
+
+    public ServiceSettings<S> mock(String mock) {
+        builder.mock(mock);
+        return this;
+    }
+
+    public ServiceSettings<S> mock(Boolean mock) {
+        builder.mock(mock);
+        return this;
+    }
+
+    public ServiceSettings<S> version(String version) {
+        builder.version(version);
+        return this;
+    }
+
+    public ServiceSettings<S> group(String group) {
+        builder.group(group);
+        return this;
+    }
+
+    public ServiceSettings<S> deprecated(Boolean deprecated) {
+        builder.deprecated(deprecated);
+        return this;
+    }
+
+    public ServiceSettings<S> delay(Integer delay) {
+        builder.delay(delay);
+        return this;
+    }
+
+    public ServiceSettings<S> export(Boolean export) {
+        builder.export(export);
+        return this;
+    }
+
+    public ServiceSettings<S> weight(Integer weight) {
+        builder.weight(weight);
+        return this;
+    }
+
+    public ServiceSettings<S> document(String document) {
+        builder.document(document);
+        return this;
+    }
+
+    public ServiceSettings<S> dynamic(Boolean dynamic) {
+        builder.dynamic(dynamic);
+        return this;
+    }
+
+    public ServiceSettings<S> token(String token) {
+        builder.token(token);
+        return this;
+    }
+
+    public ServiceSettings<S> token(Boolean token) {
+        builder.token(token);
+        return this;
+    }
+
+    public ServiceSettings<S> accesslog(String accesslog) {
+        builder.accesslog(accesslog);
+        return this;
+    }
+
+    public ServiceSettings<S> accesslog(Boolean accesslog) {
+        builder.accesslog(accesslog);
+        return this;
+    }
+
+    public ServiceSettings<S> addProtocols(List<ProtocolConfig> protocols) {
+        builder.addProtocols(protocols);
+        return this;
+    }
+
+    public ServiceSettings<S> addProtocol(ProtocolConfig protocol) {
+        builder.addProtocol(protocol);
+        return this;
+    }
+
+    public ServiceSettings<S> protocolIds(String protocolIds) {
+        builder.protocolIds(protocolIds);
+        return this;
+    }
+
+    public ServiceSettings<S> executes(Integer executes) {
+        builder.executes(executes);
+        return this;
+    }
+
+    public ServiceSettings<S> register(Boolean register) {
+        builder.register(register);
+        return this;
+    }
+
+    public ServiceSettings<S> warmup(Integer warmup) {
+        builder.warmup(warmup);
+        return this;
+    }
+
+    public ServiceSettings<S> serialization(String serialization) {
+        builder.serialization(serialization);
+        return this;
+    }
+
+    @Deprecated
+    public ServiceSettings<S> local(String local) {
+        builder.local(local);
+        return this;
+    }
+
+    @Deprecated
+    public ServiceSettings<S> local(Boolean local) {
+        builder.local(local);
+        return this;
+    }
+
+    public ServiceSettings<S> stub(String stub) {
+        builder.stub(stub);
+        return this;
+    }
+
+    public ServiceSettings<S> stub(Boolean stub) {
+        builder.stub(stub);
+        return this;
+    }
+
+    public ServiceSettings<S> monitor(MonitorConfig monitor) {
+        builder.monitor(monitor);
+        return this;
+    }
+
+    public ServiceSettings<S> monitor(String monitor) {
+        builder.monitor(monitor);
+        return this;
+    }
+
+    public ServiceSettings<S> proxy(String proxy) {
+        builder.proxy(proxy);
+        return this;
+    }
+
+    public ServiceSettings<S> cluster(String cluster) {
+        builder.cluster(cluster);
+        return this;
+    }
+
+    public ServiceSettings<S> filter(String filter) {
+        builder.filter(filter);
+        return this;
+    }
+
+    public ServiceSettings<S> listener(String listener) {
+        builder.listener(listener);
+        return this;
+    }
+
+    public ServiceSettings<S> owner(String owner) {
+        builder.owner(owner);
+        return this;
+    }
+
+    public ServiceSettings<S> connections(Integer connections) {
+        builder.connections(connections);
+        return this;
+    }
+
+    public ServiceSettings<S> layer(String layer) {
+        builder.layer(layer);
+        return this;
+    }
+
+    public ServiceSettings<S> application(ApplicationConfig application) {
+        builder.application(application);
+        return this;
+    }
+
+    public ServiceSettings<S> module(ModuleConfig module) {
+        builder.module(module);
+        return this;
+    }
+
+    public ServiceSettings<S> addRegistries(List<RegistryConfig> registries) {
+        builder.addRegistries(registries);
+        return this;
+    }
+
+    public ServiceSettings<S> addRegistry(RegistryConfig registry) {
+        builder.addRegistry(registry);
+        return this;
+    }
+
+    public ServiceSettings<S> registryIds(String registryIds) {
+        builder.registryIds(registryIds);
+        return this;
+    }
+
+    public ServiceSettings<S> onconnect(String onconnect) {
+        builder.onconnect(onconnect);
+        return this;
+    }
+
+    public ServiceSettings<S> ondisconnect(String ondisconnect) {
+        builder.ondisconnect(ondisconnect);
+        return this;
+    }
+
+    public ServiceSettings<S> metadataReportConfig(MetadataReportConfig metadataReportConfig) {
+        builder.metadataReportConfig(metadataReportConfig);
+        return this;
+    }
+
+    public ServiceSettings<S> configCenter(ConfigCenterConfig configCenter) {
+        builder.configCenter(configCenter);
+        return this;
+    }
+
+    public ServiceSettings<S> callbacks(Integer callbacks) {
+        builder.callbacks(callbacks);
+        return this;
+    }
+
+    public ServiceSettings<S> scope(String scope) {
+        builder.scope(scope);
+        return this;
+    }
+
+    public ServiceSettings<S> tag(String tag) {
+        builder.tag(tag);
+        return this;
+    }
+
+    public ServiceSettings<S> timeout(Integer timeout) {
+        builder.timeout(timeout);
+        return this;
+    }
+
+    public ServiceSettings<S> retries(Integer retries) {
+        builder.retries(retries);
+        return this;
+    }
+
+    public ServiceSettings<S> actives(Integer actives) {
+        builder.actives(actives);
+        return this;
+    }
+
+    public ServiceSettings<S> loadbalance(String loadbalance) {
+        builder.loadbalance(loadbalance);
+        return this;
+    }
+
+    public ServiceSettings<S> async(Boolean async) {
+        builder.async(async);
+        return this;
+    }
+
+    public ServiceSettings<S> sent(Boolean sent) {
+        builder.sent(sent);
+        return this;
+    }
+
+    public ServiceSettings<S> merger(String merger) {
+        builder.merger(merger);
+        return this;
+    }
+
+    public ServiceSettings<S> cache(String cache) {
+        builder.cache(cache);
+        return this;
+    }
+
+    public ServiceSettings<S> validation(String validation) {
+        builder.validation(validation);
+        return this;
+    }
+
+    public ServiceSettings<S> appendParameters(Map<String, String> appendParameters) {
+        builder.appendParameters(appendParameters);
+        return this;
+    }
+
+    public ServiceSettings<S> appendParameter(String key, String value) {
+        builder.appendParameter(key, value);
+        return this;
+    }
+
+    public ServiceSettings<S> forks(Integer forks) {
+        builder.forks(forks);
+        return this;
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java
similarity index 74%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java
index c5bc722..abf8141 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java
@@ -14,24 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.api;
-
-import java.util.List;
-
+package org.apache.dubbo.bootstrap;
 
 /**
- * DemoService
+ * The Dubbo settings
+ *
+ * @since 2.7.3
  */
-public interface DemoService {
-
-    String sayName(String name);
-
-    Box getBox();
-
-    void throwDemoException() throws DemoException;
-
-    List<User> getUsers(List<User> users);
-
-    int echo(int i);
-
-}
\ No newline at end of file
+public interface Settings {
+
+    /**
+     * Go next settings
+     *
+     * @return {@link DubboBootstrap}
+     */
+    DubboBootstrap next();
+}
diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java
new file mode 100644
index 0000000..b9acd29
--- /dev/null
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.bootstrap;
+
+import org.apache.dubbo.common.utils.NetUtils;
+
+import org.apache.curator.test.TestingServer;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+/**
+ * {@link DubboBootstrap} Test
+ *
+ * @since 2.7.3
+ */
+public class DubboBootstrapTest {
+
+    private static int zkServerPort = NetUtils.getAvailablePort();
+
+    private static TestingServer zkServer;
+
+
+    @BeforeAll
+    public static void init() throws Exception {
+        zkServer = new TestingServer(zkServerPort, true);
+    }
+
+    @AfterAll
+    public static void destroy() throws IOException {
+        zkServer.stop();
+        zkServer.close();
+    }
+
+    @Test
+    public void testProviderInFluentAPI() {
+
+        new DubboBootstrap()
+                .application("dubbo-provider-demo")
+                .next()
+                .registry()
+                .address("zookeeper://127.0.0.1:" + zkServerPort + "?registry-type=service")
+                .next()
+                .protocol()
+                .name("dubbo")
+                .port(-1)
+                .next()
+                .service("test")
+                .interfaceClass(EchoService.class)
+                .ref(new EchoServiceImpl())
+                .group("DEFAULT")
+                .version("1.0.0")
+                .next()
+                .start()
+                .stop();
+
+    }
+
+    @Test
+    public void testProviderInLambda() {
+        new DubboBootstrap()
+                .application("dubbo-provider-demo", builder -> {
+                })
+                .registry("default", builder ->
+                        builder.address("zookeeper://127.0.0.1:" + zkServerPort + "?registry-type=service")
+                )
+                .protocol("defalt", builder ->
+                        builder.name("dubbo")
+                                .port(-1)
+                )
+                .service("test", builder ->
+                        builder.interfaceClass(EchoService.class)
+                                .ref(new EchoServiceImpl())
+                                .group("DEFAULT")
+                                .version("1.0.0")
+                )
+                .start()
+                .stop();
+    }
+}
diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java
new file mode 100644
index 0000000..800f29d
--- /dev/null
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java
@@ -0,0 +1,58 @@
+/*
+ * 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.bootstrap;
+
+import org.apache.dubbo.config.ReferenceConfig;
+
+import static org.apache.dubbo.bootstrap.EchoService.GROUP;
+import static org.apache.dubbo.bootstrap.EchoService.VERSION;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.3
+ */
+public class DubboServiceConsumerBootstrap {
+
+    public static void main(String[] args) throws Exception {
+
+        DubboBootstrap bootstrap = new DubboBootstrap()
+                .application("dubbo-consumer-demo")
+                .next()
+                .registry()
+                .address("nacos://127.0.0.1:8848?registry-type=service&subscribed-services=dubbo-provider-demo")
+                .next()
+                .reference("ref")
+                .interfaceClass(EchoService.class)
+                .group(GROUP)
+                .version(VERSION)
+                .next()
+                .onlyRegisterProvider(true)
+                .start()
+                .await();
+
+        ReferenceConfig<EchoService> referenceConfig = bootstrap.referenceConfig("ref");
+
+        EchoService echoService = referenceConfig.get();
+
+        for (int i = 0; i < 500; i++) {
+            Thread.sleep(2000L);
+            System.out.println(echoService.echo("Hello,World"));
+        }
+
+    }
+}
diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java
new file mode 100644
index 0000000..bb149ad
--- /dev/null
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java
@@ -0,0 +1,52 @@
+/*
+ * 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.bootstrap;
+
+import java.io.IOException;
+
+import static org.apache.dubbo.bootstrap.EchoService.GROUP;
+import static org.apache.dubbo.bootstrap.EchoService.VERSION;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.3
+ */
+public class DubboServiceProviderBootstrap {
+
+    public static void main(String[] args) throws IOException {
+
+        new DubboBootstrap()
+                .application("dubbo-provider-demo")
+                .next()
+                .registry()
+                .address("nacos://127.0.0.1:8848?registry-type=service")
+                .next()
+                .protocol()
+                .name("dubbo")
+                .port(-1)
+                .next()
+                .service("test")
+                .interfaceClass(EchoService.class)
+                .ref(new EchoServiceImpl())
+                .group(GROUP)
+                .version(VERSION)
+                .next()
+                .start()
+                .await();
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoService.java
similarity index 74%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoService.java
index c5bc722..7ad8698 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoService.java
@@ -14,24 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.api;
-
-import java.util.List;
-
+package org.apache.dubbo.bootstrap;
 
 /**
- * DemoService
+ * Echo Service
+ *
+ * @since 2.7.3
  */
-public interface DemoService {
-
-    String sayName(String name);
-
-    Box getBox();
-
-    void throwDemoException() throws DemoException;
+public interface EchoService {
 
-    List<User> getUsers(List<User> users);
+    String GROUP = "DEFAULT";
 
-    int echo(int i);
+    String VERSION = "1.0.0";
 
-}
\ No newline at end of file
+    String echo(String message);
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoServiceImpl.java
similarity index 62%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoServiceImpl.java
index c5bc722..e0218b1 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/EchoServiceImpl.java
@@ -14,24 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.api;
+package org.apache.dubbo.bootstrap;
 
-import java.util.List;
+import org.apache.dubbo.rpc.RpcContext;
 
+import static java.lang.String.format;
 
 /**
- * DemoService
+ * The implementation of {@link EchoService}
+ *
+ * @see EchoService
+ * @since 2.7.3
  */
-public interface DemoService {
-
-    String sayName(String name);
-
-    Box getBox();
-
-    void throwDemoException() throws DemoException;
-
-    List<User> getUsers(List<User> users);
-
-    int echo(int i);
-
-}
\ No newline at end of file
+public class EchoServiceImpl implements EchoService {
+
+    @Override
+    public String echo(String message) {
+        RpcContext rpcContext = RpcContext.getContext();
+        return format("[%s:%s] ECHO - %s", rpcContext.getLocalHost(), rpcContext.getLocalPort(), message);
+    }
+}
diff --git a/dubbo-bootstrap/src/test/resources/log4j.properties b/dubbo-bootstrap/src/test/resources/log4j.properties
new file mode 100644
index 0000000..15a0900
--- /dev/null
+++ b/dubbo-bootstrap/src/test/resources/log4j.properties
@@ -0,0 +1,7 @@
+###set log levels###
+log4j.rootLogger=info, stdout
+###output to the console###
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
index 87e9b25..3ac978d 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
@@ -38,16 +38,16 @@ import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
+import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
 import static org.apache.dubbo.rpc.cluster.Constants.ADDRESS_KEY;
 import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;
 import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;
 import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;
 import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
-import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
 
 /**
  * ConditionRouter
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
index 7a2894b..8eca3c1 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
@@ -23,7 +23,6 @@ import org.apache.dubbo.remoting.Constants;
 import java.util.HashMap;
 import java.util.Map;
 
-import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;
@@ -41,6 +40,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
 import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
 import static org.apache.dubbo.rpc.Constants.INVOKER_LISTENER_KEY;
 import static org.apache.dubbo.rpc.Constants.REFERENCE_FILTER_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
 
 /**
  * ClusterUtils
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
index 871e075..1a67587 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ClusterUtilsTest.java
@@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test;
 import static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
 import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;
@@ -32,7 +33,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
 import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
 
 public class ClusterUtilsTest {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
index 106bebc..82627f2 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
@@ -40,20 +40,20 @@ import java.util.Map;
 import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
 
-import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
 import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
 import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
 import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
 
 /**
  * URL - Uniform Resource Locator (Immutable, ThreadSafe)
@@ -339,6 +339,30 @@ class URL implements Serializable {
         }
     }
 
+    static String appendDefaultPort(String address, int defaultPort) {
+        if (address != null && address.length() > 0 && defaultPort > 0) {
+            int i = address.indexOf(':');
+            if (i < 0) {
+                return address + ":" + defaultPort;
+            } else if (Integer.parseInt(address.substring(i + 1)) == 0) {
+                return address.substring(0, i + 1) + defaultPort;
+            }
+        }
+        return address;
+    }
+
+    public static String buildKey(String path, String group, String version) {
+        StringBuilder buf = new StringBuilder();
+        if (group != null && group.length() > 0) {
+            buf.append(group).append("/");
+        }
+        buf.append(path);
+        if (version != null && version.length() > 0) {
+            buf.append(":").append(version);
+        }
+        return buf.toString();
+    }
+
     public String getProtocol() {
         return protocol;
     }
@@ -452,18 +476,6 @@ class URL implements Serializable {
         return urls;
     }
 
-    static String appendDefaultPort(String address, int defaultPort) {
-        if (address != null && address.length() > 0 && defaultPort > 0) {
-            int i = address.indexOf(':');
-            if (i < 0) {
-                return address + ":" + defaultPort;
-            } else if (Integer.parseInt(address.substring(i + 1)) == 0) {
-                return address.substring(0, i + 1) + defaultPort;
-            }
-        }
-        return address;
-    }
-
     public String getPath() {
         return path;
     }
@@ -1325,6 +1337,7 @@ class URL implements Serializable {
 
     /**
      * The format of return value is '{group}/{interfaceName}:{version}'
+     *
      * @return
      */
     public String getServiceKey() {
@@ -1337,6 +1350,7 @@ class URL implements Serializable {
 
     /**
      * The format of return value is '{group}/{path/interfaceName}:{version}'
+     *
      * @return
      */
     public String getPathKey() {
@@ -1347,18 +1361,6 @@ class URL implements Serializable {
         return buildKey(inf, getParameter(GROUP_KEY), getParameter(VERSION_KEY));
     }
 
-    public static String buildKey(String path, String group, String version) {
-        StringBuilder buf = new StringBuilder();
-        if (group != null && group.length() > 0) {
-            buf.append(group).append("/");
-        }
-        buf.append(path);
-        if (version != null && version.length() > 0) {
-            buf.append(":").append(version);
-        }
-        return buf.toString();
-    }
-
     public String toServiceStringWithoutResolving() {
         return buildString(true, false, false, true);
     }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
index 647ac81..b28fe39 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
@@ -52,4 +52,38 @@ public interface RegistryConstants {
     String OVERRIDE_PROTOCOL = "override";
 
     String COMPATIBLE_CONFIG_KEY = "compatible_config";
+
+    /**
+     * The parameter key of Dubbo Registry type
+     *
+     * @since 2.7.3
+     */
+    String REGISTRY_TYPE_KEY = "registry-type";
+
+    /**
+     * The parameter value of Service-Oriented Registry type
+     *
+     * @since 2.7.3
+     */
+    String SERVICE_REGISTRY_TYPE = "service";
+
+    /**
+     * The parameter key of the subscribed service names for Service-Oriented Registry
+     *
+     * @since 2.7.3
+     */
+    String SUBSCRIBED_SERVICE_NAMES_KEY = "subscribed-services";
+
+
+    /**
+     * The request size of service instances
+     *
+     * @since 2.7.3
+     */
+    String INSTANCES_REQUEST_SIZE_KEY = "instances-request-size";
+
+    /**
+     * The default request size of service instances
+     */
+    int DEFAULT_INSTANCES_REQUEST_SIZE = 100;
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableConsumer.java b/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableConsumer.java
new file mode 100644
index 0000000..28561bb
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableConsumer.java
@@ -0,0 +1,66 @@
+/*
+ * 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.common.function;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * {@link Consumer} with {@link Throwable}
+ *
+ * @param <T> the source type
+ * @see Function
+ * @see Throwable
+ * @since 2.7.3
+ */
+@FunctionalInterface
+public interface ThrowableConsumer<T> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param t the function argument
+     * @throws Throwable if met with any error
+     */
+    void accept(T t) throws Throwable;
+
+    /**
+     * Executes {@link ThrowableConsumer}
+     *
+     * @param t the function argument
+     * @throws RuntimeException wrappers {@link Throwable}
+     */
+    default void execute(T t) throws RuntimeException {
+        try {
+            accept(t);
+        } catch (Throwable e) {
+            throw new RuntimeException(e.getMessage(), e.getCause());
+        }
+    }
+
+    /**
+     * Executes {@link ThrowableConsumer}
+     *
+     * @param t        the function argument
+     * @param consumer {@link ThrowableConsumer}
+     * @param <T>      the source type
+     * @return the result after execution
+     */
+    static <T> void execute(T t, ThrowableConsumer<T> consumer) {
+        consumer.execute(t);
+    }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableFunction.java b/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableFunction.java
new file mode 100644
index 0000000..eb7171d
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/function/ThrowableFunction.java
@@ -0,0 +1,71 @@
+/*
+ * 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.common.function;
+
+import java.util.function.Function;
+
+/**
+ * {@link Function} with {@link Throwable}
+ *
+ * @param <T> the source type
+ * @param <R> the return type
+ * @see Function
+ * @see Throwable
+ * @since 2.7.3
+ */
+@FunctionalInterface
+public interface ThrowableFunction<T, R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param t the function argument
+     * @return the function result
+     * @throws Throwable if met with any error
+     */
+    R apply(T t) throws Throwable;
+
+    /**
+     * Executes {@link ThrowableFunction}
+     *
+     * @param t the function argument
+     * @return the function result
+     * @throws RuntimeException wrappers {@link Throwable}
+     */
+    default R execute(T t) throws RuntimeException {
+        R result = null;
+        try {
+            result = apply(t);
+        } catch (Throwable e) {
+            throw new RuntimeException(e.getCause());
+        }
+        return result;
+    }
+
+    /**
+     * Executes {@link ThrowableFunction}
+     *
+     * @param t        the function argument
+     * @param function {@link ThrowableFunction}
+     * @param <T>      the source type
+     * @param <R>      the return type
+     * @return the result after execution
+     */
+    static <T, R> R execute(T t, ThrowableFunction<T, R> function) {
+        return function.execute(t);
+    }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultPage.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultPage.java
new file mode 100644
index 0000000..fd408b5
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultPage.java
@@ -0,0 +1,82 @@
+/*
+ * 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.common.utils;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * The default implementation of {@link Page}
+ *
+ * @since 2.7.3
+ */
+public class DefaultPage<T> implements Page<T>, Serializable {
+
+    private static final long serialVersionUID = 1099331838954070419L;
+
+    private final int requestOffset;
+
+    private final int pageSize;
+
+    private final int totalSize;
+
+    private final List<T> data;
+
+    private final int totalPages;
+
+    private final boolean hasNext;
+
+    public DefaultPage(int requestOffset, int pageSize, List<T> data, int totalSize) {
+        this.requestOffset = requestOffset;
+        this.pageSize = pageSize;
+        this.data = data;
+        this.totalSize = totalSize;
+        int remain = totalSize % pageSize;
+        this.totalPages = remain > 0 ? (totalSize / pageSize) + 1 : totalSize / pageSize;
+        this.hasNext = totalSize - requestOffset - pageSize > 0;
+    }
+
+    @Override
+    public int getOffset() {
+        return requestOffset;
+    }
+
+    @Override
+    public int getPageSize() {
+        return pageSize;
+    }
+
+    @Override
+    public int getTotalSize() {
+        return totalSize;
+    }
+
+    @Override
+    public int getTotalPages() {
+        return totalPages;
+    }
+
+    @Override
+    public List<T> getData() {
+        return data;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return hasNext;
+    }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
index 6fd1a4e..c2fea8b 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
@@ -37,9 +37,9 @@ import java.util.concurrent.ThreadLocalRandom;
 import java.util.regex.Pattern;
 
 import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
 import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
 
 /**
  * IP and Port Helper for RPC
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/Page.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/Page.java
new file mode 100644
index 0000000..c15cfb8
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/Page.java
@@ -0,0 +1,87 @@
+/*
+ * 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.common.utils;
+
+import java.util.List;
+
+/**
+ * The model class of pagination
+ *
+ * @since 2.7.3
+ */
+public interface Page<T> {
+
+    /**
+     * Gets the offset of request
+     *
+     * @return positive integer
+     */
+    int getOffset();
+
+    /**
+     * Gets the size of request for pagination query
+     *
+     * @return positive integer
+     */
+    int getPageSize();
+
+    /**
+     * Gets the total amount of elements.
+     *
+     * @return the total amount of elements
+     */
+    int getTotalSize();
+
+    /**
+     * Get the number of total pages.
+     *
+     * @return the number of total pages.
+     */
+    int getTotalPages();
+
+    /**
+     * The data of current page
+     *
+     * @return non-null {@link List}
+     */
+    List<T> getData();
+
+    /**
+     * The size of {@link #getData() data}
+     *
+     * @return positive integer
+     */
+    default int getDataSize() {
+        return getData().size();
+    }
+
+    /**
+     * It indicates has next page or not
+     *
+     * @return if has , return <code>true</code>, or <code>false</code>
+     */
+    boolean hasNext();
+
+    /**
+     * Returns whether the page has data at all.
+     *
+     * @return
+     */
+    default boolean hasData() {
+        return getDataSize() > 0;
+    }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
index 0c1a13d..437f131 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
@@ -1,1122 +1,1187 @@
-/*
- * 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.common.utils;
-
-import javassist.CtClass;
-import javassist.CtConstructor;
-import javassist.CtMethod;
-import javassist.NotFoundException;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.net.URL;
-import java.security.CodeSource;
-import java.security.ProtectionDomain;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Future;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * ReflectUtils
- */
-public final class ReflectUtils {
-
-    /**
-     * void(V).
-     */
-    public static final char JVM_VOID = 'V';
-
-    /**
-     * boolean(Z).
-     */
-    public static final char JVM_BOOLEAN = 'Z';
-
-    /**
-     * byte(B).
-     */
-    public static final char JVM_BYTE = 'B';
-
-    /**
-     * char(C).
-     */
-    public static final char JVM_CHAR = 'C';
-
-    /**
-     * double(D).
-     */
-    public static final char JVM_DOUBLE = 'D';
-
-    /**
-     * float(F).
-     */
-    public static final char JVM_FLOAT = 'F';
-
-    /**
-     * int(I).
-     */
-    public static final char JVM_INT = 'I';
-
-    /**
-     * long(J).
-     */
-    public static final char JVM_LONG = 'J';
-
-    /**
-     * short(S).
-     */
-    public static final char JVM_SHORT = 'S';
-
-    public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
-
-    public static final String JAVA_IDENT_REGEX = "(?:[_$a-zA-Z][_$a-zA-Z0-9]*)";
-
-    public static final String JAVA_NAME_REGEX = "(?:" + JAVA_IDENT_REGEX + "(?:\\." + JAVA_IDENT_REGEX + ")*)";
-
-    public static final String CLASS_DESC = "(?:L" + JAVA_IDENT_REGEX + "(?:\\/" + JAVA_IDENT_REGEX + ")*;)";
-
-    public static final String ARRAY_DESC = "(?:\\[+(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "))";
-
-    public static final String DESC_REGEX = "(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "|" + ARRAY_DESC + ")";
-
-    public static final Pattern DESC_PATTERN = Pattern.compile(DESC_REGEX);
-
-    public static final String METHOD_DESC_REGEX = "(?:(" + JAVA_IDENT_REGEX + ")?\\((" + DESC_REGEX + "*)\\)(" + DESC_REGEX + ")?)";
-
-    public static final Pattern METHOD_DESC_PATTERN = Pattern.compile(METHOD_DESC_REGEX);
-
-    public static final Pattern GETTER_METHOD_DESC_PATTERN = Pattern.compile("get([A-Z][_a-zA-Z0-9]*)\\(\\)(" + DESC_REGEX + ")");
-
-    public static final Pattern SETTER_METHOD_DESC_PATTERN = Pattern.compile("set([A-Z][_a-zA-Z0-9]*)\\((" + DESC_REGEX + ")\\)V");
-
-    public static final Pattern IS_HAS_CAN_METHOD_DESC_PATTERN = Pattern.compile("(?:is|has|can)([A-Z][_a-zA-Z0-9]*)\\(\\)Z");
-
-    private static final ConcurrentMap<String, Class<?>> DESC_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();
-
-    private static final ConcurrentMap<String, Class<?>> NAME_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();
-
-    private static final ConcurrentMap<String, Method> Signature_METHODS_CACHE = new ConcurrentHashMap<String, Method>();
-
-    private ReflectUtils() {
-    }
-
-    public static boolean isPrimitives(Class<?> cls) {
-        if (cls.isArray()) {
-            return isPrimitive(cls.getComponentType());
-        }
-        return isPrimitive(cls);
-    }
-
-    public static boolean isPrimitive(Class<?> cls) {
-        return cls.isPrimitive() || cls == String.class || cls == Boolean.class || cls == Character.class
-                || Number.class.isAssignableFrom(cls) || Date.class.isAssignableFrom(cls);
-    }
-
-    public static Class<?> getBoxedClass(Class<?> c) {
-        if (c == int.class) {
-            c = Integer.class;
-        } else if (c == boolean.class) {
-            c = Boolean.class;
-        } else if (c == long.class) {
-            c = Long.class;
-        } else if (c == float.class) {
-            c = Float.class;
-        } else if (c == double.class) {
-            c = Double.class;
-        } else if (c == char.class) {
-            c = Character.class;
-        } else if (c == byte.class) {
-            c = Byte.class;
-        } else if (c == short.class) {
-            c = Short.class;
-        }
-        return c;
-    }
-
-    /**
-     * is compatible.
-     *
-     * @param c class.
-     * @param o instance.
-     * @return compatible or not.
-     */
-    public static boolean isCompatible(Class<?> c, Object o) {
-        boolean pt = c.isPrimitive();
-        if (o == null) {
-            return !pt;
-        }
-
-        if (pt) {
-            c = getBoxedClass(c);
-        }
-
-        return c == o.getClass() || c.isInstance(o);
-    }
-
-    /**
-     * is compatible.
-     *
-     * @param cs class array.
-     * @param os object array.
-     * @return compatible or not.
-     */
-    public static boolean isCompatible(Class<?>[] cs, Object[] os) {
-        int len = cs.length;
-        if (len != os.length) {
-            return false;
-        }
-        if (len == 0) {
-            return true;
-        }
-        for (int i = 0; i < len; i++) {
-            if (!isCompatible(cs[i], os[i])) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    public static String getCodeBase(Class<?> cls) {
-        if (cls == null) {
-            return null;
-        }
-        ProtectionDomain domain = cls.getProtectionDomain();
-        if (domain == null) {
-            return null;
-        }
-        CodeSource source = domain.getCodeSource();
-        if (source == null) {
-            return null;
-        }
-        URL location = source.getLocation();
-        if (location == null) {
-            return null;
-        }
-        return location.getFile();
-    }
-
-    /**
-     * get name.
-     * java.lang.Object[][].class => "java.lang.Object[][]"
-     *
-     * @param c class.
-     * @return name.
-     */
-    public static String getName(Class<?> c) {
-        if (c.isArray()) {
-            StringBuilder sb = new StringBuilder();
-            do {
-                sb.append("[]");
-                c = c.getComponentType();
-            }
-            while (c.isArray());
-
-            return c.getName() + sb.toString();
-        }
-        return c.getName();
-    }
-
-    public static Class<?> getGenericClass(Class<?> cls) {
-        return getGenericClass(cls, 0);
-    }
-
-    public static Class<?> getGenericClass(Class<?> cls, int i) {
-        try {
-            ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]);
-            Object genericClass = parameterizedType.getActualTypeArguments()[i];
-            if (genericClass instanceof ParameterizedType) { // handle nested generic type
-                return (Class<?>) ((ParameterizedType) genericClass).getRawType();
-            } else if (genericClass instanceof GenericArrayType) { // handle array generic type
-                return (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType();
-            } else if (((Class) genericClass).isArray()) {
-                // Requires JDK 7 or higher, Foo<int[]> is no longer GenericArrayType
-                return ((Class) genericClass).getComponentType();
-            } else {
-                return (Class<?>) genericClass;
-            }
-        } catch (Throwable e) {
-            throw new IllegalArgumentException(cls.getName()
-                    + " generic type undefined!", e);
-        }
-    }
-
-    /**
-     * get method name.
-     * "void do(int)", "void do()", "int do(java.lang.String,boolean)"
-     *
-     * @param m method.
-     * @return name.
-     */
-    public static String getName(final Method m) {
-        StringBuilder ret = new StringBuilder();
-        ret.append(getName(m.getReturnType())).append(' ');
-        ret.append(m.getName()).append('(');
-        Class<?>[] parameterTypes = m.getParameterTypes();
-        for (int i = 0; i < parameterTypes.length; i++) {
-            if (i > 0) {
-                ret.append(',');
-            }
-            ret.append(getName(parameterTypes[i]));
-        }
-        ret.append(')');
-        return ret.toString();
-    }
-
-    public static String getSignature(String methodName, Class<?>[] parameterTypes) {
-        StringBuilder sb = new StringBuilder(methodName);
-        sb.append("(");
-        if (parameterTypes != null && parameterTypes.length > 0) {
-            boolean first = true;
-            for (Class<?> type : parameterTypes) {
-                if (first) {
-                    first = false;
-                } else {
-                    sb.append(",");
-                }
-                sb.append(type.getName());
-            }
-        }
-        sb.append(")");
-        return sb.toString();
-    }
-
-    /**
-     * get constructor name.
-     * "()", "(java.lang.String,int)"
-     *
-     * @param c constructor.
-     * @return name.
-     */
-    public static String getName(final Constructor<?> c) {
-        StringBuilder ret = new StringBuilder("(");
-        Class<?>[] parameterTypes = c.getParameterTypes();
-        for (int i = 0; i < parameterTypes.length; i++) {
-            if (i > 0) {
-                ret.append(',');
-            }
-            ret.append(getName(parameterTypes[i]));
-        }
-        ret.append(')');
-        return ret.toString();
-    }
-
-    /**
-     * get class desc.
-     * boolean[].class => "[Z"
-     * Object.class => "Ljava/lang/Object;"
-     *
-     * @param c class.
-     * @return desc.
-     * @throws NotFoundException
-     */
-    public static String getDesc(Class<?> c) {
-        StringBuilder ret = new StringBuilder();
-
-        while (c.isArray()) {
-            ret.append('[');
-            c = c.getComponentType();
-        }
-
-        if (c.isPrimitive()) {
-            String t = c.getName();
-            if ("void".equals(t)) {
-                ret.append(JVM_VOID);
-            } else if ("boolean".equals(t)) {
-                ret.append(JVM_BOOLEAN);
-            } else if ("byte".equals(t)) {
-                ret.append(JVM_BYTE);
-            } else if ("char".equals(t)) {
-                ret.append(JVM_CHAR);
-            } else if ("double".equals(t)) {
-                ret.append(JVM_DOUBLE);
-            } else if ("float".equals(t)) {
-                ret.append(JVM_FLOAT);
-            } else if ("int".equals(t)) {
-                ret.append(JVM_INT);
-            } else if ("long".equals(t)) {
-                ret.append(JVM_LONG);
-            } else if ("short".equals(t)) {
-                ret.append(JVM_SHORT);
-            }
-        } else {
-            ret.append('L');
-            ret.append(c.getName().replace('.', '/'));
-            ret.append(';');
-        }
-        return ret.toString();
-    }
-
-    /**
-     * get class array desc.
-     * [int.class, boolean[].class, Object.class] => "I[ZLjava/lang/Object;"
-     *
-     * @param cs class array.
-     * @return desc.
-     * @throws NotFoundException
-     */
-    public static String getDesc(final Class<?>[] cs) {
-        if (cs.length == 0) {
-            return "";
-        }
-
-        StringBuilder sb = new StringBuilder(64);
-        for (Class<?> c : cs) {
-            sb.append(getDesc(c));
-        }
-        return sb.toString();
-    }
-
-    /**
-     * get method desc.
-     * int do(int arg1) => "do(I)I"
-     * void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V"
-     *
-     * @param m method.
-     * @return desc.
-     */
-    public static String getDesc(final Method m) {
-        StringBuilder ret = new StringBuilder(m.getName()).append('(');
-        Class<?>[] parameterTypes = m.getParameterTypes();
-        for (int i = 0; i < parameterTypes.length; i++) {
-            ret.append(getDesc(parameterTypes[i]));
-        }
-        ret.append(')').append(getDesc(m.getReturnType()));
-        return ret.toString();
-    }
-
-    /**
-     * get constructor desc.
-     * "()V", "(Ljava/lang/String;I)V"
-     *
-     * @param c constructor.
-     * @return desc
-     */
-    public static String getDesc(final Constructor<?> c) {
-        StringBuilder ret = new StringBuilder("(");
-        Class<?>[] parameterTypes = c.getParameterTypes();
-        for (int i = 0; i < parameterTypes.length; i++) {
-            ret.append(getDesc(parameterTypes[i]));
-        }
-        ret.append(')').append('V');
-        return ret.toString();
-    }
-
-    /**
-     * get method desc.
-     * "(I)I", "()V", "(Ljava/lang/String;Z)V"
-     *
-     * @param m method.
-     * @return desc.
-     */
-    public static String getDescWithoutMethodName(Method m) {
-        StringBuilder ret = new StringBuilder();
-        ret.append('(');
-        Class<?>[] parameterTypes = m.getParameterTypes();
-        for (int i = 0; i < parameterTypes.length; i++) {
-            ret.append(getDesc(parameterTypes[i]));
-        }
-        ret.append(')').append(getDesc(m.getReturnType()));
-        return ret.toString();
-    }
-
-    /**
-     * get class desc.
-     * Object.class => "Ljava/lang/Object;"
-     * boolean[].class => "[Z"
-     *
-     * @param c class.
-     * @return desc.
-     * @throws NotFoundException
-     */
-    public static String getDesc(final CtClass c) throws NotFoundException {
-        StringBuilder ret = new StringBuilder();
-        if (c.isArray()) {
-            ret.append('[');
-            ret.append(getDesc(c.getComponentType()));
-        } else if (c.isPrimitive()) {
-            String t = c.getName();
-            if ("void".equals(t)) {
-                ret.append(JVM_VOID);
-            } else if ("boolean".equals(t)) {
-                ret.append(JVM_BOOLEAN);
-            } else if ("byte".equals(t)) {
-                ret.append(JVM_BYTE);
-            } else if ("char".equals(t)) {
-                ret.append(JVM_CHAR);
-            } else if ("double".equals(t)) {
-                ret.append(JVM_DOUBLE);
-            } else if ("float".equals(t)) {
-                ret.append(JVM_FLOAT);
-            } else if ("int".equals(t)) {
-                ret.append(JVM_INT);
-            } else if ("long".equals(t)) {
-                ret.append(JVM_LONG);
-            } else if ("short".equals(t)) {
-                ret.append(JVM_SHORT);
-            }
-        } else {
-            ret.append('L');
-            ret.append(c.getName().replace('.', '/'));
-            ret.append(';');
-        }
-        return ret.toString();
-    }
-
-    /**
-     * get method desc.
-     * "do(I)I", "do()V", "do(Ljava/lang/String;Z)V"
-     *
-     * @param m method.
-     * @return desc.
-     */
-    public static String getDesc(final CtMethod m) throws NotFoundException {
-        StringBuilder ret = new StringBuilder(m.getName()).append('(');
-        CtClass[] parameterTypes = m.getParameterTypes();
-        for (int i = 0; i < parameterTypes.length; i++) {
-            ret.append(getDesc(parameterTypes[i]));
-        }
-        ret.append(')').append(getDesc(m.getReturnType()));
-        return ret.toString();
-    }
-
-    /**
-     * get constructor desc.
-     * "()V", "(Ljava/lang/String;I)V"
-     *
-     * @param c constructor.
-     * @return desc
-     */
-    public static String getDesc(final CtConstructor c) throws NotFoundException {
-        StringBuilder ret = new StringBuilder("(");
-        CtClass[] parameterTypes = c.getParameterTypes();
-        for (int i = 0; i < parameterTypes.length; i++) {
-            ret.append(getDesc(parameterTypes[i]));
-        }
-        ret.append(')').append('V');
-        return ret.toString();
-    }
-
-    /**
-     * get method desc.
-     * "(I)I", "()V", "(Ljava/lang/String;Z)V".
-     *
-     * @param m method.
-     * @return desc.
-     */
-    public static String getDescWithoutMethodName(final CtMethod m) throws NotFoundException {
-        StringBuilder ret = new StringBuilder();
-        ret.append('(');
-        CtClass[] parameterTypes = m.getParameterTypes();
-        for (int i = 0; i < parameterTypes.length; i++) {
-            ret.append(getDesc(parameterTypes[i]));
-        }
-        ret.append(')').append(getDesc(m.getReturnType()));
-        return ret.toString();
-    }
-
-    /**
-     * name to desc.
-     * java.util.Map[][] => "[[Ljava/util/Map;"
-     *
-     * @param name name.
-     * @return desc.
-     */
-    public static String name2desc(String name) {
-        StringBuilder sb = new StringBuilder();
-        int c = 0, index = name.indexOf('[');
-        if (index > 0) {
-            c = (name.length() - index) / 2;
-            name = name.substring(0, index);
-        }
-        while (c-- > 0) {
-            sb.append("[");
-        }
-        if ("void".equals(name)) {
-            sb.append(JVM_VOID);
-        } else if ("boolean".equals(name)) {
-            sb.append(JVM_BOOLEAN);
-        } else if ("byte".equals(name)) {
-            sb.append(JVM_BYTE);
-        } else if ("char".equals(name)) {
-            sb.append(JVM_CHAR);
-        } else if ("double".equals(name)) {
-            sb.append(JVM_DOUBLE);
-        } else if ("float".equals(name)) {
-            sb.append(JVM_FLOAT);
-        } else if ("int".equals(name)) {
-            sb.append(JVM_INT);
-        } else if ("long".equals(name)) {
-            sb.append(JVM_LONG);
-        } else if ("short".equals(name)) {
-            sb.append(JVM_SHORT);
-        } else {
-            sb.append('L').append(name.replace('.', '/')).append(';');
-        }
-        return sb.toString();
-    }
-
-    /**
-     * desc to name.
-     * "[[I" => "int[][]"
-     *
-     * @param desc desc.
-     * @return name.
-     */
-    public static String desc2name(String desc) {
-        StringBuilder sb = new StringBuilder();
-        int c = desc.lastIndexOf('[') + 1;
-        if (desc.length() == c + 1) {
-            switch (desc.charAt(c)) {
-                case JVM_VOID: {
-                    sb.append("void");
-                    break;
-                }
-                case JVM_BOOLEAN: {
-                    sb.append("boolean");
-                    break;
-                }
-                case JVM_BYTE: {
-                    sb.append("byte");
-                    break;
-                }
-                case JVM_CHAR: {
-                    sb.append("char");
-                    break;
-                }
-                case JVM_DOUBLE: {
-                    sb.append("double");
-                    break;
-                }
-                case JVM_FLOAT: {
-                    sb.append("float");
-                    break;
-                }
-                case JVM_INT: {
-                    sb.append("int");
-                    break;
-                }
-                case JVM_LONG: {
-                    sb.append("long");
-                    break;
-                }
-                case JVM_SHORT: {
-                    sb.append("short");
-                    break;
-                }
-                default:
-                    throw new RuntimeException();
-            }
-        } else {
-            sb.append(desc.substring(c + 1, desc.length() - 1).replace('/', '.'));
-        }
-        while (c-- > 0) {
-            sb.append("[]");
-        }
-        return sb.toString();
-    }
-
-    public static Class<?> forName(String name) {
-        try {
-            return name2class(name);
-        } catch (ClassNotFoundException e) {
-            throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
-        }
-    }
-
-    public static Class<?> forName(ClassLoader cl, String name) {
-        try {
-            return name2class(cl, name);
-        } catch (ClassNotFoundException e) {
-            throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
-        }
-    }
-
-    /**
-     * name to class.
-     * "boolean" => boolean.class
-     * "java.util.Map[][]" => java.util.Map[][].class
-     *
-     * @param name name.
-     * @return Class instance.
-     */
-    public static Class<?> name2class(String name) throws ClassNotFoundException {
-        return name2class(ClassUtils.getClassLoader(), name);
-    }
-
-    /**
-     * name to class.
-     * "boolean" => boolean.class
-     * "java.util.Map[][]" => java.util.Map[][].class
-     *
-     * @param cl   ClassLoader instance.
-     * @param name name.
-     * @return Class instance.
-     */
-    private static Class<?> name2class(ClassLoader cl, String name) throws ClassNotFoundException {
-        int c = 0, index = name.indexOf('[');
-        if (index > 0) {
-            c = (name.length() - index) / 2;
-            name = name.substring(0, index);
-        }
-        if (c > 0) {
-            StringBuilder sb = new StringBuilder();
-            while (c-- > 0) {
-                sb.append("[");
-            }
-
-            if ("void".equals(name)) {
-                sb.append(JVM_VOID);
-            } else if ("boolean".equals(name)) {
-                sb.append(JVM_BOOLEAN);
-            } else if ("byte".equals(name)) {
-                sb.append(JVM_BYTE);
-            } else if ("char".equals(name)) {
-                sb.append(JVM_CHAR);
-            } else if ("double".equals(name)) {
-                sb.append(JVM_DOUBLE);
-            } else if ("float".equals(name)) {
-                sb.append(JVM_FLOAT);
-            } else if ("int".equals(name)) {
-                sb.append(JVM_INT);
-            } else if ("long".equals(name)) {
-                sb.append(JVM_LONG);
-            } else if ("short".equals(name)) {
-                sb.append(JVM_SHORT);
-            } else {
-                sb.append('L').append(name).append(';'); // "java.lang.Object" ==> "Ljava.lang.Object;"
-            }
-            name = sb.toString();
-        } else {
-            if ("void".equals(name)) {
-                return void.class;
-            } else if ("boolean".equals(name)) {
-                return boolean.class;
-            } else if ("byte".equals(name)) {
-                return byte.class;
-            } else if ("char".equals(name)) {
-                return char.class;
-            } else if ("double".equals(name)) {
-                return double.class;
-            } else if ("float".equals(name)) {
-                return float.class;
-            } else if ("int".equals(name)) {
-                return int.class;
-            } else if ("long".equals(name)) {
-                return long.class;
-            } else if ("short".equals(name)) {
-                return short.class;
-            }
-        }
-
-        if (cl == null) {
-            cl = ClassUtils.getClassLoader();
-        }
-        Class<?> clazz = NAME_CLASS_CACHE.get(name);
-        if (clazz == null) {
-            clazz = Class.forName(name, true, cl);
-            NAME_CLASS_CACHE.put(name, clazz);
-        }
-        return clazz;
-    }
-
-    /**
-     * desc to class.
-     * "[Z" => boolean[].class
-     * "[[Ljava/util/Map;" => java.util.Map[][].class
-     *
-     * @param desc desc.
-     * @return Class instance.
-     * @throws ClassNotFoundException
-     */
-    public static Class<?> desc2class(String desc) throws ClassNotFoundException {
-        return desc2class(ClassUtils.getClassLoader(), desc);
-    }
-
-    /**
-     * desc to class.
-     * "[Z" => boolean[].class
-     * "[[Ljava/util/Map;" => java.util.Map[][].class
-     *
-     * @param cl   ClassLoader instance.
-     * @param desc desc.
-     * @return Class instance.
-     * @throws ClassNotFoundException
-     */
-    private static Class<?> desc2class(ClassLoader cl, String desc) throws ClassNotFoundException {
-        switch (desc.charAt(0)) {
-            case JVM_VOID:
-                return void.class;
-            case JVM_BOOLEAN:
-                return boolean.class;
-            case JVM_BYTE:
-                return byte.class;
-            case JVM_CHAR:
-                return char.class;
-            case JVM_DOUBLE:
-                return double.class;
-            case JVM_FLOAT:
-                return float.class;
-            case JVM_INT:
-                return int.class;
-            case JVM_LONG:
-                return long.class;
-            case JVM_SHORT:
-                return short.class;
-            case 'L':
-                desc = desc.substring(1, desc.length() - 1).replace('/', '.'); // "Ljava/lang/Object;" ==> "java.lang.Object"
-                break;
-            case '[':
-                desc = desc.replace('/', '.');  // "[[Ljava/lang/Object;" ==> "[[Ljava.lang.Object;"
-                break;
-            default:
-                throw new ClassNotFoundException("Class not found: " + desc);
-        }
-
-        if (cl == null) {
-            cl = ClassUtils.getClassLoader();
-        }
-        Class<?> clazz = DESC_CLASS_CACHE.get(desc);
-        if (clazz == null) {
-            clazz = Class.forName(desc, true, cl);
-            DESC_CLASS_CACHE.put(desc, clazz);
-        }
-        return clazz;
-    }
-
-    /**
-     * get class array instance.
-     *
-     * @param desc desc.
-     * @return Class class array.
-     * @throws ClassNotFoundException
-     */
-    public static Class<?>[] desc2classArray(String desc) throws ClassNotFoundException {
-        Class<?>[] ret = desc2classArray(ClassUtils.getClassLoader(), desc);
-        return ret;
-    }
-
-    /**
-     * get class array instance.
-     *
-     * @param cl   ClassLoader instance.
-     * @param desc desc.
-     * @return Class[] class array.
-     * @throws ClassNotFoundException
-     */
-    private static Class<?>[] desc2classArray(ClassLoader cl, String desc) throws ClassNotFoundException {
-        if (desc.length() == 0) {
-            return EMPTY_CLASS_ARRAY;
-        }
-
-        List<Class<?>> cs = new ArrayList<Class<?>>();
-        Matcher m = DESC_PATTERN.matcher(desc);
-        while (m.find()) {
-            cs.add(desc2class(cl, m.group()));
-        }
-        return cs.toArray(EMPTY_CLASS_ARRAY);
-    }
-
-    /**
-     * Find method from method signature
-     *
-     * @param clazz      Target class to find method
-     * @param methodName Method signature, e.g.: method1(int, String). It is allowed to provide method name only, e.g.: method2
-     * @return target method
-     * @throws NoSuchMethodException
-     * @throws ClassNotFoundException
-     * @throws IllegalStateException  when multiple methods are found (overridden method when parameter info is not provided)
-     */
-    public static Method findMethodByMethodSignature(Class<?> clazz, String methodName, String[] parameterTypes)
-            throws NoSuchMethodException, ClassNotFoundException {
-        String signature = clazz.getName() + "." + methodName;
-        if (parameterTypes != null && parameterTypes.length > 0) {
-            signature += StringUtils.join(parameterTypes);
-        }
-        Method method = Signature_METHODS_CACHE.get(signature);
-        if (method != null) {
-            return method;
-        }
-        if (parameterTypes == null) {
-            List<Method> finded = new ArrayList<Method>();
-            for (Method m : clazz.getMethods()) {
-                if (m.getName().equals(methodName)) {
-                    finded.add(m);
-                }
-            }
-            if (finded.isEmpty()) {
-                throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz);
-            }
-            if (finded.size() > 1) {
-                String msg = String.format("Not unique method for method name(%s) in class(%s), find %d methods.",
-                        methodName, clazz.getName(), finded.size());
-                throw new IllegalStateException(msg);
-            }
-            method = finded.get(0);
-        } else {
-            Class<?>[] types = new Class<?>[parameterTypes.length];
-            for (int i = 0; i < parameterTypes.length; i++) {
-                types[i] = ReflectUtils.name2class(parameterTypes[i]);
-            }
-            method = clazz.getMethod(methodName, types);
-
-        }
-        Signature_METHODS_CACHE.put(signature, method);
-        return method;
-    }
-
-    public static Method findMethodByMethodName(Class<?> clazz, String methodName)
-            throws NoSuchMethodException, ClassNotFoundException {
-        return findMethodByMethodSignature(clazz, methodName, null);
-    }
-
-    public static Constructor<?> findConstructor(Class<?> clazz, Class<?> paramType) throws NoSuchMethodException {
-        Constructor<?> targetConstructor;
-        try {
-            targetConstructor = clazz.getConstructor(new Class<?>[]{paramType});
-        } catch (NoSuchMethodException e) {
-            targetConstructor = null;
-            Constructor<?>[] constructors = clazz.getConstructors();
-            for (Constructor<?> constructor : constructors) {
-                if (Modifier.isPublic(constructor.getModifiers())
-                        && constructor.getParameterTypes().length == 1
-                        && constructor.getParameterTypes()[0].isAssignableFrom(paramType)) {
-                    targetConstructor = constructor;
-                    break;
-                }
-            }
-            if (targetConstructor == null) {
-                throw e;
-            }
-        }
-        return targetConstructor;
-    }
-
-    /**
-     * Check if one object is the implementation for a given interface.
-     * <p>
-     * This method will not trigger classloading for the given interface, therefore it will not lead to error when
-     * the given interface is not visible by the classloader
-     *
-     * @param obj                Object to examine
-     * @param interfaceClazzName The given interface
-     * @return true if the object implements the given interface, otherwise return false
-     */
-    public static boolean isInstance(Object obj, String interfaceClazzName) {
-        for (Class<?> clazz = obj.getClass();
-             clazz != null && !clazz.equals(Object.class);
-             clazz = clazz.getSuperclass()) {
-            Class<?>[] interfaces = clazz.getInterfaces();
-            for (Class<?> itf : interfaces) {
-                if (itf.getName().equals(interfaceClazzName)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    public static Object getEmptyObject(Class<?> returnType) {
-        return getEmptyObject(returnType, new HashMap<Class<?>, Object>(), 0);
-    }
-
-    private static Object getEmptyObject(Class<?> returnType, Map<Class<?>, Object> emptyInstances, int level) {
-        if (level > 2) {
-            return null;
-        }
-        if (returnType == null) {
-            return null;
-        } else if (returnType == boolean.class || returnType == Boolean.class) {
-            return false;
-        } else if (returnType == char.class || returnType == Character.class) {
-            return '\0';
-        } else if (returnType == byte.class || returnType == Byte.class) {
-            return (byte) 0;
-        } else if (returnType == short.class || returnType == Short.class) {
-            return (short) 0;
-        } else if (returnType == int.class || returnType == Integer.class) {
-            return 0;
-        } else if (returnType == long.class || returnType == Long.class) {
-            return 0L;
-        } else if (returnType == float.class || returnType == Float.class) {
-            return 0F;
-        } else if (returnType == double.class || returnType == Double.class) {
-            return 0D;
-        } else if (returnType.isArray()) {
-            return Array.newInstance(returnType.getComponentType(), 0);
-        } else if (returnType.isAssignableFrom(ArrayList.class)) {
-            return new ArrayList<Object>(0);
-        } else if (returnType.isAssignableFrom(HashSet.class)) {
-            return new HashSet<Object>(0);
-        } else if (returnType.isAssignableFrom(HashMap.class)) {
-            return new HashMap<Object, Object>(0);
-        } else if (String.class.equals(returnType)) {
-            return "";
-        } else if (!returnType.isInterface()) {
-            try {
-                Object value = emptyInstances.get(returnType);
-                if (value == null) {
-                    value = returnType.newInstance();
-                    emptyInstances.put(returnType, value);
-                }
-                Class<?> cls = value.getClass();
-                while (cls != null && cls != Object.class) {
-                    Field[] fields = cls.getDeclaredFields();
-                    for (Field field : fields) {
-                        if (field.isSynthetic()) {
-                            continue;
-                        }
-                        Object property = getEmptyObject(field.getType(), emptyInstances, level + 1);
-                        if (property != null) {
-                            try {
-                                if (!field.isAccessible()) {
-                                    field.setAccessible(true);
-                                }
-                                field.set(value, property);
-                            } catch (Throwable e) {
-                            }
-                        }
-                    }
-                    cls = cls.getSuperclass();
-                }
-                return value;
-            } catch (Throwable e) {
-                return null;
-            }
-        } else {
-            return null;
-        }
-    }
-
-    public static boolean isBeanPropertyReadMethod(Method method) {
-        return method != null
-                && Modifier.isPublic(method.getModifiers())
-                && !Modifier.isStatic(method.getModifiers())
-                && method.getReturnType() != void.class
-                && method.getDeclaringClass() != Object.class
-                && method.getParameterTypes().length == 0
-                && ((method.getName().startsWith("get") && method.getName().length() > 3)
-                || (method.getName().startsWith("is") && method.getName().length() > 2));
-    }
-
-    public static String getPropertyNameFromBeanReadMethod(Method method) {
-        if (isBeanPropertyReadMethod(method)) {
-            if (method.getName().startsWith("get")) {
-                return method.getName().substring(3, 4).toLowerCase()
-                        + method.getName().substring(4);
-            }
-            if (method.getName().startsWith("is")) {
-                return method.getName().substring(2, 3).toLowerCase()
-                        + method.getName().substring(3);
-            }
-        }
-        return null;
-    }
-
-    public static boolean isBeanPropertyWriteMethod(Method method) {
-        return method != null
-                && Modifier.isPublic(method.getModifiers())
-                && !Modifier.isStatic(method.getModifiers())
-                && method.getDeclaringClass() != Object.class
-                && method.getParameterTypes().length == 1
-                && method.getName().startsWith("set")
-                && method.getName().length() > 3;
-    }
-
-    public static String getPropertyNameFromBeanWriteMethod(Method method) {
-        if (isBeanPropertyWriteMethod(method)) {
-            return method.getName().substring(3, 4).toLowerCase()
-                    + method.getName().substring(4);
-        }
-        return null;
-    }
-
-    public static boolean isPublicInstanceField(Field field) {
-        return Modifier.isPublic(field.getModifiers())
-                && !Modifier.isStatic(field.getModifiers())
-                && !Modifier.isFinal(field.getModifiers())
-                && !field.isSynthetic();
-    }
-
-    public static Map<String, Field> getBeanPropertyFields(Class cl) {
-        Map<String, Field> properties = new HashMap<String, Field>();
-        for (; cl != null; cl = cl.getSuperclass()) {
-            Field[] fields = cl.getDeclaredFields();
-            for (Field field : fields) {
-                if (Modifier.isTransient(field.getModifiers())
-                        || Modifier.isStatic(field.getModifiers())) {
-                    continue;
-                }
-
-                field.setAccessible(true);
-
-                properties.put(field.getName(), field);
-            }
-        }
-
-        return properties;
-    }
-
-    public static Map<String, Method> getBeanPropertyReadMethods(Class cl) {
-        Map<String, Method> properties = new HashMap<String, Method>();
-        for (; cl != null; cl = cl.getSuperclass()) {
-            Method[] methods = cl.getDeclaredMethods();
-            for (Method method : methods) {
-                if (isBeanPropertyReadMethod(method)) {
-                    method.setAccessible(true);
-                    String property = getPropertyNameFromBeanReadMethod(method);
-                    properties.put(property, method);
-                }
-            }
-        }
-
-        return properties;
-    }
-
-    public static Type[] getReturnTypes(Method method) {
-        Class<?> returnType = method.getReturnType();
-        Type genericReturnType = method.getGenericReturnType();
-        if (Future.class.isAssignableFrom(returnType)) {
-            if (genericReturnType instanceof ParameterizedType) {
-                Type actualArgType = ((ParameterizedType) genericReturnType).getActualTypeArguments()[0];
-                if (actualArgType instanceof ParameterizedType) {
-                    returnType = (Class<?>) ((ParameterizedType) actualArgType).getRawType();
-                    genericReturnType = actualArgType;
-                } else {
-                    returnType = (Class<?>) actualArgType;
-                    genericReturnType = returnType;
-                }
-            } else {
-                returnType = null;
-                genericReturnType = null;
-            }
-        }
-        return new Type[]{returnType, genericReturnType};
-    }
+/*
+ * 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.common.utils;
+
+import javassist.CtClass;
+import javassist.CtConstructor;
+import javassist.CtMethod;
+import javassist.NotFoundException;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.net.URL;
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Future;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.unmodifiableSet;
+
+/**
+ * ReflectUtils
+ */
+public final class ReflectUtils {
+
+    /**
+     * void(V).
+     */
+    public static final char JVM_VOID = 'V';
+
+    /**
+     * boolean(Z).
+     */
+    public static final char JVM_BOOLEAN = 'Z';
+
+    /**
+     * byte(B).
+     */
+    public static final char JVM_BYTE = 'B';
+
+    /**
+     * char(C).
+     */
+    public static final char JVM_CHAR = 'C';
+
+    /**
+     * double(D).
+     */
+    public static final char JVM_DOUBLE = 'D';
+
+    /**
+     * float(F).
+     */
+    public static final char JVM_FLOAT = 'F';
+
+    /**
+     * int(I).
+     */
+    public static final char JVM_INT = 'I';
+
+    /**
+     * long(J).
+     */
+    public static final char JVM_LONG = 'J';
+
+    /**
+     * short(S).
+     */
+    public static final char JVM_SHORT = 'S';
+
+    public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
+
+    public static final String JAVA_IDENT_REGEX = "(?:[_$a-zA-Z][_$a-zA-Z0-9]*)";
+
+    public static final String JAVA_NAME_REGEX = "(?:" + JAVA_IDENT_REGEX + "(?:\\." + JAVA_IDENT_REGEX + ")*)";
+
+    public static final String CLASS_DESC = "(?:L" + JAVA_IDENT_REGEX + "(?:\\/" + JAVA_IDENT_REGEX + ")*;)";
+
+    public static final String ARRAY_DESC = "(?:\\[+(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "))";
+
+    public static final String DESC_REGEX = "(?:(?:[VZBCDFIJS])|" + CLASS_DESC + "|" + ARRAY_DESC + ")";
+
+    public static final Pattern DESC_PATTERN = Pattern.compile(DESC_REGEX);
+
+    public static final String METHOD_DESC_REGEX = "(?:(" + JAVA_IDENT_REGEX + ")?\\((" + DESC_REGEX + "*)\\)(" + DESC_REGEX + ")?)";
+
+    public static final Pattern METHOD_DESC_PATTERN = Pattern.compile(METHOD_DESC_REGEX);
+
+    public static final Pattern GETTER_METHOD_DESC_PATTERN = Pattern.compile("get([A-Z][_a-zA-Z0-9]*)\\(\\)(" + DESC_REGEX + ")");
+
+    public static final Pattern SETTER_METHOD_DESC_PATTERN = Pattern.compile("set([A-Z][_a-zA-Z0-9]*)\\((" + DESC_REGEX + ")\\)V");
+
+    public static final Pattern IS_HAS_CAN_METHOD_DESC_PATTERN = Pattern.compile("(?:is|has|can)([A-Z][_a-zA-Z0-9]*)\\(\\)Z");
+
+    private static final ConcurrentMap<String, Class<?>> DESC_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();
+
+    private static final ConcurrentMap<String, Class<?>> NAME_CLASS_CACHE = new ConcurrentHashMap<String, Class<?>>();
+
+    private static final ConcurrentMap<String, Method> Signature_METHODS_CACHE = new ConcurrentHashMap<String, Method>();
+
+    private ReflectUtils() {
+    }
+
+    public static boolean isPrimitives(Class<?> cls) {
+        if (cls.isArray()) {
+            return isPrimitive(cls.getComponentType());
+        }
+        return isPrimitive(cls);
+    }
+
+    public static boolean isPrimitive(Class<?> cls) {
+        return cls.isPrimitive() || cls == String.class || cls == Boolean.class || cls == Character.class
+                || Number.class.isAssignableFrom(cls) || Date.class.isAssignableFrom(cls);
+    }
+
+    public static Class<?> getBoxedClass(Class<?> c) {
+        if (c == int.class) {
+            c = Integer.class;
+        } else if (c == boolean.class) {
+            c = Boolean.class;
+        } else if (c == long.class) {
+            c = Long.class;
+        } else if (c == float.class) {
+            c = Float.class;
+        } else if (c == double.class) {
+            c = Double.class;
+        } else if (c == char.class) {
+            c = Character.class;
+        } else if (c == byte.class) {
+            c = Byte.class;
+        } else if (c == short.class) {
+            c = Short.class;
+        }
+        return c;
+    }
+
+    /**
+     * is compatible.
+     *
+     * @param c class.
+     * @param o instance.
+     * @return compatible or not.
+     */
+    public static boolean isCompatible(Class<?> c, Object o) {
+        boolean pt = c.isPrimitive();
+        if (o == null) {
+            return !pt;
+        }
+
+        if (pt) {
+            c = getBoxedClass(c);
+        }
+
+        return c == o.getClass() || c.isInstance(o);
+    }
+
+    /**
+     * is compatible.
+     *
+     * @param cs class array.
+     * @param os object array.
+     * @return compatible or not.
+     */
+    public static boolean isCompatible(Class<?>[] cs, Object[] os) {
+        int len = cs.length;
+        if (len != os.length) {
+            return false;
+        }
+        if (len == 0) {
+            return true;
+        }
+        for (int i = 0; i < len; i++) {
+            if (!isCompatible(cs[i], os[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static String getCodeBase(Class<?> cls) {
+        if (cls == null) {
+            return null;
+        }
+        ProtectionDomain domain = cls.getProtectionDomain();
+        if (domain == null) {
+            return null;
+        }
+        CodeSource source = domain.getCodeSource();
+        if (source == null) {
+            return null;
+        }
+        URL location = source.getLocation();
+        if (location == null) {
+            return null;
+        }
+        return location.getFile();
+    }
+
+    /**
+     * get name.
+     * java.lang.Object[][].class => "java.lang.Object[][]"
+     *
+     * @param c class.
+     * @return name.
+     */
+    public static String getName(Class<?> c) {
+        if (c.isArray()) {
+            StringBuilder sb = new StringBuilder();
+            do {
+                sb.append("[]");
+                c = c.getComponentType();
+            }
+            while (c.isArray());
+
+            return c.getName() + sb.toString();
+        }
+        return c.getName();
+    }
+
+    public static Class<?> getGenericClass(Class<?> cls) {
+        return getGenericClass(cls, 0);
+    }
+
+    public static Class<?> getGenericClass(Class<?> cls, int i) {
+        try {
+            ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]);
+            Object genericClass = parameterizedType.getActualTypeArguments()[i];
+            if (genericClass instanceof ParameterizedType) { // handle nested generic type
+                return (Class<?>) ((ParameterizedType) genericClass).getRawType();
+            } else if (genericClass instanceof GenericArrayType) { // handle array generic type
+                return (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType();
+            } else if (((Class) genericClass).isArray()) {
+                // Requires JDK 7 or higher, Foo<int[]> is no longer GenericArrayType
+                return ((Class) genericClass).getComponentType();
+            } else {
+                return (Class<?>) genericClass;
+            }
+        } catch (Throwable e) {
+            throw new IllegalArgumentException(cls.getName()
+                    + " generic type undefined!", e);
+        }
+    }
+
+    /**
+     * get method name.
+     * "void do(int)", "void do()", "int do(java.lang.String,boolean)"
+     *
+     * @param m method.
+     * @return name.
+     */
+    public static String getName(final Method m) {
+        StringBuilder ret = new StringBuilder();
+        ret.append(getName(m.getReturnType())).append(' ');
+        ret.append(m.getName()).append('(');
+        Class<?>[] parameterTypes = m.getParameterTypes();
+        for (int i = 0; i < parameterTypes.length; i++) {
+            if (i > 0) {
+                ret.append(',');
+            }
+            ret.append(getName(parameterTypes[i]));
+        }
+        ret.append(')');
+        return ret.toString();
+    }
+
+    public static String getSignature(String methodName, Class<?>[] parameterTypes) {
+        StringBuilder sb = new StringBuilder(methodName);
+        sb.append("(");
+        if (parameterTypes != null && parameterTypes.length > 0) {
+            boolean first = true;
+            for (Class<?> type : parameterTypes) {
+                if (first) {
+                    first = false;
+                } else {
+                    sb.append(",");
+                }
+                sb.append(type.getName());
+            }
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    /**
+     * get constructor name.
+     * "()", "(java.lang.String,int)"
+     *
+     * @param c constructor.
+     * @return name.
+     */
+    public static String getName(final Constructor<?> c) {
+        StringBuilder ret = new StringBuilder("(");
+        Class<?>[] parameterTypes = c.getParameterTypes();
+        for (int i = 0; i < parameterTypes.length; i++) {
+            if (i > 0) {
+                ret.append(',');
+            }
+            ret.append(getName(parameterTypes[i]));
+        }
+        ret.append(')');
+        return ret.toString();
+    }
+
+    /**
+     * get class desc.
+     * boolean[].class => "[Z"
+     * Object.class => "Ljava/lang/Object;"
+     *
+     * @param c class.
+     * @return desc.
+     * @throws NotFoundException
+     */
+    public static String getDesc(Class<?> c) {
+        StringBuilder ret = new StringBuilder();
+
+        while (c.isArray()) {
+            ret.append('[');
+            c = c.getComponentType();
+        }
+
+        if (c.isPrimitive()) {
+            String t = c.getName();
+            if ("void".equals(t)) {
+                ret.append(JVM_VOID);
+            } else if ("boolean".equals(t)) {
+                ret.append(JVM_BOOLEAN);
+            } else if ("byte".equals(t)) {
+                ret.append(JVM_BYTE);
+            } else if ("char".equals(t)) {
+                ret.append(JVM_CHAR);
+            } else if ("double".equals(t)) {
+                ret.append(JVM_DOUBLE);
+            } else if ("float".equals(t)) {
+                ret.append(JVM_FLOAT);
+            } else if ("int".equals(t)) {
+                ret.append(JVM_INT);
+            } else if ("long".equals(t)) {
+                ret.append(JVM_LONG);
+            } else if ("short".equals(t)) {
+                ret.append(JVM_SHORT);
+            }
+        } else {
+            ret.append('L');
+            ret.append(c.getName().replace('.', '/'));
+            ret.append(';');
+        }
+        return ret.toString();
+    }
+
+    /**
+     * get class array desc.
+     * [int.class, boolean[].class, Object.class] => "I[ZLjava/lang/Object;"
+     *
+     * @param cs class array.
+     * @return desc.
+     * @throws NotFoundException
+     */
+    public static String getDesc(final Class<?>[] cs) {
+        if (cs.length == 0) {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder(64);
+        for (Class<?> c : cs) {
+            sb.append(getDesc(c));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * get method desc.
+     * int do(int arg1) => "do(I)I"
+     * void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V"
+     *
+     * @param m method.
+     * @return desc.
+     */
+    public static String getDesc(final Method m) {
+        StringBuilder ret = new StringBuilder(m.getName()).append('(');
+        Class<?>[] parameterTypes = m.getParameterTypes();
+        for (int i = 0; i < parameterTypes.length; i++) {
+            ret.append(getDesc(parameterTypes[i]));
+        }
+        ret.append(')').append(getDesc(m.getReturnType()));
+        return ret.toString();
+    }
+
+    /**
+     * get constructor desc.
+     * "()V", "(Ljava/lang/String;I)V"
+     *
+     * @param c constructor.
+     * @return desc
+     */
+    public static String getDesc(final Constructor<?> c) {
+        StringBuilder ret = new StringBuilder("(");
+        Class<?>[] parameterTypes = c.getParameterTypes();
+        for (int i = 0; i < parameterTypes.length; i++) {
+            ret.append(getDesc(parameterTypes[i]));
+        }
+        ret.append(')').append('V');
+        return ret.toString();
+    }
+
+    /**
+     * get method desc.
+     * "(I)I", "()V", "(Ljava/lang/String;Z)V"
+     *
+     * @param m method.
+     * @return desc.
+     */
+    public static String getDescWithoutMethodName(Method m) {
+        StringBuilder ret = new StringBuilder();
+        ret.append('(');
+        Class<?>[] parameterTypes = m.getParameterTypes();
+        for (int i = 0; i < parameterTypes.length; i++) {
+            ret.append(getDesc(parameterTypes[i]));
+        }
+        ret.append(')').append(getDesc(m.getReturnType()));
+        return ret.toString();
+    }
+
+    /**
+     * get class desc.
+     * Object.class => "Ljava/lang/Object;"
+     * boolean[].class => "[Z"
+     *
+     * @param c class.
+     * @return desc.
+     * @throws NotFoundException
+     */
+    public static String getDesc(final CtClass c) throws NotFoundException {
+        StringBuilder ret = new StringBuilder();
+        if (c.isArray()) {
+            ret.append('[');
+            ret.append(getDesc(c.getComponentType()));
+        } else if (c.isPrimitive()) {
+            String t = c.getName();
+            if ("void".equals(t)) {
+                ret.append(JVM_VOID);
+            } else if ("boolean".equals(t)) {
+                ret.append(JVM_BOOLEAN);
+            } else if ("byte".equals(t)) {
+                ret.append(JVM_BYTE);
+            } else if ("char".equals(t)) {
+                ret.append(JVM_CHAR);
+            } else if ("double".equals(t)) {
+                ret.append(JVM_DOUBLE);
+            } else if ("float".equals(t)) {
+                ret.append(JVM_FLOAT);
+            } else if ("int".equals(t)) {
+                ret.append(JVM_INT);
+            } else if ("long".equals(t)) {
+                ret.append(JVM_LONG);
+            } else if ("short".equals(t)) {
+                ret.append(JVM_SHORT);
+            }
+        } else {
+            ret.append('L');
+            ret.append(c.getName().replace('.', '/'));
+            ret.append(';');
+        }
+        return ret.toString();
+    }
+
+    /**
+     * get method desc.
+     * "do(I)I", "do()V", "do(Ljava/lang/String;Z)V"
+     *
+     * @param m method.
+     * @return desc.
+     */
+    public static String getDesc(final CtMethod m) throws NotFoundException {
+        StringBuilder ret = new StringBuilder(m.getName()).append('(');
+        CtClass[] parameterTypes = m.getParameterTypes();
+        for (int i = 0; i < parameterTypes.length; i++) {
+            ret.append(getDesc(parameterTypes[i]));
+        }
+        ret.append(')').append(getDesc(m.getReturnType()));
+        return ret.toString();
+    }
+
+    /**
+     * get constructor desc.
+     * "()V", "(Ljava/lang/String;I)V"
+     *
+     * @param c constructor.
+     * @return desc
+     */
+    public static String getDesc(final CtConstructor c) throws NotFoundException {
+        StringBuilder ret = new StringBuilder("(");
+        CtClass[] parameterTypes = c.getParameterTypes();
+        for (int i = 0; i < parameterTypes.length; i++) {
+            ret.append(getDesc(parameterTypes[i]));
+        }
+        ret.append(')').append('V');
+        return ret.toString();
+    }
+
+    /**
+     * get method desc.
+     * "(I)I", "()V", "(Ljava/lang/String;Z)V".
+     *
+     * @param m method.
+     * @return desc.
+     */
+    public static String getDescWithoutMethodName(final CtMethod m) throws NotFoundException {
+        StringBuilder ret = new StringBuilder();
+        ret.append('(');
+        CtClass[] parameterTypes = m.getParameterTypes();
+        for (int i = 0; i < parameterTypes.length; i++) {
+            ret.append(getDesc(parameterTypes[i]));
+        }
+        ret.append(')').append(getDesc(m.getReturnType()));
+        return ret.toString();
+    }
+
+    /**
+     * name to desc.
+     * java.util.Map[][] => "[[Ljava/util/Map;"
+     *
+     * @param name name.
+     * @return desc.
+     */
+    public static String name2desc(String name) {
+        StringBuilder sb = new StringBuilder();
+        int c = 0, index = name.indexOf('[');
+        if (index > 0) {
+            c = (name.length() - index) / 2;
+            name = name.substring(0, index);
+        }
+        while (c-- > 0) {
+            sb.append("[");
+        }
+        if ("void".equals(name)) {
+            sb.append(JVM_VOID);
+        } else if ("boolean".equals(name)) {
+            sb.append(JVM_BOOLEAN);
+        } else if ("byte".equals(name)) {
+            sb.append(JVM_BYTE);
+        } else if ("char".equals(name)) {
+            sb.append(JVM_CHAR);
+        } else if ("double".equals(name)) {
+            sb.append(JVM_DOUBLE);
+        } else if ("float".equals(name)) {
+            sb.append(JVM_FLOAT);
+        } else if ("int".equals(name)) {
+            sb.append(JVM_INT);
+        } else if ("long".equals(name)) {
+            sb.append(JVM_LONG);
+        } else if ("short".equals(name)) {
+            sb.append(JVM_SHORT);
+        } else {
+            sb.append('L').append(name.replace('.', '/')).append(';');
+        }
+        return sb.toString();
+    }
+
+    /**
+     * desc to name.
+     * "[[I" => "int[][]"
+     *
+     * @param desc desc.
+     * @return name.
+     */
+    public static String desc2name(String desc) {
+        StringBuilder sb = new StringBuilder();
+        int c = desc.lastIndexOf('[') + 1;
+        if (desc.length() == c + 1) {
+            switch (desc.charAt(c)) {
+                case JVM_VOID: {
+                    sb.append("void");
+                    break;
+                }
+                case JVM_BOOLEAN: {
+                    sb.append("boolean");
+                    break;
+                }
+                case JVM_BYTE: {
+                    sb.append("byte");
+                    break;
+                }
+                case JVM_CHAR: {
+                    sb.append("char");
+                    break;
+                }
+                case JVM_DOUBLE: {
+                    sb.append("double");
+                    break;
+                }
+                case JVM_FLOAT: {
+                    sb.append("float");
+                    break;
+                }
+                case JVM_INT: {
+                    sb.append("int");
+                    break;
+                }
+                case JVM_LONG: {
+                    sb.append("long");
+                    break;
+                }
+                case JVM_SHORT: {
+                    sb.append("short");
+                    break;
+                }
+                default:
+                    throw new RuntimeException();
+            }
+        } else {
+            sb.append(desc.substring(c + 1, desc.length() - 1).replace('/', '.'));
+        }
+        while (c-- > 0) {
+            sb.append("[]");
+        }
+        return sb.toString();
+    }
+
+    public static Class<?> forName(String name) {
+        try {
+            return name2class(name);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
+        }
+    }
+
+    public static Class<?> forName(ClassLoader cl, String name) {
+        try {
+            return name2class(cl, name);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalStateException("Not found class " + name + ", cause: " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * name to class.
+     * "boolean" => boolean.class
+     * "java.util.Map[][]" => java.util.Map[][].class
+     *
+     * @param name name.
+     * @return Class instance.
+     */
+    public static Class<?> name2class(String name) throws ClassNotFoundException {
+        return name2class(ClassUtils.getClassLoader(), name);
+    }
+
+    /**
+     * name to class.
+     * "boolean" => boolean.class
+     * "java.util.Map[][]" => java.util.Map[][].class
+     *
+     * @param cl   ClassLoader instance.
+     * @param name name.
+     * @return Class instance.
+     */
+    private static Class<?> name2class(ClassLoader cl, String name) throws ClassNotFoundException {
+        int c = 0, index = name.indexOf('[');
+        if (index > 0) {
+            c = (name.length() - index) / 2;
+            name = name.substring(0, index);
+        }
+        if (c > 0) {
+            StringBuilder sb = new StringBuilder();
+            while (c-- > 0) {
+                sb.append("[");
+            }
+
+            if ("void".equals(name)) {
+                sb.append(JVM_VOID);
+            } else if ("boolean".equals(name)) {
+                sb.append(JVM_BOOLEAN);
+            } else if ("byte".equals(name)) {
+                sb.append(JVM_BYTE);
+            } else if ("char".equals(name)) {
+                sb.append(JVM_CHAR);
+            } else if ("double".equals(name)) {
+                sb.append(JVM_DOUBLE);
+            } else if ("float".equals(name)) {
+                sb.append(JVM_FLOAT);
+            } else if ("int".equals(name)) {
+                sb.append(JVM_INT);
+            } else if ("long".equals(name)) {
+                sb.append(JVM_LONG);
+            } else if ("short".equals(name)) {
+                sb.append(JVM_SHORT);
+            } else {
+                sb.append('L').append(name).append(';'); // "java.lang.Object" ==> "Ljava.lang.Object;"
+            }
+            name = sb.toString();
+        } else {
+            if ("void".equals(name)) {
+                return void.class;
+            } else if ("boolean".equals(name)) {
+                return boolean.class;
+            } else if ("byte".equals(name)) {
+                return byte.class;
+            } else if ("char".equals(name)) {
+                return char.class;
+            } else if ("double".equals(name)) {
+                return double.class;
+            } else if ("float".equals(name)) {
+                return float.class;
+            } else if ("int".equals(name)) {
+                return int.class;
+            } else if ("long".equals(name)) {
+                return long.class;
+            } else if ("short".equals(name)) {
+                return short.class;
+            }
+        }
+
+        if (cl == null) {
+            cl = ClassUtils.getClassLoader();
+        }
+        Class<?> clazz = NAME_CLASS_CACHE.get(name);
+        if (clazz == null) {
+            clazz = Class.forName(name, true, cl);
+            NAME_CLASS_CACHE.put(name, clazz);
+        }
+        return clazz;
+    }
+
+    /**
+     * desc to class.
+     * "[Z" => boolean[].class
+     * "[[Ljava/util/Map;" => java.util.Map[][].class
+     *
+     * @param desc desc.
+     * @return Class instance.
+     * @throws ClassNotFoundException
+     */
+    public static Class<?> desc2class(String desc) throws ClassNotFoundException {
+        return desc2class(ClassUtils.getClassLoader(), desc);
+    }
+
+    /**
+     * desc to class.
+     * "[Z" => boolean[].class
+     * "[[Ljava/util/Map;" => java.util.Map[][].class
+     *
+     * @param cl   ClassLoader instance.
+     * @param desc desc.
+     * @return Class instance.
+     * @throws ClassNotFoundException
+     */
+    private static Class<?> desc2class(ClassLoader cl, String desc) throws ClassNotFoundException {
+        switch (desc.charAt(0)) {
+            case JVM_VOID:
+                return void.class;
+            case JVM_BOOLEAN:
+                return boolean.class;
+            case JVM_BYTE:
+                return byte.class;
+            case JVM_CHAR:
+                return char.class;
+            case JVM_DOUBLE:
+                return double.class;
+            case JVM_FLOAT:
+                return float.class;
+            case JVM_INT:
+                return int.class;
+            case JVM_LONG:
+                return long.class;
+            case JVM_SHORT:
+                return short.class;
+            case 'L':
+                desc = desc.substring(1, desc.length() - 1).replace('/', '.'); // "Ljava/lang/Object;" ==> "java.lang.Object"
+                break;
+            case '[':
+                desc = desc.replace('/', '.');  // "[[Ljava/lang/Object;" ==> "[[Ljava.lang.Object;"
+                break;
+            default:
+                throw new ClassNotFoundException("Class not found: " + desc);
+        }
+
+        if (cl == null) {
+            cl = ClassUtils.getClassLoader();
+        }
+        Class<?> clazz = DESC_CLASS_CACHE.get(desc);
+        if (clazz == null) {
+            clazz = Class.forName(desc, true, cl);
+            DESC_CLASS_CACHE.put(desc, clazz);
+        }
+        return clazz;
+    }
+
+    /**
+     * get class array instance.
+     *
+     * @param desc desc.
+     * @return Class class array.
+     * @throws ClassNotFoundException
+     */
+    public static Class<?>[] desc2classArray(String desc) throws ClassNotFoundException {
+        Class<?>[] ret = desc2classArray(ClassUtils.getClassLoader(), desc);
+        return ret;
+    }
+
+    /**
+     * get class array instance.
+     *
+     * @param cl   ClassLoader instance.
+     * @param desc desc.
+     * @return Class[] class array.
+     * @throws ClassNotFoundException
+     */
+    private static Class<?>[] desc2classArray(ClassLoader cl, String desc) throws ClassNotFoundException {
+        if (desc.length() == 0) {
+            return EMPTY_CLASS_ARRAY;
+        }
+
+        List<Class<?>> cs = new ArrayList<Class<?>>();
+        Matcher m = DESC_PATTERN.matcher(desc);
+        while (m.find()) {
+            cs.add(desc2class(cl, m.group()));
+        }
+        return cs.toArray(EMPTY_CLASS_ARRAY);
+    }
+
+    /**
+     * Find method from method signature
+     *
+     * @param clazz      Target class to find method
+     * @param methodName Method signature, e.g.: method1(int, String). It is allowed to provide method name only, e.g.: method2
+     * @return target method
+     * @throws NoSuchMethodException
+     * @throws ClassNotFoundException
+     * @throws IllegalStateException  when multiple methods are found (overridden method when parameter info is not provided)
+     */
+    public static Method findMethodByMethodSignature(Class<?> clazz, String methodName, String[] parameterTypes)
+            throws NoSuchMethodException, ClassNotFoundException {
+        String signature = clazz.getName() + "." + methodName;
+        if (parameterTypes != null && parameterTypes.length > 0) {
+            signature += StringUtils.join(parameterTypes);
+        }
+        Method method = Signature_METHODS_CACHE.get(signature);
+        if (method != null) {
+            return method;
+        }
+        if (parameterTypes == null) {
+            List<Method> finded = new ArrayList<Method>();
+            for (Method m : clazz.getMethods()) {
+                if (m.getName().equals(methodName)) {
+                    finded.add(m);
+                }
+            }
+            if (finded.isEmpty()) {
+                throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz);
+            }
+            if (finded.size() > 1) {
+                String msg = String.format("Not unique method for method name(%s) in class(%s), find %d methods.",
+                        methodName, clazz.getName(), finded.size());
+                throw new IllegalStateException(msg);
+            }
+            method = finded.get(0);
+        } else {
+            Class<?>[] types = new Class<?>[parameterTypes.length];
+            for (int i = 0; i < parameterTypes.length; i++) {
+                types[i] = ReflectUtils.name2class(parameterTypes[i]);
+            }
+            method = clazz.getMethod(methodName, types);
+
+        }
+        Signature_METHODS_CACHE.put(signature, method);
+        return method;
+    }
+
+    public static Method findMethodByMethodName(Class<?> clazz, String methodName)
+            throws NoSuchMethodException, ClassNotFoundException {
+        return findMethodByMethodSignature(clazz, methodName, null);
+    }
+
+    public static Constructor<?> findConstructor(Class<?> clazz, Class<?> paramType) throws NoSuchMethodException {
+        Constructor<?> targetConstructor;
+        try {
+            targetConstructor = clazz.getConstructor(new Class<?>[]{paramType});
+        } catch (NoSuchMethodException e) {
+            targetConstructor = null;
+            Constructor<?>[] constructors = clazz.getConstructors();
+            for (Constructor<?> constructor : constructors) {
+                if (Modifier.isPublic(constructor.getModifiers())
+                        && constructor.getParameterTypes().length == 1
+                        && constructor.getParameterTypes()[0].isAssignableFrom(paramType)) {
+                    targetConstructor = constructor;
+                    break;
+                }
+            }
+            if (targetConstructor == null) {
+                throw e;
+            }
+        }
+        return targetConstructor;
+    }
+
+    /**
+     * Check if one object is the implementation for a given interface.
+     * <p>
+     * This method will not trigger classloading for the given interface, therefore it will not lead to error when
+     * the given interface is not visible by the classloader
+     *
+     * @param obj                Object to examine
+     * @param interfaceClazzName The given interface
+     * @return true if the object implements the given interface, otherwise return false
+     */
+    public static boolean isInstance(Object obj, String interfaceClazzName) {
+        for (Class<?> clazz = obj.getClass();
+             clazz != null && !clazz.equals(Object.class);
+             clazz = clazz.getSuperclass()) {
+            Class<?>[] interfaces = clazz.getInterfaces();
+            for (Class<?> itf : interfaces) {
+                if (itf.getName().equals(interfaceClazzName)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static Object getEmptyObject(Class<?> returnType) {
+        return getEmptyObject(returnType, new HashMap<Class<?>, Object>(), 0);
+    }
+
+    private static Object getEmptyObject(Class<?> returnType, Map<Class<?>, Object> emptyInstances, int level) {
+        if (level > 2) {
+            return null;
+        }
+        if (returnType == null) {
+            return null;
+        } else if (returnType == boolean.class || returnType == Boolean.class) {
+            return false;
+        } else if (returnType == char.class || returnType == Character.class) {
+            return '\0';
+        } else if (returnType == byte.class || returnType == Byte.class) {
+            return (byte) 0;
+        } else if (returnType == short.class || returnType == Short.class) {
+            return (short) 0;
+        } else if (returnType == int.class || returnType == Integer.class) {
+            return 0;
+        } else if (returnType == long.class || returnType == Long.class) {
+            return 0L;
+        } else if (returnType == float.class || returnType == Float.class) {
+            return 0F;
+        } else if (returnType == double.class || returnType == Double.class) {
+            return 0D;
+        } else if (returnType.isArray()) {
+            return Array.newInstance(returnType.getComponentType(), 0);
+        } else if (returnType.isAssignableFrom(ArrayList.class)) {
+            return new ArrayList<Object>(0);
+        } else if (returnType.isAssignableFrom(HashSet.class)) {
+            return new HashSet<Object>(0);
+        } else if (returnType.isAssignableFrom(HashMap.class)) {
+            return new HashMap<Object, Object>(0);
+        } else if (String.class.equals(returnType)) {
+            return "";
+        } else if (!returnType.isInterface()) {
+            try {
+                Object value = emptyInstances.get(returnType);
+                if (value == null) {
+                    value = returnType.newInstance();
+                    emptyInstances.put(returnType, value);
+                }
+                Class<?> cls = value.getClass();
+                while (cls != null && cls != Object.class) {
+                    Field[] fields = cls.getDeclaredFields();
+                    for (Field field : fields) {
+                        if (field.isSynthetic()) {
+                            continue;
+                        }
+                        Object property = getEmptyObject(field.getType(), emptyInstances, level + 1);
+                        if (property != null) {
+                            try {
+                                if (!field.isAccessible()) {
+                                    field.setAccessible(true);
+                                }
+                                field.set(value, property);
+                            } catch (Throwable e) {
+                            }
+                        }
+                    }
+                    cls = cls.getSuperclass();
+                }
+                return value;
+            } catch (Throwable e) {
+                return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    public static boolean isBeanPropertyReadMethod(Method method) {
+        return method != null
+                && Modifier.isPublic(method.getModifiers())
+                && !Modifier.isStatic(method.getModifiers())
+                && method.getReturnType() != void.class
+                && method.getDeclaringClass() != Object.class
+                && method.getParameterTypes().length == 0
+                && ((method.getName().startsWith("get") && method.getName().length() > 3)
+                || (method.getName().startsWith("is") && method.getName().length() > 2));
+    }
+
+    public static String getPropertyNameFromBeanReadMethod(Method method) {
+        if (isBeanPropertyReadMethod(method)) {
+            if (method.getName().startsWith("get")) {
+                return method.getName().substring(3, 4).toLowerCase()
+                        + method.getName().substring(4);
+            }
+            if (method.getName().startsWith("is")) {
+                return method.getName().substring(2, 3).toLowerCase()
+                        + method.getName().substring(3);
+            }
+        }
+        return null;
+    }
+
+    public static boolean isBeanPropertyWriteMethod(Method method) {
+        return method != null
+                && Modifier.isPublic(method.getModifiers())
+                && !Modifier.isStatic(method.getModifiers())
+                && method.getDeclaringClass() != Object.class
+                && method.getParameterTypes().length == 1
+                && method.getName().startsWith("set")
+                && method.getName().length() > 3;
+    }
+
+    public static String getPropertyNameFromBeanWriteMethod(Method method) {
+        if (isBeanPropertyWriteMethod(method)) {
+            return method.getName().substring(3, 4).toLowerCase()
+                    + method.getName().substring(4);
+        }
+        return null;
+    }
+
+    public static boolean isPublicInstanceField(Field field) {
+        return Modifier.isPublic(field.getModifiers())
+                && !Modifier.isStatic(field.getModifiers())
+                && !Modifier.isFinal(field.getModifiers())
+                && !field.isSynthetic();
+    }
+
+    public static Map<String, Field> getBeanPropertyFields(Class cl) {
+        Map<String, Field> properties = new HashMap<String, Field>();
+        for (; cl != null; cl = cl.getSuperclass()) {
+            Field[] fields = cl.getDeclaredFields();
+            for (Field field : fields) {
+                if (Modifier.isTransient(field.getModifiers())
+                        || Modifier.isStatic(field.getModifiers())) {
+                    continue;
+                }
+
+                field.setAccessible(true);
+
+                properties.put(field.getName(), field);
+            }
+        }
+
+        return properties;
+    }
+
+    public static Map<String, Method> getBeanPropertyReadMethods(Class cl) {
+        Map<String, Method> properties = new HashMap<String, Method>();
+        for (; cl != null; cl = cl.getSuperclass()) {
+            Method[] methods = cl.getDeclaredMethods();
+            for (Method method : methods) {
+                if (isBeanPropertyReadMethod(method)) {
+                    method.setAccessible(true);
+                    String property = getPropertyNameFromBeanReadMethod(method);
+                    properties.put(property, method);
+                }
+            }
+        }
+
+        return properties;
+    }
+
+    public static Type[] getReturnTypes(Method method) {
+        Class<?> returnType = method.getReturnType();
+        Type genericReturnType = method.getGenericReturnType();
+        if (Future.class.isAssignableFrom(returnType)) {
+            if (genericReturnType instanceof ParameterizedType) {
+                Type actualArgType = ((ParameterizedType) genericReturnType).getActualTypeArguments()[0];
+                if (actualArgType instanceof ParameterizedType) {
+                    returnType = (Class<?>) ((ParameterizedType) actualArgType).getRawType();
+                    genericReturnType = actualArgType;
+                } else {
+                    returnType = (Class<?>) actualArgType;
+                    genericReturnType = returnType;
+                }
+            } else {
+                returnType = null;
+                genericReturnType = null;
+            }
+        }
+        return new Type[]{returnType, genericReturnType};
+    }
+  
+    /**
+     * Find the {@link Set} of {@link ParameterizedType}
+     *
+     * @param sourceClass the source {@link Class class}
+     * @return non-null read-only {@link Set}
+     * @since 2.7.3
+     */
+    public static Set<ParameterizedType> findParameterizedTypes(Class<?> sourceClass) {
+        // Add Generic Interfaces
+        List<Type> genericTypes = new LinkedList<>(asList(sourceClass.getGenericInterfaces()));
+        // Add Generic Super Class
+        genericTypes.add(sourceClass.getGenericSuperclass());
+
+        Set<ParameterizedType> parameterizedTypes = genericTypes.stream()
+                .filter(type -> type instanceof ParameterizedType)// filter ParameterizedType
+                .map(type -> ParameterizedType.class.cast(type))  // cast to ParameterizedType
+                .collect(Collectors.toSet());
+
+        if (parameterizedTypes.isEmpty()) { // If not found, try to search super types recursively
+            genericTypes.stream()
+                    .filter(type -> type instanceof Class)
+                    .map(type -> Class.class.cast(type))
+                    .forEach(superClass -> {
+                        parameterizedTypes.addAll(findParameterizedTypes(superClass));
+                    });
+        }
+
+        return unmodifiableSet(parameterizedTypes);                     // build as a Set
+
+    }
+
+    /**
+     * Find the hierarchical types form the source {@link Class class} by specified {@link Class type}.
+     *
+     * @param sourceClass the source {@link Class class}
+     * @param matchType   the type to match
+     * @param <T>         the type to match
+     * @return non-null read-only {@link Set}
+     * @since 2.7.3
+     */
+    public static <T> Set<Class<T>> findHierarchicalTypes(Class<?> sourceClass, Class<T> matchType) {
+        if (sourceClass == null) {
+            return Collections.emptySet();
+        }
+
+        Set<Class<T>> hierarchicalTypes = new LinkedHashSet<>();
+
+        if (matchType.isAssignableFrom(sourceClass)) {
+            hierarchicalTypes.add((Class<T>) sourceClass);
+        }
+
+        // Find all super classes
+        hierarchicalTypes.addAll(findHierarchicalTypes(sourceClass.getSuperclass(), matchType));
+
+        return unmodifiableSet(hierarchicalTypes);
+    }
 }
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
index 56e73cb..548c48f 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
@@ -30,19 +30,19 @@ import java.util.stream.Collectors;
 import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
 import static org.apache.dubbo.common.constants.CommonConstants.CLASSIFIER_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
 import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SPLIT_PATTERN;
 import static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
-import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
 import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
 import static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;
 import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
similarity index 69%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
index c5bc722..3e6296b 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultPageTest.java
@@ -14,24 +14,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.api;
+package org.apache.dubbo.common.utils;
+
+import org.junit.jupiter.api.Test;
 
 import java.util.List;
 
+import static java.util.Arrays.asList;
 
 /**
- * DemoService
+ * {@link DefaultPage}
+ *
+ * @since 2.7.3
  */
-public interface DemoService {
-
-    String sayName(String name);
-
-    Box getBox();
-
-    void throwDemoException() throws DemoException;
-
-    List<User> getUsers(List<User> users);
-
-    int echo(int i);
-
-}
\ No newline at end of file
+public class DefaultPageTest {
+
+    @Test
+    public void test() {
+        List<Integer> data = asList(1, 2, 3, 4, 5);
+        DefaultPage page = new DefaultPage(0, 1, data.subList(0, 1), data.size());
+    }
+}
diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/filter/LegacyInvocation.java b/dubbo-compatible/src/test/java/org/apache/dubbo/filter/LegacyInvocation.java
index a98f22e..cd1cc17 100644
--- a/dubbo-compatible/src/test/java/org/apache/dubbo/filter/LegacyInvocation.java
+++ b/dubbo-compatible/src/test/java/org/apache/dubbo/filter/LegacyInvocation.java
@@ -23,11 +23,11 @@ import com.alibaba.dubbo.rpc.Invoker;
 import java.util.HashMap;
 import java.util.Map;
 
-import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
 import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
 
 /**
diff --git a/dubbo-config/dubbo-config-api/pom.xml b/dubbo-config/dubbo-config-api/pom.xml
index 3a4584d..b8f5938 100644
--- a/dubbo-config/dubbo-config-api/pom.xml
+++ b/dubbo-config/dubbo-config-api/pom.xml
@@ -14,7 +14,8 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.apache.dubbo</groupId>
@@ -64,6 +65,13 @@
             <artifactId>dubbo-filter-cache</artifactId>
             <version>${project.parent.version}</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-metadata</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+
         <!-- FIXME, we shouldn't rely on these modules, even in test scope -->
         <dependency>
             <groupId>org.apache.dubbo</groupId>
@@ -71,17 +79,55 @@
             <version>${project.parent.version}</version>
             <scope>test</scope>
         </dependency>
+
         <dependency>
             <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo-remoting-netty4</artifactId>
             <version>${project.parent.version}</version>
             <scope>test</scope>
         </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-rpc-dubbo</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+
         <dependency>
             <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo-registry-multicast</artifactId>
             <version>${project.parent.version}</version>
             <scope>test</scope>
         </dependency>
+
+        <!-- Zookeeper Registry -->
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-registry-zookeeper</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- Zookeeper configcenter -->
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-configcenter-zookeeper</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-serialization-hessian2</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-test</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
index b725608..8130a5f 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
@@ -53,31 +53,30 @@ import java.util.Map;
 import java.util.Set;
 
 import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties;
-import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_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.COMMA_SPLIT_PATTERN;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
 import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
+import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
 import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
 import static org.apache.dubbo.config.Constants.LAYER_KEY;
 import static org.apache.dubbo.config.Constants.LISTENER_KEY;
-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.config.Constants.REGISTRIES_SUFFIX;
-import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY;
 import static org.apache.dubbo.monitor.Constants.LOGSTAT_PROTOCOL;
+import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
 import static org.apache.dubbo.registry.Constants.REGISTER_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
 import static org.apache.dubbo.registry.Constants.SUBSCRIBE_KEY;
 import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
 import static org.apache.dubbo.rpc.Constants.INVOKER_LISTENER_KEY;
@@ -86,7 +85,8 @@ import static org.apache.dubbo.rpc.Constants.PROXY_KEY;
 import static org.apache.dubbo.rpc.Constants.REFERENCE_FILTER_KEY;
 import static org.apache.dubbo.rpc.Constants.RETURN_PREFIX;
 import static org.apache.dubbo.rpc.Constants.THROW_PREFIX;
-import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
+import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
 
 /**
  * AbstractDefaultConfig
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java
index 47c035e..309f907 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java
@@ -19,6 +19,8 @@ package org.apache.dubbo.config;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.event.DubboServiceDestroyedEvent;
+import org.apache.dubbo.event.EventDispatcher;
 import org.apache.dubbo.registry.support.AbstractRegistryFactory;
 import org.apache.dubbo.rpc.Protocol;
 
@@ -42,7 +44,9 @@ public class DubboShutdownHook extends Thread {
     /**
      * Has it already been destroyed or not?
      */
-    private final AtomicBoolean destroyed= new AtomicBoolean(false);
+    private final AtomicBoolean destroyed = new AtomicBoolean(false);
+
+    private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
 
     private DubboShutdownHook(String name) {
         super(name);
@@ -89,6 +93,8 @@ public class DubboShutdownHook extends Thread {
         AbstractRegistryFactory.destroyAll();
         // destroy all the protocols
         destroyProtocols();
+        // dispatch the DubboDestroyedEvent @since 2.7.3
+        eventDispatcher.dispatch(new DubboServiceDestroyedEvent(this));
     }
 
     /**
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java
index c3dcf0c..18c4d17 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java
@@ -32,12 +32,12 @@ import org.apache.dubbo.rpc.Protocol;
 
 import java.util.Map;
 
-import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
 import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
 import static org.apache.dubbo.config.Constants.PROTOCOLS_SUFFIX;
-import static org.apache.dubbo.remoting.Constants.TELNET;
 import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
+import static org.apache.dubbo.remoting.Constants.TELNET;
 
 /**
  * ProtocolConfig
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index a3c020c..ee2e9b6 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
@@ -1,664 +1,691 @@
-/*
- * 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(), convertMethodConfig2AyncInfo(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.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.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.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.3
+     */
+    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();
+        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;
+
+        // dispatch a ReferenceConfigDestroyedEvent since 2.7.3
+        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));
+            }
+        }
+
+        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;
+
+        // dispatch a ReferenceConfigInitializedEvent since 2.7.3
+        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
+         */
+        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.");
+                }
+            }
+        }
+    }
+
+    /**
+     * Dispatch an {@link Event event}
+     *
+     * @param event an {@link Event event}
+     * @since 2.7.3
+     */
+    protected void dispatch(Event event) {
+        eventDispatcher.dispatch(event);
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
index 83f56b1..c9a96cb 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
@@ -23,11 +23,11 @@ import org.apache.dubbo.remoting.Constants;
 import java.util.Map;
 
 import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
-import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
+import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
+import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
 import static org.apache.dubbo.config.Constants.ZOOKEEPER_PROTOCOL;
 import static org.apache.dubbo.registry.Constants.EXTRA_KEYS_KEY;
 
diff --git 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
index 257d2a1..cc1138a 100644
--- 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,1054 +1,1081 @@
-/*
- * 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 == null || 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.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.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.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.DUBBO_IP_TO_BIND;
+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.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.PROTOCOLS_SUFFIX;
+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.3
+     */
+    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 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();
+
+        // dispatch a ServiceConfigExportedEvent since 2.7.3
+        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.3
+        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
+                 */
+                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 == null || 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;
+    }
+
+    /**
+     * Dispatch an {@link Event event}
+     *
+     * @param event an {@link Event event}
+     * @since 2.7.3
+     */
+    protected void dispatch(Event event) {
+        eventDispatcher.dispatch(event);
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java
index d1e33c6..12d09bf 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java
@@ -25,9 +25,11 @@ import java.util.Map;
 /**
  * AbstractBuilder
  *
+ * @param <C> The type of {@link AbstractConfig Config}
+ * @param <B> The type of {@link AbstractBuilder Builder}
  * @since 2.7
  */
-public abstract class AbstractBuilder<T extends AbstractConfig, B extends AbstractBuilder> {
+public abstract class AbstractBuilder<C extends AbstractConfig, B extends AbstractBuilder> {
     /**
      * The config id
      */
@@ -62,7 +64,7 @@ public abstract class AbstractBuilder<T extends AbstractConfig, B extends Abstra
         return parameters;
     }
 
-    protected void build(T instance) {
+    protected void build(C instance) {
         if (!StringUtils.isEmpty(id)) {
             instance.setId(id);
         }
@@ -70,4 +72,11 @@ public abstract class AbstractBuilder<T extends AbstractConfig, B extends Abstra
             instance.setPrefix(prefix);
         }
     }
+
+    /**
+     * Build an instance of {@link AbstractConfig config}
+     *
+     * @return an instance of {@link AbstractConfig config}
+     */
+    public abstract C build();
 }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ProtocolBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ProtocolBuilder.java
index 42e5550..4ddd943 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ProtocolBuilder.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ProtocolBuilder.java
@@ -185,6 +185,10 @@ public class ProtocolBuilder extends AbstractBuilder<ProtocolConfig, ProtocolBui
      */
     private Boolean isDefault;
 
+    public ProtocolBuilder id(String id) {
+        return super.id(id);
+    }
+
     public ProtocolBuilder name(String name) {
         this.name = name;
         return getThis();
@@ -206,9 +210,9 @@ public class ProtocolBuilder extends AbstractBuilder<ProtocolConfig, ProtocolBui
     }
 
     /**
-     * @see org.apache.dubbo.config.builders.ProtocolBuilder#contextpath(String)
      * @param path
      * @return ProtocolBuilder
+     * @see org.apache.dubbo.config.builders.ProtocolBuilder#contextpath(String)
      */
     @Deprecated
     public ProtocolBuilder path(String path) {
@@ -297,9 +301,9 @@ public class ProtocolBuilder extends AbstractBuilder<ProtocolConfig, ProtocolBui
     }
 
     /**
-     * @see org.apache.dubbo.config.builders.ProtocolBuilder#dispatcher(String)
      * @param dispather
      * @return ProtocolBuilder
+     * @see org.apache.dubbo.config.builders.ProtocolBuilder#dispatcher(String)
      */
     @Deprecated
     public ProtocolBuilder dispather(String dispather) {
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ReferenceBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ReferenceBuilder.java
index d0df602..52ceb94 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ReferenceBuilder.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ReferenceBuilder.java
@@ -64,6 +64,10 @@ public class ReferenceBuilder<T> extends AbstractReferenceBuilder<ReferenceConfi
      */
     private String protocol;
 
+    public ReferenceBuilder<T> id(String id) {
+        return super.id(id);
+    }
+
     public ReferenceBuilder<T> interfaceName(String interfaceName) {
         this.interfaceName = interfaceName;
         return getThis();
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/RegistryBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/RegistryBuilder.java
index f64e595..616e6af 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/RegistryBuilder.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/RegistryBuilder.java
@@ -16,10 +16,10 @@
  */
 package org.apache.dubbo.config.builders;
 
-import java.util.Map;
-
 import org.apache.dubbo.config.RegistryConfig;
 
+import java.util.Map;
+
 /**
  * This is a builder for build {@link RegistryConfig}.
  *
@@ -134,6 +134,10 @@ public class RegistryBuilder extends AbstractBuilder<RegistryConfig, RegistryBui
      */
     private String extraKeys;
 
+    public RegistryBuilder id(String id) {
+        return super.id(id);
+    }
+
     public RegistryBuilder address(String address) {
         this.address = address;
         return getThis();
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ServiceBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ServiceBuilder.java
index 6628d3a..65cc916 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ServiceBuilder.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/ServiceBuilder.java
@@ -16,13 +16,13 @@
  */
 package org.apache.dubbo.config.builders;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import org.apache.dubbo.config.MethodConfig;
 import org.apache.dubbo.config.ProviderConfig;
 import org.apache.dubbo.config.ServiceConfig;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * This is a builder for build {@link ServiceConfig}.
  *
@@ -68,6 +68,10 @@ public class ServiceBuilder<U> extends AbstractServiceBuilder<ServiceConfig, Ser
      */
     private String generic;
 
+    public ServiceBuilder id(String id) {
+        return super.id(id);
+    }
+
     public ServiceBuilder<U> interfaceName(String interfaceName) {
         this.interfaceName = interfaceName;
         return getThis();
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/DubboServiceDestroyedEvent.java
similarity index 71%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/DubboServiceDestroyedEvent.java
index c5bc722..a3384aa 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/DubboServiceDestroyedEvent.java
@@ -14,24 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.api;
-
-import java.util.List;
+package org.apache.dubbo.config.event;
 
+import org.apache.dubbo.event.Event;
 
 /**
- * DemoService
+ * An {@link Event Dubbo event} when the Dubbo service is about to be destroyed.
+ *
+ * @see Event
+ * @since 2.7.3
  */
-public interface DemoService {
-
-    String sayName(String name);
-
-    Box getBox();
-
-    void throwDemoException() throws DemoException;
-
-    List<User> getUsers(List<User> users);
-
-    int echo(int i);
+public class DubboServiceDestroyedEvent extends Event {
 
-}
\ No newline at end of file
+    public DubboServiceDestroyedEvent(Object source) {
+        super(source);
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigDestroyedEvent.java
similarity index 56%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigDestroyedEvent.java
index c5bc722..8f07e51 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigDestroyedEvent.java
@@ -14,24 +14,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.api;
-
-import java.util.List;
+package org.apache.dubbo.config.event;
 
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.annotation.Reference;
+import org.apache.dubbo.event.Event;
 
 /**
- * DemoService
+ * The {@link ReferenceConfig Dubbo service ReferenceConfig} destroyed {@link Event event}
+ *
+ * @see Reference
+ * @see ReferenceConfig#destroy()
+ * @see Event
+ * @since 2.7.3
  */
-public interface DemoService {
-
-    String sayName(String name);
-
-    Box getBox();
-
-    void throwDemoException() throws DemoException;
+public class ReferenceConfigDestroyedEvent extends Event {
 
-    List<User> getUsers(List<User> users);
+    public ReferenceConfigDestroyedEvent(ReferenceConfig referenceConfig) {
+        super(referenceConfig);
+    }
 
-    int echo(int i);
+    public ReferenceConfig getReferenceConfig() {
+        return (ReferenceConfig) getSource();
+    }
 
 }
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/provider/impl/DemoServiceImpl.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigInitializedEvent.java
similarity index 50%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/provider/impl/DemoServiceImpl.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigInitializedEvent.java
index d81269e..359c8bc 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/provider/impl/DemoServiceImpl.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ReferenceConfigInitializedEvent.java
@@ -14,38 +14,35 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.provider.impl;
+package org.apache.dubbo.config.event;
 
-import org.apache.dubbo.config.api.Box;
-import org.apache.dubbo.config.api.DemoException;
-import org.apache.dubbo.config.api.DemoService;
-import org.apache.dubbo.config.api.User;
-
-import java.util.List;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.annotation.Reference;
+import org.apache.dubbo.event.Event;
+import org.apache.dubbo.rpc.Invoker;
 
 /**
- * DemoServiceImpl
+ * The {@link ReferenceConfig Dubbo service ReferenceConfig} initialized {@link Event event}
+ *
+ * @see Reference
+ * @see ReferenceConfig#get()
+ * @see Event
+ * @since 2.7.3
  */
-public class DemoServiceImpl implements DemoService {
-
-    public String sayName(String name) {
-        return "say:" + name;
-    }
+public class ReferenceConfigInitializedEvent extends Event {
 
-    public Box getBox() {
-        return null;
-    }
+    private final Invoker<?> invoker;
 
-    public void throwDemoException() throws DemoException {
-        throw new DemoException("DemoServiceImpl");
+    public ReferenceConfigInitializedEvent(ReferenceConfig referenceConfig, Invoker<?> invoker) {
+        super(referenceConfig);
+        this.invoker = invoker;
     }
 
-    public List<User> getUsers(List<User> users) {
-        return users;
+    public ReferenceConfig getReferenceConfig() {
+        return (ReferenceConfig) getSource();
     }
 
-    public int echo(int i) {
-        return i;
+    public Invoker<?> getInvoker() {
+        return invoker;
     }
-
-}
\ No newline at end of file
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigExportedEvent.java
similarity index 63%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigExportedEvent.java
index c5bc722..ebf15f3 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigExportedEvent.java
@@ -14,24 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.api;
-
-import java.util.List;
+package org.apache.dubbo.config.event;
 
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.event.Event;
 
 /**
- * DemoService
+ * {@link ServiceConfig} event post-{@link ServiceConfig#export() export}
+ *
+ * @since 2.7.3
  */
-public interface DemoService {
-
-    String sayName(String name);
-
-    Box getBox();
-
-    void throwDemoException() throws DemoException;
-
-    List<User> getUsers(List<User> users);
+public class ServiceConfigExportedEvent extends Event {
 
-    int echo(int i);
+    public ServiceConfigExportedEvent(ServiceConfig source) {
+        super(source);
+    }
 
-}
\ No newline at end of file
+    public ServiceConfig getServiceConfig() {
+        return (ServiceConfig) getSource();
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigUnexportedEvent.java
similarity index 63%
copy from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigUnexportedEvent.java
index c5bc722..15bd3e5 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/api/DemoService.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/ServiceConfigUnexportedEvent.java
@@ -14,24 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.api;
-
-import java.util.List;
+package org.apache.dubbo.config.event;
 
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.event.Event;
 
 /**
- * DemoService
+ * {@link ServiceConfig} event post-{@link ServiceConfig#unexport() unexport}
+ *
+ * @since 2.7.3
  */
-public interface DemoService {
-
-    String sayName(String name);
-
-    Box getBox();
-
-    void throwDemoException() throws DemoException;
-
-    List<User> getUsers(List<User> users);
+public class ServiceConfigUnexportedEvent extends Event {
 
-    int echo(int i);
+    public ServiceConfigUnexportedEvent(ServiceConfig source) {
+        super(source);
+    }
 
-}
\ No newline at end of file
+    public ServiceConfig getServiceConfig() {
+        return (ServiceConfig) getSource();
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/LoggingEventListener.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/LoggingEventListener.java
new file mode 100644
index 0000000..661c3d7
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/LoggingEventListener.java
@@ -0,0 +1,51 @@
+/*
+ * 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.event.listener;
+
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.event.DubboServiceDestroyedEvent;
+import org.apache.dubbo.config.event.ServiceConfigExportedEvent;
+import org.apache.dubbo.event.Event;
+import org.apache.dubbo.event.GenericEventListener;
+
+import static java.lang.String.format;
+
+/**
+ * A listener for logging the {@link Event Dubbo event}
+ *
+ * @see ServiceConfigExportedEvent
+ * @since 2.7.3
+ */
+public class LoggingEventListener extends GenericEventListener {
+
+    private static final String NAME = "Dubbo Service";
+
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+
+    public void onEvent(DubboServiceDestroyedEvent event) {
+        if (logger.isInfoEnabled()) {
+            logger.info(NAME + " has been destroyed.");
+        }
+    }
+
+    private void debug(String pattern, Object... args) {
+        if (logger.isDebugEnabled()) {
+            logger.debug(format(pattern, args));
+        }
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/ServiceNameMappingListener.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/ServiceNameMappingListener.java
new file mode 100644
index 0000000..bef416a
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/event/listener/ServiceNameMappingListener.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.event.listener;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.event.ServiceConfigExportedEvent;
+import org.apache.dubbo.event.EventListener;
+import org.apache.dubbo.metadata.ServiceNameMapping;
+
+import java.util.List;
+
+import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+import static org.apache.dubbo.metadata.ServiceNameMapping.getDefaultExtension;
+
+/**
+ * An {@link EventListener event listener} for mapping {@link ServiceConfig#getExportedUrls() the exported Dubbo
+ * service inerface} to its service name
+ *
+ * @see ServiceNameMapping
+ * @see ServiceConfig#getExportedUrls()
+ * @since 2.7.3
+ */
+public class ServiceNameMappingListener implements EventListener<ServiceConfigExportedEvent> {
+
+    private final ServiceNameMapping serviceNameMapping = getDefaultExtension();
+
+    @Override
+    public void onEvent(ServiceConfigExportedEvent event) {
+        ServiceConfig serviceConfig = event.getServiceConfig();
+        List<URL> exportedURLs = serviceConfig.getExportedUrls();
+        exportedURLs.forEach(url -> {
+            String serviceInterface = url.getServiceInterface();
+            String group = url.getParameter(GROUP_KEY);
+            String version = url.getParameter(VERSION_KEY);
+            String protocol = url.getProtocol();
+            serviceNameMapping.map(serviceInterface, group, version, protocol);
+        });
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java
new file mode 100644
index 0000000..ac36f9e
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporter.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.metadata;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.metadata.LocalMetadataService;
+import org.apache.dubbo.metadata.MetadataService;
+import org.apache.dubbo.metadata.MetadataServiceExporter;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import static java.util.Collections.unmodifiableList;
+
+/**
+ * {@link MetadataServiceExporter} implementation based on {@link AbstractConfig Dubbo configurations}, the clients
+ * should make sure the {@link ApplicationConfig}, {@link RegistryConfig} and {@link ProtocolConfig} are ready before
+ * {@link #export()}.
+ * <p>
+ * Typically, do not worry about their ready status, because they are initialized before
+ * any {@link ServiceConfig} exports, or The Dubbo export will be failed.
+ *
+ * @see MetadataServiceExporter
+ * @see ServiceConfig
+ * @see ConfigManager
+ * @since 2.7.3
+ */
+public class ConfigurableMetadataServiceExporter implements MetadataServiceExporter {
+
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+
+    private volatile ServiceConfig<MetadataService> serviceConfig;
+
+    private ApplicationConfig applicationConfig;
+
+    private List<RegistryConfig> registries = new LinkedList<>();
+
+    private List<ProtocolConfig> protocols = new LinkedList<>();
+
+    public void setApplicationConfig(ApplicationConfig applicationConfig) {
+        this.applicationConfig = applicationConfig;
+    }
+
+    public void setRegistries(Collection<RegistryConfig> registries) {
+        this.registries.clear();
+        this.registries.addAll(registries);
+    }
+
+    public void setProtocols(Collection<ProtocolConfig> protocols) {
+        this.protocols.clear();
+        this.protocols.addAll(protocols);
+    }
+
+    @Override
+    public List<URL> export() {
+
+        if (!isExported()) {
+
+            LocalMetadataService metadataService = LocalMetadataService.getDefaultExtension();
+
+            ServiceConfig<MetadataService> serviceConfig = new ServiceConfig<>();
+            serviceConfig.setApplication(applicationConfig);
+            serviceConfig.setRegistries(registries);
+            serviceConfig.setProtocols(protocols);
+            serviceConfig.setInterface(MetadataService.class);
+            serviceConfig.setRef(metadataService);
+            serviceConfig.setGroup(getApplicationConfig().getName());
+            serviceConfig.setVersion(metadataService.version());
+
+            // export
... 9935 lines suppressed ...