You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2021/09/14 02:17:28 UTC

[dubbo] branch 3.0 updated: [3.0] Multi instance - multi module config/deploy and spring support (#8789)

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

albumenj pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.0 by this push:
     new 5c2161a  [3.0] Multi instance - multi module config/deploy and spring support (#8789)
5c2161a is described below

commit 5c2161aa0e9a073a51dd14e0c0edb36668d371a8
Author: Gong Dewei <ky...@qq.com>
AuthorDate: Tue Sep 14 10:17:07 2021 +0800

    [3.0] Multi instance - multi module config/deploy and spring support (#8789)
    
    * Add spring support for multi instance
    
    * Fix testMultiModuleApplication
    
    * polish ApplicationModel and so on
    
    * destroy application when all module are removed
    
    * Extract ApplicationDeployer and ModuleDeployer, add ModuleConfigManager, add spring support for module manage
    
    * Fix ut
    
    * Initialize SpringExtensionInjector
    
    * Fix DubboHealthIndicatorTest
    
    * Fix SpringExtensionInjector avoid using not completed Spring ApplicationContext
    
    * Prepare application instance before refer services, fix SpringXmlConfigTest
    
    * App index starts from 1 in each FrameworkModel
    
    * Add ConfigScopeModelInitializer, Refactor DubboShutdownHook
    
    * Register bean with class is change to getOrRegisterBean
    
    * Fix ShutdownTelnetTest
    
    * Fix missing dependency
    
    * Fix not found ApplicationModel bean in spring context
    
    * Add module deploy and reload test
    
    * Put deployer to scope model attributes
    
    * Add getDeployer() to ApplicationModel/ModuleModel
---
 .../cluster/router/tag/TagDynamicStateRouter.java  |   10 +-
 .../cluster/router/tag/TagStaticStateRouter.java   |   11 +-
 .../dubbo/rpc/cluster/merger/ResultMergerTest.java |    1 -
 .../support/AbstractClusterInvokerTest.java        |    1 -
 .../rpc/cluster/support/ClusterUtilsTest.java      |    1 -
 .../dubbo/common/CommonScopeModelInitializer.java  |    2 +
 .../common/beans/factory/ScopeBeanFactory.java     |   37 +-
 .../beans/factory/ScopeBeanFactoryInitializer.java |   75 -
 .../beans/support/InstantiationStrategy.java       |   16 +-
 .../dubbo/common/bytecode/ClassGenerator.java      |    7 +-
 .../apache/dubbo/common/config/ReferenceCache.java |   38 +-
 .../file/FileSystemDynamicConfiguration.java       |   38 +-
 .../dubbo/common/deploy/ApplicationDeployer.java   |   34 +-
 .../apache/dubbo/common/deploy/ModuleDeployer.java |   35 +-
 .../dubbo/common/lang/ShutdownHookCallbacks.java   |   10 +-
 .../manager/DefaultExecutorRepository.java         |    4 +-
 .../org/apache/dubbo/config/AbstractConfig.java    |   22 +-
 .../dubbo/config/AbstractInterfaceConfig.java      |    9 +-
 .../apache/dubbo/config/AbstractMethodConfig.java  |    5 +
 .../apache/dubbo/config/ReferenceConfigBase.java   |   12 +-
 .../org/apache/dubbo/config/ServiceConfigBase.java |   19 +-
 .../config/context/AbstractConfigManager.java      |  527 ++++++
 .../apache/dubbo/config/context/ConfigManager.java |  549 +------
 .../dubbo/config/context/ConfigValidator.java      |   19 +-
 .../dubbo/config/context/ModuleConfigManager.java  |  264 +++
 .../apache/dubbo/rpc/model/ApplicationModel.java   |   62 +-
 .../org/apache/dubbo/rpc/model/FrameworkModel.java |   26 +-
 ...ModelPostProcessor.java => ModelConstants.java} |   15 +-
 .../org/apache/dubbo/rpc/model/ModuleModel.java    |   27 +-
 .../org/apache/dubbo/rpc/model/ScopeModel.java     |   73 +-
 .../compiler/support/AdaptiveCompilerTest.java     |    1 -
 .../common/extension/ExtensionDirectorTest.java    |    1 -
 .../extension/support/ActivateComparatorTest.java  |    1 -
 .../common/lang/ShutdownHookCallbacksTest.java     |    3 +-
 .../dubbo/common/logger/LoggerFactoryTest.java     |    1 -
 .../apache/dubbo/common/utils/ConfigUtilsTest.java |    1 -
 ...sInterfaceDisplayNameHasMetaCharactersTest.java |    6 +-
 .../dubbo/config/context/ConfigManagerTest.java    |   50 +-
 .../dubbo/config/ConfigScopeModelInitializer.java  |   23 +-
 .../org/apache/dubbo/config/DubboShutdownHook.java |   35 +-
 .../org/apache/dubbo/config/ReferenceConfig.java   |   33 +-
 .../org/apache/dubbo/config/ServiceConfig.java     |   83 +-
 .../config/bootstrap/BootstrapTakeoverMode.java    |    2 +-
 .../bootstrap/DefaultApplicationDeployer.java      |  941 +++++++++++
 .../config/bootstrap/DefaultModuleDeployer.java    |  345 ++++
 .../dubbo/config/bootstrap/DubboBootstrap.java     | 1733 ++++----------------
 .../config/bootstrap/ModuleDeployListener.java     |   21 +-
 .../ConfigurableMetadataServiceExporter.java       |    2 -
 .../config/utils/CompositeReferenceCache.java      |  109 ++
 .../dubbo/config/utils/DefaultConfigValidator.java |   59 +
 ...eConfigCache.java => SimpleReferenceCache.java} |  164 +-
 ...rg.apache.dubbo.rpc.model.ScopeModelInitializer |    1 +
 .../apache/dubbo/config/AbstractConfigTest.java    |    1 -
 .../dubbo/config/ConfigCenterConfigTest.java       |    1 -
 .../apache/dubbo/config/ConsumerConfigTest.java    |    9 +-
 .../apache/dubbo/config/ReferenceConfigTest.java   |   28 +-
 .../bootstrap/DubboBootstrapMultiInstanceTest.java |  174 +-
 .../dubbo/config/bootstrap/DubboBootstrapTest.java |   20 +-
 .../ServiceInstanceHostPortCustomizerTest.java     |    1 -
 .../dubbo/config/utils/MockReferenceConfig.java    |    1 +
 ...onfigCacheTest.java => ReferenceCacheTest.java} |   37 +-
 .../dubbo/config/utils/XxxMockReferenceConfig.java |    1 +
 ...egistryCenterExportProviderIntegrationTest.java |    2 -
 ...MultipleRegistryCenterInjvmIntegrationTest.java |    9 +-
 ...terServiceDiscoveryRegistryIntegrationTest.java |    7 +-
 ...RegistryCenterDubboProtocolIntegrationTest.java |    4 +-
 ...egistryCenterExportProviderIntegrationTest.java |    2 -
 .../SingleRegistryCenterInjvmIntegrationTest.java  |    7 +-
 .../dubbo/config/spring/ConfigCenterBean.java      |    3 -
 .../apache/dubbo/config/spring/ReferenceBean.java  |   16 +-
 .../apache/dubbo/config/spring/ServiceBean.java    |   10 +-
 .../context/DubboBootstrapApplicationListener.java |   28 +-
 .../DubboBootstrapServletContextListener.java      |   58 -
 .../spring/context/DubboConfigBeanInitializer.java |   42 +-
 .../DubboInfraBeanRegisterPostProcessor.java       |   11 +-
 .../context/DubboSpringInitializationContext.java  |   74 +
 .../DubboSpringInitializationCustomizer.java       |    6 +-
 .../spring/context/DubboSpringInitializer.java     |  131 +-
 .../context/event/DubboAnnotationInitedEvent.java  |   11 +-
 .../spring/extension/SpringExtensionInjector.java  |   86 +-
 .../spring/reference/ReferenceBeanManager.java     |    8 +-
 .../spring/schema/DubboNamespaceHandler.java       |    3 +-
 .../spring/status/DataSourceStatusChecker.java     |   26 +-
 .../config/spring/status/SpringStatusChecker.java  |   55 +-
 .../dubbo/config/spring/util/DubboBeanUtils.java   |   58 +-
 .../org/apache/dubbo/config/spring/ConfigTest.java |   35 +-
 .../dubbo/config/spring/JavaConfigBeanTest.java    |    6 +-
 .../annotation/MethodConfigCallbackTest.java       |    4 +-
 .../configprops/SpringBootConfigPropsTest.java     |   10 +-
 .../SpringBootMultipleConfigPropsTest.java         |   10 +-
 .../DubboComponentScanRegistrarTest.java           |    5 +-
 .../extension/SpringExtensionInjectorTest.java     |   55 +-
 .../config/spring/impl/MethodCallbackImpl.java     |    3 +-
 .../spring/issues/issue7003/Issue7003Test.java     |    3 +-
 .../consumer/PropertyConfigurerTest.java           |    5 -
 .../consumer2/PropertySourcesConfigurerTest.java   |    6 +-
 .../consumer3/PropertySourcesInJavaConfigTest.java |    9 -
 .../javaconfig/JavaConfigReferenceBeanTest.java    |   22 -
 .../spring/schema/DubboNamespaceHandlerTest.java   |    4 +-
 .../config/spring/schema/GenericServiceTest.java   |   10 +-
 .../schema/GenericServiceWithoutInterfaceTest.java |    6 +-
 .../spring/status/DataSourceStatusCheckerTest.java |    5 +-
 .../spring/status/SpringStatusCheckerTest.java     |   37 +-
 .../dubbo/container/spring/SpringContainer.java    |    1 -
 .../apache/dubbo/demo/consumer/Application.java    |    3 +-
 .../dubbo/demo/consumer/GenericApplication.java    |    3 +-
 .../dubbo/demo/graalvm/consumer/Application.java   |    3 +-
 dubbo-metadata/dubbo-metadata-processor/pom.xml    |   10 +-
 .../dubbo/monitor/dubbo/MetricsFilterTest.java     |   17 +-
 .../dubbo/auth/AccessKeyAuthenticatorTest.java     |    1 -
 .../dubbo/auth/filter/ConsumerSignFilterTest.java  |    1 -
 .../dubbo/auth/filter/ProviderAuthFilterTest.java  |    1 -
 .../dubbo/qos/command/impl/ShutdownTelnet.java     |    6 +-
 .../dubbo/qos/command/impl/ShutdownTelnetTest.java |    5 +-
 .../legacy/service/generic/GenericServiceTest.java |    6 +-
 .../registry/client/DefaultServiceInstance.java    |    3 +-
 .../client/FileSystemServiceDiscovery.java         |    8 +-
 .../metadata/ServiceInstanceMetadataUtils.java     |    3 +-
 .../SpringCloudMetadataServiceURLBuilder.java      |    3 +-
 .../store/InMemoryWritableMetadataService.java     |    3 +-
 .../client/migration/model/MigrationRule.java      |    1 -
 .../registry/integration/RegistryProtocol.java     |    2 +-
 .../registry/CacheableFallbackRegistryTest.java    |    1 -
 .../client/ServiceDiscoveryRegistryTest.java       |    1 -
 .../metadata/MetadataServiceNameMappingTest.java   |    1 -
 .../client/metadata/MetadataUtilsTest.java         |    1 -
 .../ProtocolPortsMetadataCustomizerTest.java       |    7 +-
 .../store/InMemoryMetadataServiceTest.java         |    1 -
 .../client/migration/model/MigrationRuleTest.java  |    1 -
 .../registry/dns/DNSServiceDiscoveryTest.java      |    3 +-
 .../apache/dubbo/registry/nacos/NacosRegistry.java |   17 +-
 .../nacos/util/NacosNamingServiceUtils.java        |   13 +-
 .../apache/dubbo/registry/xds/util/XdsChannel.java |    9 +-
 .../zookeeper/ZookeeperServiceDiscovery.java       |    5 +-
 .../ZookeeperServiceDiscoveryChangeWatcher.java    |    3 +-
 .../org/apache/dubbo/remoting/api/Connection.java  |   17 +-
 .../dubbo/remoting/api/PortUnificationServer.java  |   17 +-
 .../remoting/api/PortUnificationServerHandler.java |    3 +-
 .../org/apache/dubbo/remoting/api/SslContexts.java |   11 +-
 .../apache/dubbo/remoting/api/WireProtocol.java    |    5 +-
 .../apache/dubbo/remoting/api/EmptyProtocol.java   |    3 +-
 .../remoting/transport/netty4/NettyClient.java     |   21 +-
 .../org/apache/dubbo/rpc/filter/GenericFilter.java |    7 +-
 .../org/apache/dubbo/rpc/support/MockInvoker.java  |    3 +-
 .../apache/dubbo/rpc/support/MockInvokerTest.java  |    1 -
 .../dubbo/decode/DubboTelnetDecodeTest.java        |    7 +-
 .../dubbo/rpc/protocol/grpc/GrpcOptionsUtils.java  |   19 +-
 .../dubbo/rpc/protocol/grpc/GrpcProtocolTest.java  |    9 +-
 .../rpc/protocol/tri/AbstractServerStream.java     |    3 +-
 .../apache/dubbo/rpc/protocol/tri/GrpcStatus.java  |    6 +-
 .../tri/TripleHttp2FrameServerHandler.java         |   23 +-
 .../rpc/protocol/tri/TripleHttp2Protocol.java      |   15 +-
 .../dubbo/rpc/protocol/tri/TripleInvoker.java      |    3 +-
 .../dubbo/rpc/protocol/tri/UnaryClientStream.java  |    8 +-
 .../dubbo/rpc/protocol/tri/UnaryServerStream.java  |    3 +-
 .../rpc/protocol/tri/service/TriHealthImpl.java    |    1 -
 .../serialize/hessian2/Hessian2ObjectInput.java    |    3 +-
 .../serialize/hessian2/Hessian2ObjectOutput.java   |    3 +-
 .../endpoint/metadata/DubboShutdownMetadata.java   |    6 +-
 .../boot/actuate/health/DubboHealthIndicator.java  |   11 +-
 .../event/AwaitingNonWebApplicationListener.java   |   19 +-
 .../AwaitingNonWebApplicationListenerTest.java     |   45 +-
 .../test/spring/SpringJavaConfigBeanTest.java      |   14 +-
 163 files changed, 4120 insertions(+), 3038 deletions(-)

diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagDynamicStateRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagDynamicStateRouter.java
index 5a6dadc..85e7d76 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagDynamicStateRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagDynamicStateRouter.java
@@ -16,11 +16,6 @@
  */
 package org.apache.dubbo.rpc.cluster.router.tag;
 
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
 import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
@@ -41,6 +36,11 @@ import org.apache.dubbo.rpc.cluster.router.state.RouterCache;
 import org.apache.dubbo.rpc.cluster.router.tag.model.TagRouterRule;
 import org.apache.dubbo.rpc.cluster.router.tag.model.TagRuleParser;
 
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
 import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
 import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
 import static org.apache.dubbo.rpc.Constants.FORCE_USE_TAG;
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagStaticStateRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagStaticStateRouter.java
index 8ede3c1..6e29ba7 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagStaticStateRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagStaticStateRouter.java
@@ -16,11 +16,6 @@
  */
 package org.apache.dubbo.rpc.cluster.router.tag;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.CollectionUtils;
 import org.apache.dubbo.common.utils.StringUtils;
@@ -31,6 +26,12 @@ import org.apache.dubbo.rpc.cluster.RouterChain;
 import org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;
 import org.apache.dubbo.rpc.cluster.router.state.BitList;
 import org.apache.dubbo.rpc.cluster.router.state.RouterCache;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
 import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
 
 /**
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/merger/ResultMergerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/merger/ResultMergerTest.java
index ef921bb..e49ac1f 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/merger/ResultMergerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/merger/ResultMergerTest.java
@@ -17,7 +17,6 @@
 package org.apache.dubbo.rpc.cluster.merger;
 
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java
index a621371..0c3dec7 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java
@@ -33,7 +33,6 @@ import org.apache.dubbo.rpc.cluster.filter.DemoService;
 import org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance;
 import org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance;
 import org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance;
-
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
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 8e897df..7cf23b3 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
@@ -19,7 +19,6 @@ package org.apache.dubbo.rpc.cluster.support;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.URLBuilder;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java b/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java
index 8caab81..4ac60c6 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.common;
 
 import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
+import org.apache.dubbo.common.lang.ShutdownHookCallbacks;
 import org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
@@ -32,6 +33,7 @@ public class CommonScopeModelInitializer implements ScopeModelInitializer {
     @Override
     public void initializeApplicationModel(ApplicationModel applicationModel) {
         ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
+        beanFactory.registerBean(ShutdownHookCallbacks.class);
         beanFactory.registerBean(FrameworkStatusReportService.class);
     }
 
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java
index e417591..21a8232 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java
@@ -65,10 +65,14 @@ public class ScopeBeanFactory {
     }
 
     public <T> T registerBean(Class<T> bean) throws ScopeBeanException {
-        return this.registerBean(null, bean);
+        return this.getOrRegisterBean(null, bean);
     }
 
     public <T> T registerBean(String name, Class<T> clazz) throws ScopeBeanException {
+        return getOrRegisterBean(name, clazz);
+    }
+
+    private <T> T createAndRegisterBean(String name, Class<T> clazz) {
         T instance = getBean(name, clazz);
         if (instance != null) {
             throw new ScopeBeanException("already exists bean with same name and type, name=" + name + ", type=" + clazz.getName());
@@ -76,7 +80,7 @@ public class ScopeBeanFactory {
         try {
             instance = instantiationStrategy.instantiate(clazz);
         } catch (Throwable e) {
-            throw new ScopeBeanException("create bean instance failed, type=" + clazz.getName());
+            throw new ScopeBeanException("create bean instance failed, type=" + clazz.getName(), e);
         }
         registerBean(name, instance);
         return instance;
@@ -101,23 +105,23 @@ public class ScopeBeanFactory {
         registeredBeanInfos.add(new BeanInfo(name, bean));
     }
 
-    public <T> T registerBeanIfAbsent(Class<T> type) {
-        return registerBeanIfAbsent(null, type);
+    public <T> T getOrRegisterBean(Class<T> type) {
+        return getOrRegisterBean(null, type);
     }
 
-    public <T> T registerBeanIfAbsent(String name, Class<T> type) {
+    public <T> T getOrRegisterBean(String name, Class<T> type) {
         T bean = getBean(name, type);
         if (bean == null) {
-            bean = registerBean(name, type);
+            bean = createAndRegisterBean(name, type);
         }
         return bean;
     }
 
-    public <T> T registerBeanIfAbsent(Class<T> type, Function<? super Class<T>, ? extends T> mappingFunction) {
-        return registerBeanIfAbsent(null, type, mappingFunction);
+    public <T> T getOrRegisterBean(Class<T> type, Function<? super Class<T>, ? extends T> mappingFunction) {
+        return getOrRegisterBean(null, type, mappingFunction);
     }
 
-    public <T> T registerBeanIfAbsent(String name, Class<T> type, Function<? super Class<T>, ? extends T> mappingFunction) {
+    public <T> T getOrRegisterBean(String name, Class<T> type, Function<? super Class<T>, ? extends T> mappingFunction) {
         T bean = getBean(name, type);
         if (bean == null) {
             //TODO add lock for type
@@ -177,16 +181,23 @@ public class ScopeBeanFactory {
             return null;
         }
         List<BeanInfo> candidates = null;
+        BeanInfo firstCandidate = null;
         for (BeanInfo beanInfo : registeredBeanInfos) {
             // if required bean type is same class/superclass/interface of the registered bean
             if (type.isAssignableFrom(beanInfo.instance.getClass())) {
                 if (StringUtils.isEquals(beanInfo.name, name)) {
                     return (T) beanInfo.instance;
                 } else {
-                    if (candidates == null) {
-                        candidates = new ArrayList<>();
+                    // optimize for only one matched bean
+                    if (firstCandidate == null) {
+                        firstCandidate = beanInfo;
+                    } else {
+                        if (candidates == null) {
+                            candidates = new ArrayList<>();
+                            candidates.add(firstCandidate);
+                        }
+                        candidates.add(beanInfo);
                     }
-                    candidates.add(beanInfo);
                 }
             }
         }
@@ -199,6 +210,8 @@ public class ScopeBeanFactory {
                 List<String> candidateBeanNames = candidates.stream().map(beanInfo -> beanInfo.name).collect(Collectors.toList());
                 throw new ScopeBeanException("expected single matching bean but found " + candidates.size() + " candidates for type [" + type.getName() + "]: " + candidateBeanNames);
             }
+        } else if (firstCandidate != null) {
+            return (T) firstCandidate.instance;
         }
         return null;
     }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactoryInitializer.java b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactoryInitializer.java
deleted file mode 100644
index 07ced8d..0000000
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactoryInitializer.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.beans.factory;
-
-import org.apache.dubbo.rpc.model.ApplicationModel;
-import org.apache.dubbo.rpc.model.FrameworkModel;
-import org.apache.dubbo.rpc.model.ModuleModel;
-import org.apache.dubbo.rpc.model.ScopeModel;
-import org.apache.dubbo.rpc.model.ScopeModelPostProcessor;
-
-/**
- * Initialize the bean factory for ScopeModel
- */
-public abstract class ScopeBeanFactoryInitializer implements ScopeModelPostProcessor {
-
-    @Override
-    public void postProcessScopeModel(ScopeModel scopeModel) {
-        if (scopeModel instanceof ApplicationModel) {
-            ApplicationModel applicationModel = (ApplicationModel) scopeModel;
-            registerApplicationBeans(applicationModel, applicationModel.getBeanFactory());
-        } else if (scopeModel instanceof FrameworkModel) {
-            FrameworkModel frameworkModel = (FrameworkModel) scopeModel;
-            registerFrameworkBeans(frameworkModel, frameworkModel.getBeanFactory());
-        } else if (scopeModel instanceof ModuleModel) {
-            ModuleModel moduleModel = (ModuleModel) scopeModel;
-            registerModuleBeans(moduleModel, moduleModel.getBeanFactory());
-        }
-    }
-
-    /**
-     * Initialize beans for framework
-     *
-     * @param frameworkModel
-     * @param beanFactory
-     */
-    protected void registerFrameworkBeans(FrameworkModel frameworkModel, ScopeBeanFactory beanFactory) {
-
-    }
-
-    /**
-     * Initialize beans for application
-     *
-     * @param applicationModel
-     * @param beanFactory
-     */
-    protected void registerApplicationBeans(ApplicationModel applicationModel, ScopeBeanFactory beanFactory) {
-//        beanFactory.registerBean(MetadataReportInstance.class);
-//        beanFactory.registerBean(RemoteMetadataServiceImpl.class);
-    }
-
-    /**
-     * Initialize beans for module
-     *
-     * @param moduleModel
-     * @param beanFactory
-     */
-    protected void registerModuleBeans(ModuleModel moduleModel, ScopeBeanFactory beanFactory) {
-
-    }
-
-}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/support/InstantiationStrategy.java b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/support/InstantiationStrategy.java
index 5e1fea3..b1b67ce 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/support/InstantiationStrategy.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/support/InstantiationStrategy.java
@@ -61,12 +61,9 @@ public class InstantiationStrategy {
         List<Constructor> matchedConstructors = new ArrayList<>();
         Constructor<?>[] declaredConstructors = type.getConstructors();
         for (Constructor<?> constructor : declaredConstructors) {
-            for (Class<?> parameterType : constructor.getParameterTypes()) {
-                if (!isSupportedConstructorParameterType(parameterType)) {
-                    break;
-                }
+            if (isMatched(constructor)) {
+                matchedConstructors.add(constructor);
             }
-            matchedConstructors.add(constructor);
         }
         if (matchedConstructors.size() > 1) {
             throw new IllegalArgumentException("Expect only one but found " +
@@ -86,6 +83,15 @@ public class InstantiationStrategy {
         return (T) constructor.newInstance(args);
     }
 
+    private boolean isMatched(Constructor<?> constructor) {
+        for (Class<?> parameterType : constructor.getParameterTypes()) {
+            if (!isSupportedConstructorParameterType(parameterType)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private boolean isSupportedConstructorParameterType(Class<?> parameterType) {
         return ScopeModel.class.isAssignableFrom(parameterType);
     }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
index ed2ff6b..182b4de 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
@@ -16,10 +16,6 @@
  */
 package org.apache.dubbo.common.bytecode;
 
-import org.apache.dubbo.common.utils.ArrayUtils;
-import org.apache.dubbo.common.utils.ReflectUtils;
-import org.apache.dubbo.common.utils.StringUtils;
-
 import javassist.CannotCompileException;
 import javassist.ClassPool;
 import javassist.CtClass;
@@ -29,6 +25,9 @@ import javassist.CtMethod;
 import javassist.CtNewConstructor;
 import javassist.CtNewMethod;
 import javassist.NotFoundException;
+import org.apache.dubbo.common.utils.ArrayUtils;
+import org.apache.dubbo.common.utils.ReflectUtils;
+import org.apache.dubbo.common.utils.StringUtils;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/api/EmptyProtocol.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ReferenceCache.java
similarity index 54%
copy from dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/api/EmptyProtocol.java
copy to dubbo-common/src/main/java/org/apache/dubbo/common/config/ReferenceCache.java
index 7d3b5cf..a7f23d9 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/test/java/org/apache/dubbo/remoting/api/EmptyProtocol.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ReferenceCache.java
@@ -14,31 +14,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.remoting.api;
+package org.apache.dubbo.common.config;
 
-import org.apache.dubbo.common.URL;
+import org.apache.dubbo.config.ReferenceConfigBase;
 
-import io.netty.channel.ChannelPipeline;
-import io.netty.handler.ssl.SslContext;
+import java.util.List;
 
-public class EmptyProtocol implements WireProtocol {
-    @Override
-    public ProtocolDetector detector() {
-        return null;
-    }
+public interface ReferenceCache {
+    @SuppressWarnings("unchecked")
+    <T> T get(ReferenceConfigBase<T> referenceConfig);
 
-    @Override
-    public void configServerPipeline(URL url, ChannelPipeline pipeline,SslContext sslContext) {
+    @SuppressWarnings("unchecked")
+    <T> T get(String key, Class<T> type);
 
-    }
+    @SuppressWarnings("unchecked")
+    <T> T get(String key);
 
-    @Override
-    public void configClientPipeline(URL url, ChannelPipeline pipeline, SslContext sslContext) {
+    @SuppressWarnings("unchecked")
+    <T> List<T> getAll(Class<T> type);
 
-    }
+    @SuppressWarnings("unchecked")
+    <T> T get(Class<T> type);
 
-    @Override
-    public void close() {
+    void destroy(String key, Class<?> type);
 
-    }
+    void destroy(Class<?> type);
+
+    <T> void destroy(ReferenceConfigBase<T> referenceConfig);
+
+    void destroyAll();
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java
index a41d711..2dcf71d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java
@@ -16,6 +16,9 @@
  */
 package org.apache.dubbo.common.config.configcenter.file;
 
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
 import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
@@ -27,10 +30,8 @@ import org.apache.dubbo.common.function.ThrowableFunction;
 import org.apache.dubbo.common.lang.ShutdownHookCallbacks;
 import org.apache.dubbo.common.utils.NamedThreadFactory;
 import org.apache.dubbo.common.utils.StringUtils;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.apache.dubbo.rpc.model.ScopeModel;
+import org.apache.dubbo.rpc.model.ScopeModelUtil;
 
 import java.io.File;
 import java.io.IOException;
@@ -54,6 +55,7 @@ import java.util.TreeSet;
 import java.util.concurrent.Callable;
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -147,7 +149,6 @@ public class FileSystemDynamicConfiguration extends TreePathDynamicConfiguration
         MODIFIERS = initWatchEventModifiers();
         DELAY = initDelay(MODIFIERS);
         WATCH_EVENTS_LOOP_THREAD_POOL = newWatchEventsLoopThreadPool();
-        registerDubboShutdownHook();
     }
 
     /**
@@ -168,6 +169,8 @@ public class FileSystemDynamicConfiguration extends TreePathDynamicConfiguration
     private final Set<File> processingDirectories;
 
     private final Map<File, List<ConfigurationListener>> listenersRepository;
+    private ScopeModel scopeModel;
+    private AtomicBoolean hasRegisteredShutdownHook = new AtomicBoolean();
 
     public FileSystemDynamicConfiguration() {
         this(new File(DEFAULT_CONFIG_CENTER_DIR_PATH));
@@ -199,11 +202,26 @@ public class FileSystemDynamicConfiguration extends TreePathDynamicConfiguration
         this.encoding = encoding;
         this.processingDirectories = initProcessingDirectories();
         this.listenersRepository = new LinkedHashMap<>();
+        registerDubboShutdownHook();
+    }
+
+    public FileSystemDynamicConfiguration(File rootDirectory, String encoding,
+                                          String threadPoolPrefixName,
+                                          int threadPoolSize,
+                                          long keepAliveTime,
+                                          ScopeModel scopeModel) {
+        super(rootDirectory.getAbsolutePath(), threadPoolPrefixName, threadPoolSize, keepAliveTime, DEFAULT_GROUP, -1L);
+        this.rootDirectory = rootDirectory;
+        this.encoding = encoding;
+        this.processingDirectories = initProcessingDirectories();
+        this.listenersRepository = new LinkedHashMap<>();
+        this.scopeModel = scopeModel;
+        registerDubboShutdownHook();
     }
 
     public FileSystemDynamicConfiguration(URL url) {
         this(initDirectory(url), getEncoding(url), getThreadPoolPrefixName(url), getThreadPoolSize(url),
-                getThreadPoolKeepAliveTime(url));
+                getThreadPoolKeepAliveTime(url), url.getScopeModel());
     }
 
     private Set<File> initProcessingDirectories() {
@@ -237,8 +255,12 @@ public class FileSystemDynamicConfiguration extends TreePathDynamicConfiguration
      *
      * @since 2.7.8
      */
-    private static void registerDubboShutdownHook() {
-        ShutdownHookCallbacks.INSTANCE.addCallback(() -> {
+    private void registerDubboShutdownHook() {
+        if (!hasRegisteredShutdownHook.compareAndSet(false, true)) {
+            return;
+        }
+        ShutdownHookCallbacks shutdownHookCallbacks = ScopeModelUtil.getApplicationModel(scopeModel).getBeanFactory().getBean(ShutdownHookCallbacks.class);
+        shutdownHookCallbacks.addCallback(() -> {
             watchService.ifPresent(w -> {
                 try {
                     w.close();
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ApplicationDeployer.java
similarity index 57%
copy from dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java
copy to dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ApplicationDeployer.java
index 08a5e09..7c2a04a 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ApplicationDeployer.java
@@ -14,23 +14,35 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.spring.context;
+package org.apache.dubbo.common.deploy;
 
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.apache.dubbo.common.config.ReferenceCache;
+import org.apache.dubbo.common.context.Lifecycle;
+import org.apache.dubbo.rpc.model.ApplicationModel;
 
 /**
- * Dubbo spring initialization context object
+ * initialize and start application instance
  */
-public class DubboSpringInitializationContext {
+public interface ApplicationDeployer extends Lifecycle {
 
-    private BeanDefinitionRegistry registry;
+    void initialize();
 
-    public BeanDefinitionRegistry getRegistry() {
-        return registry;
-    }
+    void start();
 
-    void setRegistry(BeanDefinitionRegistry registry) {
-        this.registry = registry;
-    }
+    void prepareApplicationInstance();
+
+    void destroy();
+
+    boolean isInitialized();
+
+    boolean isStarted();
+
+    boolean isStartup();
+
+    boolean isShutdown();
+
+    ApplicationModel getApplicationModel();
+
+    ReferenceCache getReferenceCache();
 
 }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ModuleDeployer.java
similarity index 55%
copy from dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java
copy to dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ModuleDeployer.java
index 08a5e09..16f0161 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ModuleDeployer.java
@@ -14,23 +14,36 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.spring.context;
+package org.apache.dubbo.common.deploy;
 
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.apache.dubbo.common.config.ReferenceCache;
+import org.apache.dubbo.config.ServiceConfigBase;
+
+import java.util.concurrent.CompletableFuture;
 
 /**
- * Dubbo spring initialization context object
+ * Export/refer services of module
  */
-public class DubboSpringInitializationContext {
+public interface ModuleDeployer {
+
+    void initialize() throws IllegalStateException;
+
+    CompletableFuture start() throws IllegalStateException;
+
+    void destroy() throws IllegalStateException;
+
+    boolean isStartup();
+
+    boolean isInitialized();
+
+    boolean isExportBackground();
+
+    boolean isReferBackground();
 
-    private BeanDefinitionRegistry registry;
+    ReferenceCache getReferenceCache();
 
-    public BeanDefinitionRegistry getRegistry() {
-        return registry;
-    }
+    void prepare();
 
-    void setRegistry(BeanDefinitionRegistry registry) {
-        this.registry = registry;
-    }
+    void notifyExportService(ServiceConfigBase<?> sc);
 
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java b/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java
index e1d01a2..da3f6a7 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/lang/ShutdownHookCallbacks.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.common.lang;
 
 import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.rpc.model.ApplicationModel;
 
 import java.util.Collection;
 import java.util.LinkedList;
@@ -32,11 +33,12 @@ import static org.apache.dubbo.common.function.ThrowableAction.execute;
  */
 public class ShutdownHookCallbacks {
 
-    public static final ShutdownHookCallbacks INSTANCE = new ShutdownHookCallbacks();
-
     private final List<ShutdownHookCallback> callbacks = new LinkedList<>();
 
-    ShutdownHookCallbacks() {
+    private ApplicationModel applicationModel;
+
+    public ShutdownHookCallbacks(ApplicationModel applicationModel) {
+        this.applicationModel = applicationModel;
         loadCallbacks();
     }
 
@@ -62,7 +64,7 @@ public class ShutdownHookCallbacks {
 
     private void loadCallbacks() {
         ExtensionLoader<ShutdownHookCallback> loader =
-                ExtensionLoader.getExtensionLoader(ShutdownHookCallback.class);
+                applicationModel.getExtensionLoader(ShutdownHookCallback.class);
         loader.getSupportedExtensionInstances().forEach(this::addCallback);
     }
 
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/DefaultExecutorRepository.java b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/DefaultExecutorRepository.java
index 5c93b23..bf63c38 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/DefaultExecutorRepository.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/DefaultExecutorRepository.java
@@ -233,7 +233,7 @@ public class DefaultExecutorRepository implements ExecutorRepository, ExtensionA
     }
 
     private Integer getExportThreadNum() {
-        List<Integer> threadNum = ApplicationModel.ofNullable(applicationModel).getApplicationConfigManager().getProviders()
+        List<Integer> threadNum = ApplicationModel.ofNullable(applicationModel).getDefaultModule().getConfigManager().getProviders()
             .stream()
             .map(ProviderConfig::getExportThreadNum)
             .filter(k -> k != null && k > 0)
@@ -280,7 +280,7 @@ public class DefaultExecutorRepository implements ExecutorRepository, ExtensionA
     }
 
     private Integer getReferThreadNum() {
-        List<Integer> threadNum = ApplicationModel.ofNullable(applicationModel).getApplicationConfigManager().getConsumers()
+        List<Integer> threadNum = ApplicationModel.ofNullable(applicationModel).getDefaultModule().getConfigManager().getConsumers()
             .stream()
             .map(ConsumerConfig::getReferThreadNum)
             .filter(k -> k != null && k > 0)
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
index dc57114..3b4be54 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
@@ -338,20 +338,10 @@ public abstract class AbstractConfig implements Serializable {
     public final void setScopeModel(ScopeModel scopeModel) {
         if (this.scopeModel != scopeModel) {
             checkScopeModel(scopeModel);
-            // remove this config from current ConfigManager
             ScopeModel oldScopeModel = this.scopeModel;
-            if (oldScopeModel != null) {
-                boolean removed = getConfigManager().removeConfig(this);
-                // change scope model and add it into new ConfigManager
-                this.scopeModel = scopeModel;
-                if (removed) {
-                    getConfigManager().addConfig(this);
-                }
-            }else {
-                this.scopeModel = scopeModel;
-            }
+            this.scopeModel = scopeModel;
             // reinitialize spi extension and change referenced config's scope model
-            this.postProcessAfterScopeModelChanged();
+            this.postProcessAfterScopeModelChanged(oldScopeModel, this.scopeModel);
         }
     }
 
@@ -379,8 +369,14 @@ public abstract class AbstractConfig implements Serializable {
      *   }
      * }
      * </pre>
+     * @param oldScopeModel
+     * @param newScopeModel
      */
-    protected void postProcessAfterScopeModelChanged() {
+    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {
+        // remove this config from old ConfigManager
+//        if (oldScopeModel != null && oldScopeModel instanceof ApplicationModel) {
+//           ((ApplicationModel)oldScopeModel).getApplicationConfigManager().removeConfig(this);
+//        }
     }
 
     protected <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
index 48de804..feb504a 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
@@ -29,6 +29,7 @@ import org.apache.dubbo.common.utils.ReflectUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.support.Parameter;
 import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.ScopeModel;
 import org.apache.dubbo.rpc.model.ScopeModelUtil;
 import org.apache.dubbo.rpc.model.ServiceMetadata;
 
@@ -205,8 +206,12 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
     }
 
     @Override
-    protected void postProcessAfterScopeModelChanged() {
-        super.postProcessAfterScopeModelChanged();
+    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {
+        super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);
+        // remove this config from old ConfigManager
+//        if (oldScopeModel != null && oldScopeModel instanceof ModuleModel) {
+//            ((ModuleModel)oldScopeModel).getConfigManager().removeConfig(this);
+//        }
 
         // change referenced config's scope model
         ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(scopeModel);
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractMethodConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractMethodConfig.java
index e8b2f41..5bdb5cb 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractMethodConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractMethodConfig.java
@@ -16,6 +16,7 @@
  */
 package org.apache.dubbo.config;
 
+import org.apache.dubbo.config.context.ModuleConfigManager;
 import org.apache.dubbo.config.support.Parameter;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.ModuleModel;
@@ -117,6 +118,10 @@ public abstract class AbstractMethodConfig extends AbstractConfig {
         }
     }
 
+    protected ModuleConfigManager getModuleConfigManager() {
+        return getScopeModel().getConfigManager();
+    }
+
     public Integer getForks() {
         return forks;
     }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java
index b573b02..77c3f73 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.common.utils.RegexProperties;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.annotation.Reference;
 import org.apache.dubbo.config.support.Parameter;
+import org.apache.dubbo.rpc.model.ScopeModel;
 import org.apache.dubbo.rpc.model.ServiceMetadata;
 import org.apache.dubbo.rpc.service.GenericService;
 import org.apache.dubbo.rpc.support.ProtocolUtils;
@@ -114,7 +115,7 @@ public abstract class ReferenceConfigBase<T> extends AbstractReferenceConfig {
     protected void preProcessRefresh() {
         super.preProcessRefresh();
         if (consumer == null) {
-            consumer = getConfigManager()
+            consumer = getModuleConfigManager()
                     .getDefaultConsumer()
                     .orElseThrow(() -> new IllegalArgumentException("Default consumer is not initialized"));
         }
@@ -211,8 +212,8 @@ public abstract class ReferenceConfigBase<T> extends AbstractReferenceConfig {
     }
 
     @Override
-    protected void postProcessAfterScopeModelChanged() {
-        super.postProcessAfterScopeModelChanged();
+    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {
+        super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);
         if (this.consumer != null && this.consumer.getScopeModel() != scopeModel) {
             this.consumer.setScopeModel(scopeModel);
         }
@@ -346,7 +347,8 @@ public abstract class ReferenceConfigBase<T> extends AbstractReferenceConfig {
 
     public abstract T get();
 
-    public abstract void destroy();
-
+    public void destroy() {
+        getModuleConfigManager().removeConfig(this);
+    }
 
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java
index cbce529..8694be3 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java
@@ -21,6 +21,7 @@ import org.apache.dubbo.common.utils.CollectionUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.annotation.Service;
 import org.apache.dubbo.config.support.Parameter;
+import org.apache.dubbo.rpc.model.ScopeModel;
 import org.apache.dubbo.rpc.model.ServiceMetadata;
 import org.apache.dubbo.rpc.service.GenericService;
 import org.apache.dubbo.rpc.support.ProtocolUtils;
@@ -105,8 +106,8 @@ public abstract class ServiceConfigBase<T> extends AbstractServiceConfig {
     }
 
     @Override
-    protected void postProcessAfterScopeModelChanged() {
-        super.postProcessAfterScopeModelChanged();
+    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {
+        super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);
         if (this.provider != null && this.provider.getScopeModel() != scopeModel) {
             this.provider.setScopeModel(scopeModel);
         }
@@ -206,7 +207,7 @@ public abstract class ServiceConfigBase<T> extends AbstractServiceConfig {
         super.preProcessRefresh();
         convertProviderIdToProvider();
         if (provider == null) {
-            provider = getConfigManager()
+            provider = getModuleConfigManager()
                     .getDefaultProvider()
                     .orElseThrow(() -> new IllegalArgumentException("Default provider is not initialized"));
         }
@@ -254,7 +255,7 @@ public abstract class ServiceConfigBase<T> extends AbstractServiceConfig {
 
     protected void convertProviderIdToProvider() {
         if (provider == null && StringUtils.hasText(providerIds)) {
-            provider = getConfigManager().getProvider(providerIds)
+            provider = getModuleConfigManager().getProvider(providerIds)
                     .orElseThrow(() -> new IllegalStateException("Provider config not found: " + providerIds));
         }
     }
@@ -346,7 +347,7 @@ public abstract class ServiceConfigBase<T> extends AbstractServiceConfig {
     }
 
     public void setProvider(ProviderConfig provider) {
-        getConfigManager().addProvider(provider);
+        getModuleConfigManager().addProvider(provider);
         this.provider = provider;
     }
 
@@ -446,8 +447,16 @@ public abstract class ServiceConfigBase<T> extends AbstractServiceConfig {
         return shouldExportAsync;
     }
 
+    /**
+     * export service and auto start application instance
+     */
     public abstract void export();
 
+    /**
+     * export service only, do not register application instance, for exporting services in batches by module
+     */
+    public abstract void exportOnly();
+
     public abstract void unexport();
 
     public abstract boolean isExported();
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
new file mode 100644
index 0000000..f7a4320
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
@@ -0,0 +1,527 @@
+/*
+ * 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.context;
+
+import org.apache.dubbo.common.config.ConfigurationUtils;
+import org.apache.dubbo.common.config.Environment;
+import org.apache.dubbo.common.config.PropertiesConfiguration;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.context.LifecycleAdapter;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.ConcurrentHashSet;
+import org.apache.dubbo.common.utils.ReflectUtils;
+import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.MetricsConfig;
+import org.apache.dubbo.config.ModuleConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.ReferenceConfigBase;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfigBase;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.ScopeModel;
+import org.apache.dubbo.rpc.model.ScopeModelUtil;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+import static java.lang.Boolean.TRUE;
+import static java.util.Collections.emptyMap;
+import static java.util.Optional.ofNullable;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
+import static org.apache.dubbo.config.AbstractConfig.getTagName;
+
+public abstract class AbstractConfigManager extends LifecycleAdapter {
+
+    private static final String CONFIG_NAME_READ_METHOD = "getName";
+
+    private static final Logger logger = LoggerFactory.getLogger(AbstractConfigManager.class);
+
+    final Map<String, Map<String, AbstractConfig>> configsCache = new ConcurrentHashMap<>();
+
+    private final Map<String, AtomicInteger> configIdIndexes = new ConcurrentHashMap<>();
+
+    protected Set<AbstractConfig> duplicatedConfigs = new ConcurrentHashSet<>();
+
+    protected final ScopeModel scopeModel;
+    protected final ApplicationModel applicationModel;
+    private final Collection<Class<? extends AbstractConfig>> supportedConfigTypes;
+    private final Environment environment;
+    private ConfigValidator configValidator;
+
+    public AbstractConfigManager(ScopeModel scopeModel, Collection<Class<? extends AbstractConfig>> supportedConfigTypes) {
+        this.scopeModel = scopeModel;
+        this.applicationModel = ScopeModelUtil.getApplicationModel(scopeModel);
+        this.supportedConfigTypes = supportedConfigTypes;
+        environment = applicationModel.getApplicationEnvironment();
+    }
+
+    /**
+     * Add the dubbo {@link AbstractConfig config}
+     *
+     * @param config the dubbo {@link AbstractConfig config}
+     */
+    public final <T extends AbstractConfig> T addConfig(AbstractConfig config) {
+        if (config == null) {
+            return null;
+        }
+        // ignore MethodConfig
+        if (!isSupportConfigType(config.getClass())) {
+            throw new IllegalArgumentException("Unsupported config type: " + config);
+        }
+
+        if (config.getScopeModel() != scopeModel) {
+            config.setScopeModel(scopeModel);
+        }
+
+        Map<String, AbstractConfig> configsMap = configsCache.computeIfAbsent(getTagName(config.getClass()), type -> new ConcurrentHashMap<>());
+
+        // fast check duplicated equivalent config before write lock
+        if (!(config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase)) {
+            for (AbstractConfig value : configsMap.values()) {
+                if (value.equals(config)) {
+                    return (T) value;
+                }
+            }
+        }
+
+        // lock by config type
+        synchronized (configsMap) {
+            return (T) addIfAbsent(config, configsMap);
+        }
+    }
+
+    protected boolean isSupportConfigType(Class<? extends AbstractConfig> type) {
+        for (Class<? extends AbstractConfig> supportedConfigType : supportedConfigTypes) {
+            if (supportedConfigType.isAssignableFrom(type)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Add config
+     *
+     * @param config
+     * @param configsMap
+     * @return the existing equivalent config or the new adding config
+     * @throws IllegalStateException
+     */
+    private <C extends AbstractConfig> C addIfAbsent(C config, Map<String, C> configsMap)
+        throws IllegalStateException {
+
+        if (config == null || configsMap == null) {
+            return config;
+        }
+
+        // find by value
+        Optional<C> prevConfig = findDuplicatedConfig(configsMap, config);
+        if (prevConfig.isPresent()) {
+            return prevConfig.get();
+        }
+
+        String key = config.getId();
+        if (key == null) {
+            do {
+                // generate key if id is not set
+                key = generateConfigId(config);
+            } while (configsMap.containsKey(key));
+        }
+
+        C existedConfig = configsMap.get(key);
+        if (existedConfig != null && !isEquals(existedConfig, config)) {
+            String type = config.getClass().getSimpleName();
+            logger.warn(String.format("Duplicate %s found, there already has one default %s or more than two %ss have the same id, " +
+                    "you can try to give each %s a different id, override previous config with later config. id: %s, prev: %s, later: %s",
+                type, type, type, type, key, existedConfig, config));
+        }
+
+        // override existed config if any
+        configsMap.put(key, config);
+        return config;
+    }
+
+    protected <C extends AbstractConfig> Optional<C> findDuplicatedConfig(Map<String, C> configsMap, C config) {
+        Optional<C> prevConfig = findConfigByValue(configsMap.values(), config);
+        if (prevConfig.isPresent()) {
+            if (prevConfig.get() == config) {
+                // the new one is same as existing one
+                return prevConfig;
+            }
+
+            // ignore duplicated equivalent config
+            if (logger.isInfoEnabled() && duplicatedConfigs.add(config)) {
+                logger.info("Ignore duplicated config: " + config);
+            }
+            return prevConfig;
+        }
+        return Optional.empty();
+    }
+
+    public <C extends AbstractConfig> Map<String, C> getConfigsMap(Class<C> cls) {
+        return getConfigsMap(getTagName(cls));
+    }
+
+    protected <C extends AbstractConfig> Map<String, C> getConfigsMap(String configType) {
+        return (Map<String, C>) configsCache.getOrDefault(configType, emptyMap());
+    }
+
+    protected <C extends AbstractConfig> Collection<C> getConfigs(String configType) {
+        return (Collection<C>) getConfigsMap(configType).values();
+    }
+
+    public <C extends AbstractConfig> Collection<C> getConfigs(Class<C> configType) {
+        return (Collection<C>) getConfigsMap(getTagName(configType)).values();
+    }
+
+    /**
+     * Get config by id
+     *
+     * @param configType
+     * @param id
+     * @return
+     */
+    protected <C extends AbstractConfig> C getConfigById(String configType, String id) {
+        return (C) getConfigsMap(configType).get(id);
+    }
+
+    /**
+     * Get config instance by id or by name
+     *
+     * @param cls      Config type
+     * @param idOrName the id or name of the config
+     * @return
+     */
+    public <T extends AbstractConfig> Optional<T> getConfig(Class<T> cls, String idOrName) {
+        T config = getConfigById(getTagName(cls), idOrName);
+        if (config == null) {
+            config = getConfigByName(cls, idOrName);
+        }
+        return ofNullable(config);
+    }
+
+    /**
+     * Get config by name if existed
+     *
+     * @param cls
+     * @param name
+     * @return
+     */
+    protected <C extends AbstractConfig> C getConfigByName(Class<? extends C> cls, String name) {
+        Map<String, ? extends C> configsMap = getConfigsMap(cls);
+        if (configsMap.isEmpty()) {
+            return null;
+        }
+        // try find config by name
+        if (ReflectUtils.hasMethod(cls, CONFIG_NAME_READ_METHOD)) {
+            List<C> list = configsMap.values().stream()
+                .filter(cfg -> name.equals(getConfigName(cfg)))
+                .collect(Collectors.toList());
+            if (list.size() > 1) {
+                throw new IllegalStateException("Found more than one config by name: " + name +
+                    ", instances: " + list + ". Please remove redundant configs or get config by id.");
+            } else if (list.size() == 1) {
+                return list.get(0);
+            }
+        }
+        return null;
+    }
+
+    private <C extends AbstractConfig> String getConfigName(C config) {
+        try {
+            return (String) ReflectUtils.getProperty(config, CONFIG_NAME_READ_METHOD);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    protected <C extends AbstractConfig> Optional<C> findConfigByValue(Collection<C> values, C config) {
+        // 1. find same config instance (speed up raw api usage)
+        Optional<C> prevConfig = values.stream().filter(val -> val == config).findFirst();
+        if (prevConfig.isPresent()) {
+            return prevConfig;
+        }
+
+        // 2. find equal config
+        prevConfig = values.stream()
+            .filter(val -> isEquals(val, config))
+            .findFirst();
+        return prevConfig;
+    }
+
+    protected boolean isEquals(AbstractConfig oldOne, AbstractConfig newOne) {
+        if (oldOne == newOne) {
+            return true;
+        }
+        if (oldOne == null || newOne == null) {
+            return false;
+        }
+        if (oldOne.getClass() != newOne.getClass()) {
+            return false;
+        }
+        // make both are refreshed or none is refreshed
+        if (oldOne.isRefreshed() || newOne.isRefreshed()) {
+            if (!oldOne.isRefreshed()) {
+                oldOne.refresh();
+            }
+            if (!newOne.isRefreshed()) {
+                newOne.refresh();
+            }
+        }
+        return oldOne.equals(newOne);
+    }
+
+    protected <C extends AbstractConfig> String generateConfigId(C config) {
+        String tagName = getTagName(config.getClass());
+        int idx = configIdIndexes.computeIfAbsent(tagName, clazz -> new AtomicInteger(0)).incrementAndGet();
+        return tagName + "#" + idx;
+    }
+
+    public <C extends AbstractConfig> List<C> getDefaultConfigs(Class<C> cls) {
+        return getDefaultConfigs(getConfigsMap(getTagName(cls)));
+    }
+
+    static <C extends AbstractConfig> Boolean isDefaultConfig(C config) {
+        return config.isDefault();
+    }
+
+    static <C extends AbstractConfig> List<C> getDefaultConfigs(Map<String, C> configsMap) {
+        // find isDefault() == true
+        List<C> list = configsMap.values()
+            .stream()
+            .filter(c -> TRUE.equals(AbstractConfigManager.isDefaultConfig(c)))
+            .collect(Collectors.toList());
+        if (list.size() > 0) {
+            return list;
+        }
+
+        // find isDefault() == null
+        list = configsMap.values()
+            .stream()
+            .filter(c -> AbstractConfigManager.isDefaultConfig(c) == null)
+            .collect(Collectors.toList());
+        return list;
+
+        // exclude isDefault() == false
+    }
+
+    public abstract void loadConfigs();
+
+    public <T extends AbstractConfig> void loadConfigsOfTypeFromProps(Class<T> cls) {
+        PropertiesConfiguration properties = applicationModel.getApplicationEnvironment().getPropertiesConfiguration();
+
+        // load multiple configs with id
+        Set<String> configIds = this.getConfigIdsFromProps(cls);
+        configIds.forEach(id -> {
+            if (!this.getConfig(cls, id).isPresent()) {
+                T config = null;
+                try {
+                    config = createConfig(cls, scopeModel);
+                    config.setId(id);
+                } catch (Exception e) {
+                    throw new IllegalStateException("create config instance failed, id: " + id + ", type:" + cls.getSimpleName());
+                }
+
+                String key = null;
+                boolean addDefaultNameConfig = false;
+                try {
+                    // add default name config (same as id), e.g. dubbo.protocols.rest.port=1234
+                    key = DUBBO + "." + AbstractConfig.getPluralTagName(cls) + "." + id + ".name";
+                    if (properties.getProperty(key) == null) {
+                        properties.setProperty(key, id);
+                        addDefaultNameConfig = true;
+                    }
+
+                    config.refresh();
+                    this.addConfig(config);
+                } catch (Exception e) {
+                    logger.error("load config failed, id: " + id + ", type:" + cls.getSimpleName(), e);
+                    throw new IllegalStateException("load config failed, id: " + id + ", type:" + cls.getSimpleName());
+                } finally {
+                    if (addDefaultNameConfig && key != null) {
+                        properties.remove(key);
+                    }
+                }
+            }
+        });
+
+        // If none config of the type, try load single config
+        if (this.getConfigs(cls).isEmpty()) {
+            // load single config
+            List<Map<String, String>> configurationMaps = environment.getConfigurationMaps();
+            if (ConfigurationUtils.hasSubProperties(configurationMaps, AbstractConfig.getTypePrefix(cls))) {
+                T config = null;
+                try {
+                    config = createConfig(cls, scopeModel);
+                    config.refresh();
+                } catch (Exception e) {
+                    throw new IllegalStateException("create default config instance failed, type:" + cls.getSimpleName());
+                }
+
+                this.addConfig(config);
+            }
+        }
+
+    }
+
+    private <T extends AbstractConfig> T createConfig(Class<T> cls, ScopeModel scopeModel) throws ReflectiveOperationException {
+        T config = cls.newInstance();
+        config.setScopeModel(scopeModel);
+        return config;
+    }
+
+    /**
+     * Search props and extract config ids of specify type.
+     * <pre>
+     * # properties
+     * dubbo.registries.registry1.address=xxx
+     * dubbo.registries.registry2.port=xxx
+     *
+     * # extract
+     * Set configIds = getConfigIds(RegistryConfig.class)
+     *
+     * # result
+     * configIds: ["registry1", "registry2"]
+     * </pre>
+     *
+     * @param clazz config type
+     * @return ids of specify config type
+     */
+    private Set<String> getConfigIdsFromProps(Class<? extends AbstractConfig> clazz) {
+        String prefix = CommonConstants.DUBBO + "." + AbstractConfig.getPluralTagName(clazz) + ".";
+        return ConfigurationUtils.getSubIds(environment.getConfigurationMaps(), prefix);
+    }
+
+
+    protected <T extends AbstractConfig> void checkDefaultAndValidateConfigs(Class<T> configType) {
+        try {
+            if (shouldAddDefaultConfig(configType)) {
+                T config = createConfig(configType, scopeModel);
+                config.refresh();
+                if (!isNeedValidation(config) || config.isValid()) {
+                    this.addConfig(config);
+                } else {
+                    logger.info("Ignore invalid config: " + config);
+                }
+            }
+        } catch (Exception e) {
+            throw new IllegalStateException("Add default config failed: " + configType.getSimpleName(), e);
+        }
+
+        //validate configs
+        Collection<T> configs = this.getConfigs(configType);
+        for (T config : configs) {
+            getConfigValidator().validate(config);
+        }
+
+        // check required default
+        if (isRequired(configType) && configs.isEmpty()) {
+            throw new IllegalStateException("Default config not found for " + configType.getSimpleName());
+        }
+    }
+
+    /**
+     * The component configuration that does not affect the main process does not need to be verified.
+     *
+     * @param config
+     * @param <T>
+     * @return
+     */
+    protected <T extends AbstractConfig> boolean isNeedValidation(T config) {
+        if (config instanceof MetadataReportConfig) {
+            return false;
+        }
+        return true;
+    }
+
+    private ConfigValidator getConfigValidator() {
+        if (configValidator == null) {
+            configValidator = applicationModel.getBeanFactory().getBean(ConfigValidator.class);
+        }
+        return configValidator;
+    }
+
+    /**
+     * The configuration that does not affect the main process is not necessary.
+     *
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    protected <T extends AbstractConfig> boolean isRequired(Class<T> clazz) {
+        if (clazz == RegistryConfig.class ||
+            clazz == MetadataReportConfig.class ||
+            clazz == MonitorConfig.class ||
+            clazz == ModuleConfig.class ||
+            clazz == MetricsConfig.class) {
+            return false;
+        }
+        return true;
+    }
+
+    private <T extends AbstractConfig> boolean shouldAddDefaultConfig(Class<T> clazz) {
+        // Configurations that are not required will not be automatically added to the default configuration
+        if (!isRequired(clazz)) {
+            return false;
+        }
+        return this.getDefaultConfigs(clazz).isEmpty();
+    }
+
+
+    public void refreshAll() {
+
+    }
+
+
+    /**
+     * In some scenario,  we may nee to add and remove ServiceConfig or ReferenceConfig dynamically.
+     *
+     * @param config the config instance to remove.
+     * @return
+     */
+    public boolean removeConfig(AbstractConfig config) {
+        if (config == null) {
+            return false;
+        }
+
+        Map<String, AbstractConfig> configs = configsCache.get(getTagName(config.getClass()));
+        if (CollectionUtils.isNotEmptyMap(configs)) {
+            return configs.values().removeIf(c -> config == c);
+        }
+        return false;
+    }
+
+    @Override
+    public void destroy() throws IllegalStateException {
+        clear();
+    }
+
+    public void clear() {
+        this.configsCache.clear();
+        this.configIdIndexes.clear();
+        this.duplicatedConfigs.clear();
+    }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
index 7bae399..433121e 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
@@ -18,83 +18,55 @@ package org.apache.dubbo.config.context;
 
 import org.apache.dubbo.common.config.CompositeConfiguration;
 import org.apache.dubbo.common.context.FrameworkExt;
-import org.apache.dubbo.common.context.LifecycleAdapter;
 import org.apache.dubbo.common.extension.DisableInject;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.CollectionUtils;
 import org.apache.dubbo.common.utils.ConcurrentHashSet;
-import org.apache.dubbo.common.utils.ReflectUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.AbstractConfig;
-import org.apache.dubbo.config.AbstractInterfaceConfig;
-import org.apache.dubbo.config.AbstractMethodConfig;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.ConfigCenterConfig;
 import org.apache.dubbo.config.ConfigKeys;
-import org.apache.dubbo.config.ConsumerConfig;
 import org.apache.dubbo.config.MetadataReportConfig;
-import org.apache.dubbo.config.MethodConfig;
 import org.apache.dubbo.config.MetricsConfig;
 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.ReferenceConfigBase;
 import org.apache.dubbo.config.RegistryConfig;
-import org.apache.dubbo.config.ServiceConfigBase;
 import org.apache.dubbo.config.SslConfig;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.Collectors;
 
-import static java.lang.Boolean.TRUE;
-import static java.util.Collections.emptyMap;
 import static java.util.Optional.ofNullable;
-import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
 import static org.apache.dubbo.config.AbstractConfig.getTagName;
 
 /**
  * A lock-free config manager (through ConcurrentHashMap), for fast read operation.
  * The Write operation lock with sub configs map of config type, for safely check and add new config.
  */
-public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
+public class ConfigManager extends AbstractConfigManager implements FrameworkExt {
 
     private static final Logger logger = LoggerFactory.getLogger(ConfigManager.class);
 
     public static final String NAME = "config";
     public static final String BEAN_NAME = "dubboConfigManager";
-    private static final String CONFIG_NAME_READ_METHOD = "getName";
     public static final String DUBBO_CONFIG_MODE = ConfigKeys.DUBBO_CONFIG_MODE;
 
-    final Map<String, Map<String, AbstractConfig>> configsCache = new ConcurrentHashMap<>();
-
-    private Map<String, AbstractInterfaceConfig> referenceConfigCache = new ConcurrentHashMap<>();
-
-    private Map<String, AbstractInterfaceConfig> serviceConfigCache = new ConcurrentHashMap<>();
-
-    private Set<AbstractConfig> duplicatedConfigs = new ConcurrentHashSet<>();
-
     private ConfigMode configMode = ConfigMode.STRICT;
 
-    private boolean ignoreDuplicatedInterface = false;
-
     private ApplicationModel applicationModel;
 
     private AtomicBoolean inited = new AtomicBoolean(false);
 
-    private static Map<String, AtomicInteger> configIdIndexes = new ConcurrentHashMap<>();
-
     private static Set<Class<? extends AbstractConfig>> uniqueConfigTypes = new ConcurrentHashSet<>();
 
     static {
@@ -104,14 +76,12 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
         uniqueConfigTypes.add(MonitorConfig.class);
         uniqueConfigTypes.add(MetricsConfig.class);
         uniqueConfigTypes.add(SslConfig.class);
-
-        List<String> configNames = new ArrayList<>(uniqueConfigTypes.size());
-        for (Class<? extends AbstractConfig> configType : uniqueConfigTypes) {
-            configNames.add(configType.getSimpleName());
-        }
     }
 
     public ConfigManager(ApplicationModel applicationModel) {
+        super(applicationModel, Arrays.asList(ApplicationConfig.class, ModuleConfig.class, MonitorConfig.class,
+            MetricsConfig.class, SslConfig.class, ProtocolConfig.class, RegistryConfig.class, ConfigCenterConfig.class,
+            MetadataReportConfig.class));
         this.applicationModel = applicationModel;
     }
 
@@ -132,12 +102,7 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
             throw new IllegalArgumentException(msg, e);
         }
 
-        String ignoreDuplicatedInterfaceStr = (String) configuration
-            .getProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE);
-        if (ignoreDuplicatedInterfaceStr != null) {
-            this.ignoreDuplicatedInterface = Boolean.parseBoolean(ignoreDuplicatedInterfaceStr);
-        }
-        logger.info("Dubbo config mode: " + configMode + ", ignore duplicated interface: " + ignoreDuplicatedInterface);
+        logger.info("Config settings - config mode: " + configMode);
     }
 
 
@@ -151,7 +116,7 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
      */
     @DisableInject
     public void setApplication(ApplicationConfig application) {
-        addConfig(application, true);
+        addConfig(application);
     }
 
     public Optional<ApplicationConfig> getApplication() {
@@ -166,7 +131,7 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
 
     @DisableInject
     public void setMonitor(MonitorConfig monitor) {
-        addConfig(monitor, true);
+        addConfig(monitor);
     }
 
     public Optional<MonitorConfig> getMonitor() {
@@ -177,7 +142,7 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
 
     @DisableInject
     public void setModule(ModuleConfig module) {
-        addConfig(module, true);
+        addConfig(module);
     }
 
     public Optional<ModuleConfig> getModule() {
@@ -186,7 +151,7 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
 
     @DisableInject
     public void setMetrics(MetricsConfig metrics) {
-        addConfig(metrics, true);
+        addConfig(metrics);
     }
 
     public Optional<MetricsConfig> getMetrics() {
@@ -195,7 +160,7 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
 
     @DisableInject
     public void setSsl(SslConfig sslConfig) {
-        addConfig(sslConfig, true);
+        addConfig(sslConfig);
     }
 
     public Optional<SslConfig> getSsl() {
@@ -250,64 +215,6 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
         return defaults;
     }
 
-    // MetadataReportConfig correlative methods
-
-    public void addProvider(ProviderConfig providerConfig) {
-        addConfig(providerConfig);
-    }
-
-    public void addProviders(Iterable<ProviderConfig> providerConfigs) {
-        providerConfigs.forEach(this::addProvider);
-    }
-
-    public Optional<ProviderConfig> getProvider(String id) {
-        return getConfig(ProviderConfig.class, id);
-    }
-
-    /**
-     * Only allows one default ProviderConfig
-     */
-    public Optional<ProviderConfig> getDefaultProvider() {
-        List<ProviderConfig> providerConfigs = getDefaultConfigs(getConfigsMap(getTagName(ProviderConfig.class)));
-        if (CollectionUtils.isNotEmpty(providerConfigs)) {
-            return Optional.of(providerConfigs.get(0));
-        }
-        return Optional.empty();
-    }
-
-    public Collection<ProviderConfig> getProviders() {
-        return getConfigs(getTagName(ProviderConfig.class));
-    }
-
-    // ConsumerConfig correlative methods
-
-    public void addConsumer(ConsumerConfig consumerConfig) {
-        addConfig(consumerConfig);
-    }
-
-    public void addConsumers(Iterable<ConsumerConfig> consumerConfigs) {
-        consumerConfigs.forEach(this::addConsumer);
-    }
-
-    public Optional<ConsumerConfig> getConsumer(String id) {
-        return getConfig(ConsumerConfig.class, id);
-    }
-
-    /**
-     * Only allows one default ConsumerConfig
-     */
-    public Optional<ConsumerConfig> getDefaultConsumer() {
-        List<ConsumerConfig> consumerConfigs = getDefaultConfigs(getConfigsMap(getTagName(ConsumerConfig.class)));
-        if (CollectionUtils.isNotEmpty(consumerConfigs)) {
-            return Optional.of(consumerConfigs.get(0));
-        }
-        return Optional.empty();
-    }
-
-    public Collection<ConsumerConfig> getConsumers() {
-        return getConfigs(getTagName(ConsumerConfig.class));
-    }
-
     // ProtocolConfig correlative methods
 
     public void addProtocol(ProtocolConfig protocolConfig) {
@@ -353,21 +260,6 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
         return getConfig(RegistryConfig.class, id);
     }
 
-    /**
-     * Get config instance by id or by name
-     *
-     * @param cls      Config type
-     * @param idOrName the id or name of the config
-     * @return
-     */
-    public <T extends AbstractConfig> Optional<T> getConfig(Class<T> cls, String idOrName) {
-        T config = getConfigById(getTagName(cls), idOrName);
-        if (config == null) {
-            config = getConfigByName(cls, idOrName);
-        }
-        return ofNullable(config);
-    }
-
     public List<RegistryConfig> getDefaultRegistries() {
         return getDefaultConfigs(getConfigsMap(getTagName(RegistryConfig.class)));
     }
@@ -376,47 +268,6 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
         return getConfigs(getTagName(RegistryConfig.class));
     }
 
-    // ServiceConfig correlative methods
-
-    public void addService(ServiceConfigBase<?> serviceConfig) {
-        if (serviceConfig.getScopeModel() == null) {
-            serviceConfig.setScopeModel(applicationModel.getDefaultModule());
-        }
-        addConfig(serviceConfig);
-    }
-
-    public void addServices(Iterable<ServiceConfigBase<?>> serviceConfigs) {
-        serviceConfigs.forEach(this::addService);
-    }
-
-    public Collection<ServiceConfigBase> getServices() {
-        return getConfigs(getTagName(ServiceConfigBase.class));
-    }
-
-    public <T> ServiceConfigBase<T> getService(String id) {
-        return getConfig(ServiceConfigBase.class, id).orElse(null);
-    }
-
-    // ReferenceConfig correlative methods
-
-    public void addReference(ReferenceConfigBase<?> referenceConfig) {
-        if (referenceConfig.getScopeModel() == null) {
-            referenceConfig.setScopeModel(applicationModel.getDefaultModule());
-        }
-        addConfig(referenceConfig);
-    }
-
-    public void addReferences(Iterable<ReferenceConfigBase<?>> referenceConfigs) {
-        referenceConfigs.forEach(this::addReference);
-    }
-
-    public Collection<ReferenceConfigBase<?>> getReferences() {
-        return getConfigs(getTagName(ReferenceConfigBase.class));
-    }
-
-    public <T> ReferenceConfigBase<T> getReference(String id) {
-        return getConfig(ReferenceConfigBase.class, id).orElse(null);
-    }
 
     public void refreshAll() {
         // refresh all configs here,
@@ -428,157 +279,20 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
 
         getProtocols().forEach(ProtocolConfig::refresh);
         getRegistries().forEach(RegistryConfig::refresh);
-        getProviders().forEach(ProviderConfig::refresh);
-        getConsumers().forEach(ConsumerConfig::refresh);
         getConfigCenters().forEach(ConfigCenterConfig::refresh);
         getMetadataConfigs().forEach(MetadataReportConfig::refresh);
     }
 
-    /**
-     * In some scenario,  we may nee to add and remove ServiceConfig or ReferenceConfig dynamically.
-     *
-     * @param config the config instance to remove.
-     * @return
-     */
-    public boolean removeConfig(AbstractConfig config) {
-        if (config == null) {
-            return false;
-        }
-
-        Map<String, AbstractConfig> configs = configsCache.get(getTagName(config.getClass()));
-        if (CollectionUtils.isNotEmptyMap(configs)) {
-            return configs.values().removeIf(c -> config == c);
-        }
-        return false;
-    }
-
-    public void clear() {
-        this.configsCache.clear();
-        configIdIndexes.clear();
-        this.referenceConfigCache.clear();
-        this.serviceConfigCache.clear();
-        this.duplicatedConfigs.clear();
-    }
-
-    /**
-     * @throws IllegalStateException
-     * @since 2.7.8
-     */
-    @Override
-    public void destroy() throws IllegalStateException {
-        clear();
-    }
-
-    /**
-     * Add the dubbo {@link AbstractConfig config}
-     *
-     * @param config the dubbo {@link AbstractConfig config}
-     */
-    public void addConfig(AbstractConfig config) {
-        if (config == null) {
-            return;
-        }
-        if (config.getScopeModel() == null) {
-            config.setScopeModel(applicationModel);
-        }
-        addConfig(config, isUniqueConfig(config));
-    }
-
     private boolean isUniqueConfig(AbstractConfig config) {
-        return uniqueConfigTypes.contains(config.getClass());
-    }
-
-    protected <T extends AbstractConfig> T addConfig(AbstractConfig config, boolean unique) {
-        if (config == null) {
-            return null;
-        }
-
-        if(!(config instanceof AbstractMethodConfig)) {
-            config.setScopeModel(applicationModel);
-        }
-
-        // ignore MethodConfig
-        if (config instanceof MethodConfig) {
-            return null;
-        }
-
-        Map<String, AbstractConfig> configsMap = configsCache.computeIfAbsent(getTagName(config.getClass()), type -> newMap());
-
-        // fast check duplicated equivalent config before write lock
-        if (!(config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase)) {
-            for (AbstractConfig value : configsMap.values()) {
-                if (value.equals(config)) {
-                    return (T) value;
-                }
-            }
-        }
-
-        // lock by config type
-        synchronized (configsMap) {
-            return (T) addIfAbsent(config, configsMap, unique);
-        }
-    }
-
-    public <C extends AbstractConfig> Map<String, C> getConfigsMap(Class<C> cls) {
-        return getConfigsMap(getTagName(cls));
-    }
-
-    private <C extends AbstractConfig> Map<String, C> getConfigsMap(String configType) {
-        return (Map<String, C>) configsCache.getOrDefault(configType, emptyMap());
-    }
-
-    private <C extends AbstractConfig> Collection<C> getConfigs(String configType) {
-        return (Collection<C>) getConfigsMap(configType).values();
-    }
-
-    public <C extends AbstractConfig> Collection<C> getConfigs(Class<C> configType) {
-        return (Collection<C>) getConfigsMap(getTagName(configType)).values();
-    }
-
-    /**
-     * Get config by id
-     *
-     * @param configType
-     * @param id
-     * @return
-     */
-    private <C extends AbstractConfig> C getConfigById(String configType, String id) {
-        return (C) getConfigsMap(configType).get(id);
-    }
-
-    /**
-     * Get config by name if existed
-     *
-     * @param cls
-     * @param name
-     * @return
-     */
-    private <C extends AbstractConfig> C getConfigByName(Class<? extends C> cls, String name) {
-        Map<String, ? extends C> configsMap = getConfigsMap(cls);
-        if (configsMap.isEmpty()) {
-            return null;
+        if (uniqueConfigTypes.contains(config.getClass())) {
+            return true;
         }
-        // try find config by name
-        if (ReflectUtils.hasMethod(cls, CONFIG_NAME_READ_METHOD)) {
-            List<C> list = configsMap.values().stream()
-                .filter(cfg -> name.equals(getConfigName(cfg)))
-                .collect(Collectors.toList());
-            if (list.size() > 1) {
-                throw new IllegalStateException("Found more than one config by name: " + name +
-                    ", instances: " + list + ". Please remove redundant configs or get config by id.");
-            } else if (list.size() == 1) {
-                return list.get(0);
+        for (Class<? extends AbstractConfig> uniqueConfigType : uniqueConfigTypes) {
+            if (uniqueConfigType.isAssignableFrom(config.getClass())) {
+                return true;
             }
         }
-        return null;
-    }
-
-    private <C extends AbstractConfig> String getConfigName(C config) {
-        try {
-            return (String) ReflectUtils.getProperty(config, CONFIG_NAME_READ_METHOD);
-        } catch (Exception e) {
-            return null;
-        }
+        return false;
     }
 
     protected <C extends AbstractConfig> C getSingleConfig(String configType) throws IllegalStateException {
@@ -594,74 +308,26 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
         return (C) configsMap.values().iterator().next();
     }
 
-    private static boolean isEquals(AbstractConfig oldOne, AbstractConfig newOne) {
-        if (oldOne == newOne) {
-            return true;
-        }
-        if (oldOne == null || newOne == null) {
-            return false;
-        }
-        if (oldOne.getClass() != newOne.getClass()) {
-            return false;
-        }
-        // make both are refreshed or none is refreshed
-        if (oldOne.isRefreshed() || newOne.isRefreshed()) {
-            if (!oldOne.isRefreshed()) {
-                oldOne.refresh();
-            }
-            if (!newOne.isRefreshed()) {
-                newOne.refresh();
-            }
-        }
-        return oldOne.equals(newOne);
-    }
-
-    private static Map newMap() {
-        return new ConcurrentHashMap();
-    }
-
-    /**
-     * Add config
-     *
-     * @param config
-     * @param configsMap
-     * @param unique
-     * @return the existing equivalent config or the new adding config
-     * @throws IllegalStateException
-     */
-    private <C extends AbstractConfig> C addIfAbsent(C config, Map<String, C> configsMap, boolean unique)
-        throws IllegalStateException {
-
-        if (config == null || configsMap == null) {
-            return config;
-        }
+    @Override
+    protected <C extends AbstractConfig> Optional<C> findDuplicatedConfig(Map<String, C> configsMap, C config) {
 
-        // check duplicated configs
-        // special check service and reference config by unique service name, speed up the processing of large number of instances
-        if (config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase) {
-            C existedConfig = (C) checkDuplicatedInterfaceConfig((AbstractInterfaceConfig) config);
-            if (existedConfig != null) {
-                return existedConfig;
+        // find by value
+        Optional<C> prevConfig = findConfigByValue(configsMap.values(), config);
+        if (prevConfig.isPresent()) {
+            if (prevConfig.get() == config) {
+                // the new one is same as existing one
+                return prevConfig;
             }
-        } else {
-            // find by value
-            Optional<C> prevConfig = findConfigByValue(configsMap.values(), config);
-            if (prevConfig.isPresent()) {
-                if (prevConfig.get() == config) {
-                    // the new one is same as existing one
-                    return prevConfig.get();
-                }
 
-                // ignore duplicated equivalent config
-                if (logger.isInfoEnabled() && duplicatedConfigs.add(config)) {
-                    logger.info("Ignore duplicated config: " + config);
-                }
-                return prevConfig.get();
+            // ignore duplicated equivalent config
+            if (logger.isInfoEnabled() && duplicatedConfigs.add(config)) {
+                logger.info("Ignore duplicated config: " + config);
             }
+            return prevConfig;
         }
 
         // check unique config
-        if (unique && configsMap.size() > 0) {
+        if (configsMap.size() > 0 && isUniqueConfig(config)) {
             C oldOne = configsMap.values().iterator().next();
             String configName = oldOne.getClass().getSimpleName();
             String msgPrefix = "Duplicate Configs found for " + configName + ", only one unique " + configName +
@@ -678,7 +344,7 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
                     if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {
                         logger.warn(msgPrefix + "keep previous config and ignore later config");
                     }
-                    return oldOne;
+                    return Optional.of(oldOne);
                 }
                 case OVERRIDE: {
                     // clear previous config, add new config
@@ -690,126 +356,73 @@ public class ConfigManager extends LifecycleAdapter implements FrameworkExt {
                 }
             }
         }
-
-        String key = getId(config);
-        if (key == null) {
-            do {
-                // generate key if id is not set
-                key = generateConfigId(config);
-            } while (configsMap.containsKey(key));
-        }
-
-        C existedConfig = configsMap.get(key);
-        if (existedConfig != null && !isEquals(existedConfig, config)) {
-            String type = config.getClass().getSimpleName();
-            logger.warn(String.format("Duplicate %s found, there already has one default %s or more than two %ss have the same id, " +
-                    "you can try to give each %s a different id, override previous config with later config. id: %s, prev: %s, later: %s",
-                type, type, type, type, key, existedConfig, config));
-        }
-
-        // override existed config if any
-        configsMap.put(key, config);
-        return config;
+        return Optional.empty();
     }
 
-    private <C extends AbstractConfig> Optional<C> findConfigByValue(Collection<C> values, C config) {
-        // 1. find same config instance (speed up raw api usage)
-        Optional<C> prevConfig = values.stream().filter(val -> val == config).findFirst();
-        if (prevConfig.isPresent()) {
-            return prevConfig;
-        }
+    @Override
+    public void loadConfigs() {
+        // application config has load before starting config center
+        // load dubbo.applications.xxx
+        loadConfigsOfTypeFromProps(ApplicationConfig.class);
 
-        // 2. find equal config
-        prevConfig = values.stream()
-            .filter(val -> isEquals(val, config))
-            .findFirst();
-        return prevConfig;
-    }
+        // load dubbo.modules.xxx
+        loadConfigsOfTypeFromProps(ModuleConfig.class);
 
-    /**
-     * check duplicated ReferenceConfig/ServiceConfig
-     *
-     * @param config
-     */
-    private AbstractInterfaceConfig checkDuplicatedInterfaceConfig(AbstractInterfaceConfig config) {
-        String uniqueServiceName;
-        Map<String, AbstractInterfaceConfig> configCache;
-        if (config instanceof ReferenceConfigBase) {
-            return null;
-        } else if (config instanceof ServiceConfigBase) {
-            ServiceConfigBase serviceConfig = (ServiceConfigBase) config;
-            uniqueServiceName = serviceConfig.getUniqueServiceName();
-            configCache = serviceConfigCache;
-        } else {
-            throw new IllegalArgumentException("Illegal type of parameter 'config' : " + config.getClass().getName());
-        }
+        // load dubbo.monitors.xxx
+        loadConfigsOfTypeFromProps(MonitorConfig.class);
 
-        AbstractInterfaceConfig prevConfig = configCache.putIfAbsent(uniqueServiceName, config);
-        if (prevConfig != null) {
-            if (prevConfig == config) {
-                return prevConfig;
-            }
+        // load dubbo.metricses.xxx
+        loadConfigsOfTypeFromProps(MetricsConfig.class);
 
-            if (prevConfig.equals(config)) {
-                // TODO Is there any problem with ignoring duplicate and equivalent but different ReferenceConfig instances?
-                if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {
-                    logger.warn("Ignore duplicated and equal config: " + config);
-                }
-                return prevConfig;
-            }
+        // load multiple config types:
+        // load dubbo.protocols.xxx
+        loadConfigsOfTypeFromProps(ProtocolConfig.class);
 
-            String configType = config.getClass().getSimpleName();
-            String msg = "Found multiple " + configType + "s with unique service name [" +
-                uniqueServiceName + "], previous: " + prevConfig + ", later: " + config + ". " +
-                "There can only be one instance of " + configType + " with the same triple (group, interface, version). " +
-                "If multiple instances are required for the same interface, please use a different group or version.";
+        // load dubbo.registries.xxx
+        loadConfigsOfTypeFromProps(RegistryConfig.class);
 
-            if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {
-                logger.warn(msg);
-            }
-            if (!ignoreDuplicatedInterface) {
-                throw new IllegalStateException(msg);
-            }
-        }
-        return prevConfig;
-    }
+        // load dubbo.metadata-report.xxx
+        loadConfigsOfTypeFromProps(MetadataReportConfig.class);
 
-    public static <C extends AbstractConfig> String generateConfigId(C config) {
-        String tagName = getTagName(config.getClass());
-        int idx = configIdIndexes.computeIfAbsent(tagName, clazz -> new AtomicInteger(0)).incrementAndGet();
-        return tagName + "#" + idx;
-    }
+        // config centers has bean loaded before starting config center
+        //loadConfigsOfTypeFromProps(ConfigCenterConfig.class);
 
-    static <C extends AbstractConfig> String getId(C config) {
-        String id = config.getId();
-        return isNotEmpty(id) ? id : null;
+        checkConfigs();
     }
 
-    static <C extends AbstractConfig> Boolean isDefaultConfig(C config) {
-        return config.isDefault();
-    }
+    private void checkConfigs() {
+        // check config types (ignore metadata-center)
+        List<Class<? extends AbstractConfig>> multipleConfigTypes = Arrays.asList(
+            ApplicationConfig.class,
+            ProtocolConfig.class,
+            RegistryConfig.class,
+            MetadataReportConfig.class,
+            MonitorConfig.class,
+            ModuleConfig.class,
+            MetricsConfig.class,
+            SslConfig.class);
 
-    static <C extends AbstractConfig> List<C> getDefaultConfigs(Map<String, C> configsMap) {
-        // find isDefault() == true
-        List<C> list = configsMap.values()
-            .stream()
-            .filter(c -> TRUE.equals(ConfigManager.isDefaultConfig(c)))
-            .collect(Collectors.toList());
-        if (list.size() > 0) {
-            return list;
+        for (Class<? extends AbstractConfig> configType : multipleConfigTypes) {
+            checkDefaultAndValidateConfigs(configType);
         }
 
-        // find isDefault() == null
-        list = configsMap.values()
-            .stream()
-            .filter(c -> ConfigManager.isDefaultConfig(c) == null)
-            .collect(Collectors.toList());
-        return list;
-
-        // exclude isDefault() == false
+        // check port conflicts
+        Map<Integer, ProtocolConfig> protocolPortMap = new LinkedHashMap<>();
+        for (ProtocolConfig protocol : this.getProtocols()) {
+            Integer port = protocol.getPort();
+            if (port == null || port == -1) {
+                continue;
+            }
+            ProtocolConfig prevProtocol = protocolPortMap.get(port);
+            if (prevProtocol != null) {
+                throw new IllegalStateException("Duplicated port used by protocol configs, port: " + port +
+                    ", configs: " + Arrays.asList(prevProtocol, protocol));
+            }
+            protocolPortMap.put(port, protocol);
+        }
     }
 
-    protected ConfigMode getConfigMode() {
+    ConfigMode getConfigMode() {
         return configMode;
     }
 }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
similarity index 64%
copy from dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java
copy to dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
index 08a5e09..7d20b1b 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
@@ -14,23 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.spring.context;
+package org.apache.dubbo.config.context;
 
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.apache.dubbo.config.AbstractConfig;
 
-/**
- * Dubbo spring initialization context object
- */
-public class DubboSpringInitializationContext {
-
-    private BeanDefinitionRegistry registry;
-
-    public BeanDefinitionRegistry getRegistry() {
-        return registry;
-    }
+public interface ConfigValidator {
 
-    void setRegistry(BeanDefinitionRegistry registry) {
-        this.registry = registry;
-    }
+    void validate(AbstractConfig config);
 
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ModuleConfigManager.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ModuleConfigManager.java
new file mode 100644
index 0000000..753bf27
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ModuleConfigManager.java
@@ -0,0 +1,264 @@
+/*
+ * 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.context;
+
+import org.apache.dubbo.common.config.CompositeConfiguration;
+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.ConfigKeys;
+import org.apache.dubbo.config.ConsumerConfig;
+import org.apache.dubbo.config.ProviderConfig;
+import org.apache.dubbo.config.ReferenceConfigBase;
+import org.apache.dubbo.config.ServiceConfigBase;
+import org.apache.dubbo.rpc.model.ModuleModel;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.apache.dubbo.config.AbstractConfig.getTagName;
+
+/**
+ * Manage configs of module
+ */
+public class ModuleConfigManager extends AbstractConfigManager {
+
+    private static final Logger logger = LoggerFactory.getLogger(ModuleConfigManager.class);
+
+    private Map<String, AbstractInterfaceConfig> serviceConfigCache = new ConcurrentHashMap<>();
+
+    private boolean ignoreDuplicatedInterface = false;
+
+    private AtomicBoolean inited = new AtomicBoolean(false);
+
+
+    public ModuleConfigManager(ModuleModel moduleModel) {
+        super(moduleModel, Arrays.asList(ServiceConfigBase.class, ReferenceConfigBase.class, ProviderConfig.class, ConsumerConfig.class));
+    }
+
+    @Override
+    public void initialize() throws IllegalStateException {
+        super.initialize();
+        if (!inited.compareAndSet(false, true)) {
+            return;
+        }
+        CompositeConfiguration configuration = applicationModel.getApplicationEnvironment().getConfiguration();
+
+        String ignoreDuplicatedInterfaceStr = (String) configuration
+            .getProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE);
+        if (ignoreDuplicatedInterfaceStr != null) {
+            this.ignoreDuplicatedInterface = Boolean.parseBoolean(ignoreDuplicatedInterfaceStr);
+        }
+        logger.info("Config settings - ignore duplicated interface: " + ignoreDuplicatedInterface);
+    }
+
+    // ServiceConfig correlative methods
+
+    public void addService(ServiceConfigBase<?> serviceConfig) {
+        addConfig(serviceConfig);
+    }
+
+    public void addServices(Iterable<ServiceConfigBase<?>> serviceConfigs) {
+        serviceConfigs.forEach(this::addService);
+    }
+
+    public Collection<ServiceConfigBase> getServices() {
+        return getConfigs(getTagName(ServiceConfigBase.class));
+    }
+
+    public <T> ServiceConfigBase<T> getService(String id) {
+        return getConfig(ServiceConfigBase.class, id).orElse(null);
+    }
+
+    // ReferenceConfig correlative methods
+
+    public void addReference(ReferenceConfigBase<?> referenceConfig) {
+        addConfig(referenceConfig);
+    }
+
+    public void addReferences(Iterable<ReferenceConfigBase<?>> referenceConfigs) {
+        referenceConfigs.forEach(this::addReference);
+    }
+
+    public Collection<ReferenceConfigBase<?>> getReferences() {
+        return getConfigs(getTagName(ReferenceConfigBase.class));
+    }
+
+    public <T> ReferenceConfigBase<T> getReference(String id) {
+        return getConfig(ReferenceConfigBase.class, id).orElse(null);
+    }
+
+    public void addProvider(ProviderConfig providerConfig) {
+        addConfig(providerConfig);
+    }
+
+    public void addProviders(Iterable<ProviderConfig> providerConfigs) {
+        providerConfigs.forEach(this::addProvider);
+    }
+
+    public Optional<ProviderConfig> getProvider(String id) {
+        return getConfig(ProviderConfig.class, id);
+    }
+
+    /**
+     * Only allows one default ProviderConfig
+     */
+    public Optional<ProviderConfig> getDefaultProvider() {
+        List<ProviderConfig> providerConfigs = getDefaultConfigs(getConfigsMap(getTagName(ProviderConfig.class)));
+        if (CollectionUtils.isNotEmpty(providerConfigs)) {
+            return Optional.of(providerConfigs.get(0));
+        }
+        return Optional.empty();
+    }
+
+    public Collection<ProviderConfig> getProviders() {
+        return getConfigs(getTagName(ProviderConfig.class));
+    }
+
+    // ConsumerConfig correlative methods
+
+    public void addConsumer(ConsumerConfig consumerConfig) {
+        addConfig(consumerConfig);
+    }
+
+    public void addConsumers(Iterable<ConsumerConfig> consumerConfigs) {
+        consumerConfigs.forEach(this::addConsumer);
+    }
+
+    public Optional<ConsumerConfig> getConsumer(String id) {
+        return getConfig(ConsumerConfig.class, id);
+    }
+
+    /**
+     * Only allows one default ConsumerConfig
+     */
+    public Optional<ConsumerConfig> getDefaultConsumer() {
+        List<ConsumerConfig> consumerConfigs = getDefaultConfigs(getConfigsMap(getTagName(ConsumerConfig.class)));
+        if (CollectionUtils.isNotEmpty(consumerConfigs)) {
+            return Optional.of(consumerConfigs.get(0));
+        }
+        return Optional.empty();
+    }
+
+    public Collection<ConsumerConfig> getConsumers() {
+        return getConfigs(getTagName(ConsumerConfig.class));
+    }
+
+    public void refreshAll() {
+        // refresh all configs here,
+        getProviders().forEach(ProviderConfig::refresh);
+        getConsumers().forEach(ConsumerConfig::refresh);
+
+        for (ReferenceConfigBase<?> reference : getReferences()) {
+            reference.refresh();
+        }
+
+        for (ServiceConfigBase sc : getServices()) {
+            sc.refresh();
+        }
+    }
+
+    public void clear() {
+        super.clear();
+        this.serviceConfigCache.clear();
+    }
+
+
+    @Override
+    protected <C extends AbstractConfig> Optional<C> findDuplicatedConfig(Map<String, C> configsMap, C config) {
+        // check duplicated configs
+        // special check service and reference config by unique service name, speed up the processing of large number of instances
+        if (config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase) {
+            C existedConfig = (C) findDuplicatedInterfaceConfig((AbstractInterfaceConfig) config);
+            if (existedConfig != null) {
+                return Optional.of(existedConfig);
+            }
+        } else {
+            return super.findDuplicatedConfig(configsMap, config);
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * check duplicated ReferenceConfig/ServiceConfig
+     *
+     * @param config
+     */
+    private AbstractInterfaceConfig findDuplicatedInterfaceConfig(AbstractInterfaceConfig config) {
+        String uniqueServiceName;
+        Map<String, AbstractInterfaceConfig> configCache;
+        if (config instanceof ReferenceConfigBase) {
+            return null;
+        } else if (config instanceof ServiceConfigBase) {
+            ServiceConfigBase serviceConfig = (ServiceConfigBase) config;
+            uniqueServiceName = serviceConfig.getUniqueServiceName();
+            configCache = serviceConfigCache;
+        } else {
+            throw new IllegalArgumentException("Illegal type of parameter 'config' : " + config.getClass().getName());
+        }
+
+        AbstractInterfaceConfig prevConfig = configCache.putIfAbsent(uniqueServiceName, config);
+        if (prevConfig != null) {
+            if (prevConfig == config) {
+                return prevConfig;
+            }
+
+            if (prevConfig.equals(config)) {
+                // Is there any problem with ignoring duplicate and equivalent but different ReferenceConfig instances?
+                if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {
+                    logger.warn("Ignore duplicated and equal config: " + config);
+                }
+                return prevConfig;
+            }
+
+            String configType = config.getClass().getSimpleName();
+            String msg = "Found multiple " + configType + "s with unique service name [" +
+                uniqueServiceName + "], previous: " + prevConfig + ", later: " + config + ". " +
+                "There can only be one instance of " + configType + " with the same triple (group, interface, version). " +
+                "If multiple instances are required for the same interface, please use a different group or version.";
+
+            if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {
+                logger.warn(msg);
+            }
+            if (!ignoreDuplicatedInterface) {
+                throw new IllegalStateException(msg);
+            }
+        }
+        return prevConfig;
+    }
+
+    @Override
+    public void loadConfigs() {
+        // load dubbo.providers.xxx
+        loadConfigsOfTypeFromProps(ProviderConfig.class);
+
+        // load dubbo.consumers.xxx
+        loadConfigsOfTypeFromProps(ConsumerConfig.class);
+
+        // check configs
+        checkDefaultAndValidateConfigs(ProviderConfig.class);
+        checkDefaultAndValidateConfigs(ConsumerConfig.class);
+    }
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java
index ad6e309..b7d84e6 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java
@@ -18,11 +18,13 @@ package org.apache.dubbo.rpc.model;
 
 import org.apache.dubbo.common.config.Environment;
 import org.apache.dubbo.common.context.FrameworkExt;
+import org.apache.dubbo.common.deploy.ApplicationDeployer;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.extension.ExtensionScope;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
+import org.apache.dubbo.common.utils.Assert;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.context.ConfigManager;
 
@@ -31,7 +33,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * {@link ExtensionLoader}, {@code DubboBootstrap} and this class are at present designed to be
@@ -49,7 +51,6 @@ import java.util.concurrent.atomic.AtomicLong;
 
 public class ApplicationModel extends ScopeModel {
     protected static final Logger LOGGER = LoggerFactory.getLogger(ApplicationModel.class);
-    private static final AtomicLong index = new AtomicLong(0);
     public static final String NAME = "ApplicationModel";
     private static volatile ApplicationModel defaultInstance;
 
@@ -62,6 +63,11 @@ public class ApplicationModel extends ScopeModel {
 
     private ModuleModel internalModule;
 
+    private volatile ModuleModel defaultModule;
+
+    // internal module index is 0, default module index is 1
+    private AtomicInteger moduleIndex = new AtomicInteger(0);
+
 
     // --------- static methods ----------//
 
@@ -152,16 +158,16 @@ public class ApplicationModel extends ScopeModel {
 
     public ApplicationModel(FrameworkModel frameworkModel) {
         super(frameworkModel, ExtensionScope.APPLICATION);
+        Assert.notNull(frameworkModel, "FrameworkModel can not be null");
         this.frameworkModel = frameworkModel;
         frameworkModel.addApplication(this);
         initialize();
-        this.modelName = NAME + "-" + index.getAndIncrement();
     }
 
     @Override
     protected void initialize() {
         super.initialize();
-        internalModule = new ModuleModel(this.modelName + "-internal", this);
+        internalModule = new ModuleModel(this);
         this.serviceRepository = new ServiceRepository(this);
 
         ExtensionLoader<ApplicationInitListener> extensionLoader = this.getExtensionLoader(ApplicationInitListener.class);
@@ -177,8 +183,6 @@ public class ApplicationModel extends ScopeModel {
         for (ScopeModelInitializer initializer : initializers) {
             initializer.initializeApplicationModel(this);
         }
-
-        postProcessAfterCreated();
     }
 
     private void initFrameworkExts() {
@@ -223,6 +227,10 @@ public class ApplicationModel extends ScopeModel {
         return frameworkModel;
     }
 
+    public synchronized ModuleModel newModule() {
+        return new ModuleModel(this);
+    }
+
     public Environment getApplicationEnvironment() {
         if (environment == null) {
             environment = (Environment) this.getExtensionLoader(FrameworkExt.class)
@@ -255,33 +263,47 @@ public class ApplicationModel extends ScopeModel {
         return getCurrentConfig().getName();
     }
 
-    public synchronized void addModule(ModuleModel model) {
-        if (!this.moduleModels.contains(model)) {
-            this.moduleModels.add(model);
+    synchronized void addModule(ModuleModel moduleModel) {
+        if (!this.moduleModels.contains(moduleModel)) {
+            this.moduleModels.add(moduleModel);
+            moduleModel.setInternalName(buildInternalName(ModuleModel.NAME, getInternalId(), moduleIndex.getAndIncrement()));
         }
     }
 
-    public synchronized void removeModule(ModuleModel model) {
-        this.moduleModels.remove(model);
+    synchronized void removeModule(ModuleModel moduleModel) {
+        this.moduleModels.remove(moduleModel);
+        if (moduleModel == defaultModule) {
+            defaultModule = findDefaultModule();
+        }
         if (this.moduleModels.size() == 1 && this.moduleModels.get(0) == internalModule) {
             this.internalModule.destroy();
         }
-        destroy();
+        if (this.moduleModels.isEmpty()) {
+            destroy();
+        }
     }
 
     public List<ModuleModel> getModuleModels() {
-        return moduleModels;
+        return Collections.unmodifiableList(moduleModels);
     }
 
     public synchronized ModuleModel getDefaultModule() {
+        if (defaultModule == null) {
+            defaultModule = findDefaultModule();
+            if (defaultModule == null) {
+                defaultModule = this.newModule();
+            }
+        }
+        return defaultModule;
+    }
+
+    private ModuleModel findDefaultModule() {
         for (ModuleModel moduleModel : moduleModels) {
             if (moduleModel != internalModule) {
                 return moduleModel;
             }
         }
-        ModuleModel moduleModel = new ModuleModel(this);
-        this.addModule(moduleModel);
-        return moduleModel;
+        return null;
     }
 
     public ModuleModel getInternalModule() {
@@ -327,4 +349,12 @@ public class ApplicationModel extends ScopeModel {
     protected boolean containsClassLoader(ClassLoader classLoader) {
         return moduleModels.stream().anyMatch(moduleModel -> moduleModel.getClassLoaders().contains(classLoader));
     }
+
+    public ApplicationDeployer getDeployer() {
+        return getAttribute(ModelConstants.DEPLOYER, ApplicationDeployer.class);
+    }
+
+    public void setDeployer(ApplicationDeployer deployer) {
+        setAttribute(ModelConstants.DEPLOYER, deployer);
+    }
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/FrameworkModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/FrameworkModel.java
index 53ee49c..547485f 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/FrameworkModel.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/FrameworkModel.java
@@ -34,8 +34,11 @@ public class FrameworkModel extends ScopeModel {
 
     protected static final Logger LOGGER = LoggerFactory.getLogger(FrameworkModel.class);
 
-    private static final AtomicLong index = new AtomicLong(0);
     public static final String NAME = "FrameworkModel";
+    private static final AtomicLong index = new AtomicLong(1);
+    // app index starts from 1 in each FrameworkModel
+    private final AtomicLong appIndex = new AtomicLong(1);
+
     private volatile static FrameworkModel defaultInstance;
 
     private static List<FrameworkModel> allInstances = Collections.synchronizedList(new ArrayList<>());
@@ -45,10 +48,11 @@ public class FrameworkModel extends ScopeModel {
     private FrameworkServiceRepository serviceRepository;
 
 
+
     public FrameworkModel() {
         super(null, ExtensionScope.FRAMEWORK);
         initialize();
-        this.modelName = NAME + "-" + index.getAndIncrement();
+        this.setInternalName(buildInternalName(NAME, null, index.getAndIncrement()));
     }
 
     @Override
@@ -62,9 +66,6 @@ public class FrameworkModel extends ScopeModel {
         for (ScopeModelInitializer initializer : initializers) {
             initializer.initializeFrameworkModel(this);
         }
-
-
-        postProcessAfterCreated();
     }
 
     @Override
@@ -105,13 +106,18 @@ public class FrameworkModel extends ScopeModel {
         }
     }
 
-    public void addApplication(ApplicationModel model) {
-        if (!this.applicationModels.contains(model)) {
-            this.applicationModels.add(model);
+    public ApplicationModel newApplication() {
+        return new ApplicationModel(this);
+    }
+
+    synchronized void addApplication(ApplicationModel applicationModel) {
+        if (!this.applicationModels.contains(applicationModel)) {
+            this.applicationModels.add(applicationModel);
+            applicationModel.setInternalName(buildInternalName(ApplicationModel.NAME, getInternalId(), appIndex.getAndIncrement()));
         }
     }
 
-    public void removeApplication(ApplicationModel model) {
+    synchronized void removeApplication(ApplicationModel model) {
         this.applicationModels.remove(model);
         if (applicationModels.size() == 0) {
             destroy();
@@ -119,7 +125,7 @@ public class FrameworkModel extends ScopeModel {
     }
 
     public List<ApplicationModel> getApplicationModels() {
-        return applicationModels;
+        return Collections.unmodifiableList(applicationModels);
     }
 
     public FrameworkServiceRepository getServiceRepository() {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelPostProcessor.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelConstants.java
similarity index 65%
copy from dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelPostProcessor.java
copy to dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelConstants.java
index 5a78a3f..d226d6d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelPostProcessor.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelConstants.java
@@ -16,19 +16,8 @@
  */
 package org.apache.dubbo.rpc.model;
 
-import org.apache.dubbo.common.extension.ExtensionScope;
-import org.apache.dubbo.common.extension.SPI;
+public interface ModelConstants {
 
-/**
- * A post-processor after scope model is created (one of FrameworkModel/ApplicationModel/ModuleModel)
- */
-@SPI(scope = ExtensionScope.FRAMEWORK)
-public interface ScopeModelPostProcessor {
-
-    /**
-     * Post-process after a scope model is created.
-     * @param scopeModel
-     */
-    void postProcessScopeModel(ScopeModel scopeModel);
+    String DEPLOYER = "deployer";
 
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java
index 81e9114..5f16a6f 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java
@@ -16,10 +16,13 @@
  */
 package org.apache.dubbo.rpc.model;
 
+import org.apache.dubbo.common.deploy.ModuleDeployer;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.extension.ExtensionScope;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.Assert;
+import org.apache.dubbo.config.context.ModuleConfigManager;
 
 import java.util.List;
 import java.util.Set;
@@ -36,31 +39,29 @@ public class ModuleModel extends ScopeModel {
 
     private final ApplicationModel applicationModel;
     private ModuleServiceRepository serviceRepository;
+    private ModuleConfigManager moduleConfigManager;
 
-    public ModuleModel(ApplicationModel applicationModel) {
-        this(NAME + "-" + index.getAndIncrement(), applicationModel);
-    }
 
-    public ModuleModel(String name, ApplicationModel applicationModel) {
+    public ModuleModel(ApplicationModel applicationModel) {
         super(applicationModel, ExtensionScope.MODULE);
+        Assert.notNull(applicationModel, "ApplicationModel can not be null");
         this.applicationModel = applicationModel;
         applicationModel.addModule(this);
         initialize();
-        this.modelName = name;
     }
 
     @Override
     protected void initialize() {
         super.initialize();
         this.serviceRepository = new ModuleServiceRepository(this);
+        this.moduleConfigManager = new ModuleConfigManager(this);
+        this.moduleConfigManager.initialize();
 
         ExtensionLoader<ScopeModelInitializer> initializerExtensionLoader = this.getExtensionLoader(ScopeModelInitializer.class);
         Set<ScopeModelInitializer> initializers = initializerExtensionLoader.getSupportedExtensionInstances();
         for (ScopeModelInitializer initializer : initializers) {
             initializer.initializeModuleModel(this);
         }
-
-        postProcessAfterCreated();
     }
 
     @Override
@@ -108,4 +109,16 @@ public class ModuleModel extends ScopeModel {
     public ModuleServiceRepository getServiceRepository() {
         return serviceRepository;
     }
+
+    public ModuleConfigManager getConfigManager() {
+        return moduleConfigManager;
+    }
+
+    public ModuleDeployer getDeployer() {
+        return getAttribute(ModelConstants.DEPLOYER, ModuleDeployer.class);
+    }
+
+    public void setDeployer(ModuleDeployer deployer) {
+        setAttribute(ModelConstants.DEPLOYER, deployer);
+    }
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java
index 4b1d9ed..b22e0e9 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java
@@ -33,7 +33,21 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 public abstract class ScopeModel implements ExtensionAccessor {
 
-    protected String modelName;
+    /**
+     * The internal name is used to represent the hierarchy of the model tree, such as:
+     * <ol>
+     *     <li>FrameworkModel-1</li>
+     *     FrameworkModel (index=1)
+     *     <li>ApplicationModel-1.2</li>
+     *     FrameworkModel (index=1) -> ApplicationModel (index=2)
+     *     <li>ModuleModel-1.2.0</li>
+     *     FrameworkModel (index=1) -> ApplicationModel (index=2) -> ModuleModel (index=0, internal module)
+     *     <li>ModuleModel-1.2.1</li>
+     *     FrameworkModel (index=1) -> ApplicationModel (index=2) -> ModuleModel (index=1, first user module)
+     * </ol>
+     */
+    private String internalName;
+
     private Set<ClassLoader> classLoaders;
 
     private final ScopeModel parent;
@@ -44,7 +58,7 @@ public abstract class ScopeModel implements ExtensionAccessor {
     private ScopeBeanFactory beanFactory;
     private List<ScopeModelDestroyListener> destroyListeners;
 
-    private Map<String, Object> attribute;
+    private Map<String, Object> attributes;
     private AtomicBoolean destroyed = new AtomicBoolean(false);
 
     public ScopeModel(ScopeModel parent, ExtensionScope scope) {
@@ -66,7 +80,7 @@ public abstract class ScopeModel implements ExtensionAccessor {
         this.extensionDirector.addExtensionPostProcessor(new ScopeModelAwareExtensionProcessor(this));
         this.beanFactory = new ScopeBeanFactory(parent != null ? parent.getBeanFactory() : null, extensionDirector);
         this.destroyListeners = new LinkedList<>();
-        this.attribute = new ConcurrentHashMap<>();
+        this.attributes = new ConcurrentHashMap<>();
         this.classLoaders = new ConcurrentHashSet<>();
 
         // Add Framework's ClassLoader by default
@@ -84,7 +98,7 @@ public abstract class ScopeModel implements ExtensionAccessor {
                     removeClassLoader(classLoader);
                 }
                 onDestroy();
-            }catch (Throwable t) {
+            } catch (Throwable t) {
                 t.printStackTrace();
             }
         }
@@ -102,8 +116,20 @@ public abstract class ScopeModel implements ExtensionAccessor {
         destroyListeners.add(listener);
     }
 
-    public Map<String, Object> getAttribute() {
-        return attribute;
+    public Map<String, Object> getAttributes() {
+        return attributes;
+    }
+
+    public <T> T getAttribute(String key, Class<T> type) {
+        return (T) attributes.get(key);
+    }
+
+    public Object getAttribute(String key) {
+        return attributes.get(key);
+    }
+
+    public void setAttribute(String key, Object value) {
+        attributes.put(key, value);
     }
 
     public ExtensionDirector getExtensionDirector() {
@@ -118,20 +144,12 @@ public abstract class ScopeModel implements ExtensionAccessor {
         return parent;
     }
 
-    protected void postProcessAfterCreated() {
-        Set<ScopeModelPostProcessor> scopeModelPostProcessors = getExtensionLoader(ScopeModelPostProcessor.class)
-            .getSupportedExtensionInstances();
-        for (ScopeModelPostProcessor processor : scopeModelPostProcessors) {
-            processor.postProcessScopeModel(this);
-        }
+    public String getInternalName() {
+        return internalName;
     }
 
-    public String getModelName() {
-        return modelName;
-    }
-
-    public void setModelName(String modelName) {
-        this.modelName = modelName;
+    protected void setInternalName(String internalName) {
+        this.internalName = internalName;
     }
 
     public void addClassLoader(ClassLoader classLoader) {
@@ -159,4 +177,23 @@ public abstract class ScopeModel implements ExtensionAccessor {
     public Set<ClassLoader> getClassLoaders() {
         return Collections.unmodifiableSet(classLoaders);
     }
+
+    public String getInternalId() {
+        // XxxModule-1.1
+        if (this.internalName == null) {
+            return null;
+        }
+        return this.internalName.substring(this.internalName.indexOf('-') + 1);
+    }
+
+    protected String buildInternalName(String type, String parentInternalId, long childIndex) {
+        // FrameworkModel-1
+        // ApplicationModel-1.1
+        // ModuleModel-1.1.1
+        if (parentInternalId != null) {
+            return type + "-" + parentInternalId + "." + childIndex;
+        } else {
+            return type + "-" + childIndex;
+        }
+    }
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/AdaptiveCompilerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/AdaptiveCompilerTest.java
index 8252470..4192c36 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/AdaptiveCompilerTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/compiler/support/AdaptiveCompilerTest.java
@@ -17,7 +17,6 @@
 package org.apache.dubbo.common.compiler.support;
 
 import org.apache.dubbo.rpc.model.FrameworkModel;
-
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionDirectorTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionDirectorTest.java
index 0a68d06..e0031d4 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionDirectorTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionDirectorTest.java
@@ -25,7 +25,6 @@ import org.apache.dubbo.common.extension.director.impl.TestModuleService;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 import org.apache.dubbo.rpc.model.ModuleModel;
-
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/ActivateComparatorTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/ActivateComparatorTest.java
index 29d8b1c..c6baf04 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/ActivateComparatorTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/support/ActivateComparatorTest.java
@@ -17,7 +17,6 @@
 package org.apache.dubbo.common.extension.support;
 
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/lang/ShutdownHookCallbacksTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/lang/ShutdownHookCallbacksTest.java
index c599148..6d0e7a4 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/lang/ShutdownHookCallbacksTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/lang/ShutdownHookCallbacksTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.dubbo.common.lang;
 
+import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -34,7 +35,7 @@ public class ShutdownHookCallbacksTest {
 
     @BeforeEach
     public void init() {
-        callbacks = new ShutdownHookCallbacks();
+        callbacks = new ShutdownHookCallbacks(ApplicationModel.defaultModel());
     }
 
     @Test
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java
index c83765f..685569c 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java
@@ -17,7 +17,6 @@
 package org.apache.dubbo.common.logger;
 
 import org.apache.dubbo.rpc.model.FrameworkModel;
-
 import org.junit.jupiter.api.Test;
 
 import java.io.File;
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ConfigUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ConfigUtilsTest.java
index 76f6977..5fda7ff 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ConfigUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/ConfigUtilsTest.java
@@ -21,7 +21,6 @@ import org.apache.dubbo.common.config.InmemoryConfiguration;
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.common.threadpool.ThreadPool;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/NetUtilsInterfaceDisplayNameHasMetaCharactersTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/NetUtilsInterfaceDisplayNameHasMetaCharactersTest.java
index e927c50..6e6ce36 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/NetUtilsInterfaceDisplayNameHasMetaCharactersTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/NetUtilsInterfaceDisplayNameHasMetaCharactersTest.java
@@ -20,10 +20,10 @@ import org.junit.jupiter.api.Test;
 import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 
-import java.util.Enumeration;
-import java.util.NoSuchElementException;
 import java.net.InetAddress;
 import java.net.NetworkInterface;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
 
 import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_NETWORK_IGNORED_INTERFACE;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -110,4 +110,4 @@ public class NetUtilsInterfaceDisplayNameHasMetaCharactersTest {
         }
     }
 
-}
\ No newline at end of file
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
index a80fffd..8894252 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
@@ -26,7 +26,6 @@ import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.ProviderConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -50,6 +49,7 @@ import static org.junit.jupiter.api.Assertions.fail;
 public class ConfigManagerTest {
 
     private ConfigManager configManager = ApplicationModel.defaultModel().getApplicationConfigManager();
+    private ModuleConfigManager moduleConfigManager = ApplicationModel.defaultModel().getDefaultModule().getConfigManager();
 
     @BeforeEach
     public void init() {
@@ -69,12 +69,6 @@ public class ConfigManagerTest {
         assertFalse(configManager.getModule().isPresent());
         assertFalse(configManager.getMetrics().isPresent());
 
-        // providers and consumers
-        assertFalse(configManager.getDefaultProvider().isPresent());
-        assertFalse(configManager.getDefaultConsumer().isPresent());
-        assertTrue(configManager.getProviders().isEmpty());
-        assertTrue(configManager.getConsumers().isEmpty());
-
         // protocols
         assertTrue(configManager.getProtocols().isEmpty());
         assertTrue(configManager.getDefaultProtocols().isEmpty());
@@ -83,15 +77,21 @@ public class ConfigManagerTest {
         assertTrue(configManager.getRegistries().isEmpty());
         assertTrue(configManager.getDefaultRegistries().isEmpty());
 
-        // services and references
-        assertTrue(configManager.getServices().isEmpty());
-        assertTrue(configManager.getReferences().isEmpty());
-
         // config centers
         assertTrue(configManager.getConfigCenters().isEmpty());
 
         // metadata
         assertTrue(configManager.getMetadataConfigs().isEmpty());
+
+        // services and references
+        assertTrue(moduleConfigManager.getServices().isEmpty());
+        assertTrue(moduleConfigManager.getReferences().isEmpty());
+
+        // providers and consumers
+        assertFalse(moduleConfigManager.getDefaultProvider().isPresent());
+        assertFalse(moduleConfigManager.getDefaultConsumer().isPresent());
+        assertTrue(moduleConfigManager.getProviders().isEmpty());
+        assertTrue(moduleConfigManager.getConsumers().isEmpty());
     }
 
     // Test ApplicationConfig correlative methods
@@ -135,18 +135,18 @@ public class ConfigManagerTest {
     @Test
     public void testProviderConfig() {
         ProviderConfig config = new ProviderConfig();
-        configManager.addProviders(asList(config, null));
-        Collection<ProviderConfig> configs = configManager.getProviders();
+        moduleConfigManager.addProviders(asList(config, null));
+        Collection<ProviderConfig> configs = moduleConfigManager.getProviders();
         assertEquals(1, configs.size());
         assertEquals(config, configs.iterator().next());
-        assertTrue(configManager.getDefaultProvider().isPresent());
+        assertTrue(moduleConfigManager.getDefaultProvider().isPresent());
 
         config = new ProviderConfig();
         config.setId(DEFAULT_KEY);
         config.setQueues(10);
-        configManager.addProvider(config);
-        assertTrue(configManager.getDefaultProvider().isPresent());
-        configs = configManager.getProviders();
+        moduleConfigManager.addProvider(config);
+        assertTrue(moduleConfigManager.getDefaultProvider().isPresent());
+        configs = moduleConfigManager.getProviders();
         assertEquals(2, configs.size());
     }
 
@@ -154,18 +154,18 @@ public class ConfigManagerTest {
     @Test
     public void testConsumerConfig() {
         ConsumerConfig config = new ConsumerConfig();
-        configManager.addConsumers(asList(config, null));
-        Collection<ConsumerConfig> configs = configManager.getConsumers();
+        moduleConfigManager.addConsumers(asList(config, null));
+        Collection<ConsumerConfig> configs = moduleConfigManager.getConsumers();
         assertEquals(1, configs.size());
         assertEquals(config, configs.iterator().next());
-        assertTrue(configManager.getDefaultConsumer().isPresent());
+        assertTrue(moduleConfigManager.getDefaultConsumer().isPresent());
 
         config = new ConsumerConfig();
         config.setId(DEFAULT_KEY);
         config.setThreads(10);
-        configManager.addConsumer(config);
-        assertTrue(configManager.getDefaultConsumer().isPresent());
-        configs = configManager.getConsumers();
+        moduleConfigManager.addConsumer(config);
+        assertTrue(moduleConfigManager.getDefaultConsumer().isPresent());
+        configs = moduleConfigManager.getConsumers();
         assertEquals(2, configs.size());
     }
 
@@ -216,12 +216,12 @@ public class ConfigManagerTest {
     @Test
     public void testAddConfig() {
         configManager.addConfig(new ApplicationConfig("ConfigManagerTest"));
-        configManager.addConfig(new ProviderConfig());
         configManager.addConfig(new ProtocolConfig());
+        moduleConfigManager.addConfig(new ProviderConfig());
 
         assertTrue(configManager.getApplication().isPresent());
-        assertFalse(configManager.getProviders().isEmpty());
         assertFalse(configManager.getProtocols().isEmpty());
+        assertFalse(moduleConfigManager.getProviders().isEmpty());
     }
 
     @Test
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java
similarity index 59%
copy from dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java
index 8caab81..994116d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java
@@ -14,16 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.common;
+package org.apache.dubbo.config;
 
 import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
-import org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;
+import org.apache.dubbo.common.deploy.ApplicationDeployer;
+import org.apache.dubbo.common.deploy.ModuleDeployer;
+import org.apache.dubbo.config.bootstrap.DefaultApplicationDeployer;
+import org.apache.dubbo.config.bootstrap.DefaultModuleDeployer;
+import org.apache.dubbo.config.utils.DefaultConfigValidator;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 import org.apache.dubbo.rpc.model.ModuleModel;
 import org.apache.dubbo.rpc.model.ScopeModelInitializer;
 
-public class CommonScopeModelInitializer implements ScopeModelInitializer {
+public class ConfigScopeModelInitializer implements ScopeModelInitializer {
+
     @Override
     public void initializeFrameworkModel(FrameworkModel frameworkModel) {
 
@@ -32,11 +37,19 @@ public class CommonScopeModelInitializer implements ScopeModelInitializer {
     @Override
     public void initializeApplicationModel(ApplicationModel applicationModel) {
         ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
-        beanFactory.registerBean(FrameworkStatusReportService.class);
+        beanFactory.registerBean(DubboShutdownHook.class);
+        beanFactory.registerBean(DefaultConfigValidator.class);
+        // applicationDeployer
+        ApplicationDeployer applicationDeployer = beanFactory.registerBean(DefaultApplicationDeployer.class);
+        applicationModel.setDeployer(applicationDeployer);
+
     }
 
     @Override
     public void initializeModuleModel(ModuleModel moduleModel) {
-
+        ScopeBeanFactory beanFactory = moduleModel.getBeanFactory();
+        // moduleDeployer
+        ModuleDeployer moduleDeployer = beanFactory.registerBean(DefaultModuleDeployer.class);
+        moduleModel.setDeployer(moduleDeployer);
     }
 }
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 9e03a23..45daa42 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
@@ -16,10 +16,14 @@
  */
 package org.apache.dubbo.config;
 
+import org.apache.dubbo.common.lang.ShutdownHookCallback;
 import org.apache.dubbo.common.lang.ShutdownHookCallbacks;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.Assert;
+import org.apache.dubbo.rpc.model.ApplicationModel;
 
+import java.util.Collection;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -32,9 +36,7 @@ public class DubboShutdownHook extends Thread {
 
     private static final Logger logger = LoggerFactory.getLogger(DubboShutdownHook.class);
 
-    private static final DubboShutdownHook DUBBO_SHUTDOWN_HOOK = new DubboShutdownHook("DubboShutdownHook");
-
-    private final ShutdownHookCallbacks callbacks = ShutdownHookCallbacks.INSTANCE;
+    private final ShutdownHookCallbacks callbacks;
 
     /**
      * Has it already been registered or not?
@@ -46,13 +48,15 @@ public class DubboShutdownHook extends Thread {
      */
     private final AtomicBoolean destroyed = new AtomicBoolean(false);
 
-    private DubboShutdownHook(String name) {
-        super(name);
+    public DubboShutdownHook(ApplicationModel applicationModel) {
+        super("DubboShutdownHook");
+        this.callbacks = applicationModel.getBeanFactory().getBean(ShutdownHookCallbacks.class);
+        Assert.notNull(this.callbacks, "ShutdownHookCallbacks is null");
     }
 
-    public static DubboShutdownHook getDubboShutdownHook() {
-        return DUBBO_SHUTDOWN_HOOK;
-    }
+//    public static DubboShutdownHook getDubboShutdownHook() {
+//        return DUBBO_SHUTDOWN_HOOK;
+//    }
 
     @Override
     public void run() {
@@ -85,13 +89,21 @@ public class DubboShutdownHook extends Thread {
         callbacks.callback();
     }
 
+    public DubboShutdownHook addCallback(ShutdownHookCallback callback) {
+        callbacks.addCallback(callback);
+        return this;
+    }
+
+    public Collection<ShutdownHookCallback> getCallbacks() {
+        return callbacks.getCallbacks();
+    }
+
     /**
      * Register the ShutdownHook
      */
     public void register() {
         if (registered.compareAndSet(false, true)) {
-            DubboShutdownHook dubboShutdownHook = getDubboShutdownHook();
-            Runtime.getRuntime().addShutdownHook(dubboShutdownHook);
+            Runtime.getRuntime().addShutdownHook(this);
         }
     }
 
@@ -100,8 +112,7 @@ public class DubboShutdownHook extends Thread {
      */
     public void unregister() {
         if (registered.compareAndSet(true, false)) {
-            DubboShutdownHook dubboShutdownHook = getDubboShutdownHook();
-            Runtime.getRuntime().removeShutdownHook(dubboShutdownHook);
+            Runtime.getRuntime().removeShutdownHook(this);
         }
     }
 
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 0dade4d..e13400e 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
@@ -29,7 +29,6 @@ import org.apache.dubbo.common.utils.NetUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.common.utils.UrlUtils;
 import org.apache.dubbo.config.annotation.Reference;
-import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.support.Parameter;
 import org.apache.dubbo.config.utils.ConfigValidationUtils;
 import org.apache.dubbo.registry.client.metadata.MetadataUtils;
@@ -40,6 +39,7 @@ 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.registry.ZoneAwareCluster;
+import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.AsyncMethodInfo;
 import org.apache.dubbo.rpc.model.ConsumerModel;
 import org.apache.dubbo.rpc.model.ModuleServiceRepository;
@@ -134,8 +134,6 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
      */
     private transient volatile boolean destroyed;
 
-    private DubboBootstrap bootstrap;
-
     /**
      * The service names that the Dubbo interface subscribed.
      *
@@ -152,8 +150,8 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
     }
 
     @Override
-    protected void postProcessAfterScopeModelChanged() {
-        super.postProcessAfterScopeModelChanged();
+    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {
+        super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);
 
         protocolSPI = this.getExtensionLoader(Protocol.class).getAdaptiveExtension();
         proxyFactory = this.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
@@ -210,6 +208,7 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
 
     @Override
     public synchronized void destroy() {
+        super.destroy();
         if (destroyed) {
             return;
         }
@@ -227,6 +226,7 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
             ModuleServiceRepository repository = getScopeModel().getServiceRepository();
             repository.unregisterConsumer(consumerModel);
         }
+        getScopeModel().getConfigManager().removeConfig(this);
     }
 
     protected synchronized void init() {
@@ -234,19 +234,12 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
             return;
         }
 
-        // Using DubboBootstrap API will associate bootstrap when registering reference.
-        // Loading by Spring context will associate bootstrap in afterPropertiesSet() method.
-        // Initializing bootstrap here only for compatible with old API usages.
-        if (bootstrap == null) {
-            bootstrap = DubboBootstrap.getInstance(getScopeModel().getApplicationModel());
-            bootstrap.initialize();
-            bootstrap.reference(this);
+        if (getScopeModel() == null) {
+            setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
         }
 
-        // check bootstrap state
-        if (!bootstrap.isInitialized()) {
-            throw new IllegalStateException("DubboBootstrap is not initialized");
-        }
+        // prepare application for reference
+        getScopeModel().getDeployer().prepare();
 
         if (!this.isRefreshed()) {
             this.refresh();
@@ -606,14 +599,6 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
         return isJvmRefer;
     }
 
-    public DubboBootstrap getBootstrap() {
-        return bootstrap;
-    }
-
-    public void setBootstrap(DubboBootstrap bootstrap) {
-        this.bootstrap = bootstrap;
-    }
-
     private void postProcessConfig() {
         List<ConfigPostProcessor> configPostProcessors = this.getExtensionLoader(ConfigPostProcessor.class)
             .getActivateExtension(URL.valueOf("configPostProcessor://"), (String[]) null);
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 b1f4cac..fe96dd3 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
@@ -19,6 +19,7 @@ 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.deploy.ModuleDeployer;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
@@ -29,8 +30,6 @@ 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.bootstrap.BootstrapTakeoverMode;
-import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker;
 import org.apache.dubbo.config.support.Parameter;
 import org.apache.dubbo.config.utils.ConfigValidationUtils;
@@ -45,6 +44,7 @@ import org.apache.dubbo.rpc.ProxyFactory;
 import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
 import org.apache.dubbo.rpc.model.ModuleServiceRepository;
 import org.apache.dubbo.rpc.model.ProviderModel;
+import org.apache.dubbo.rpc.model.ScopeModel;
 import org.apache.dubbo.rpc.model.ServiceDescriptor;
 import org.apache.dubbo.rpc.service.GenericService;
 import org.apache.dubbo.rpc.support.ProtocolUtils;
@@ -133,8 +133,6 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
      */
     private transient volatile boolean unexported;
 
-    private DubboBootstrap bootstrap;
-
     private transient volatile AtomicBoolean initialized = new AtomicBoolean(false);
 
     /**
@@ -153,8 +151,8 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
     }
 
     @Override
-    protected void postProcessAfterScopeModelChanged() {
-        super.postProcessAfterScopeModelChanged();
+    protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {
+        super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);
         protocolSPI = this.getExtensionLoader(Protocol.class).getAdaptiveExtension();
         proxyFactory = this.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
         localMetadataService = this.getScopeModel().getDefaultExtension(WritableMetadataService.class);
@@ -197,42 +195,33 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
         repository.unregisterProvider(providerModel);
     }
 
-    public void init() {
+    private void init() {
         if (this.initialized.compareAndSet(false, true)) {
-            if (this.bootstrap == null) {
-                this.bootstrap = DubboBootstrap.getInstance(getScopeModel().getApplicationModel());
-                this.bootstrap.initialize();
-            }
-            this.bootstrap.service(this);
+            initServiceMetadata(provider);
+            serviceMetadata.setServiceType(getInterfaceClass());
+            serviceMetadata.setTarget(getRef());
+            serviceMetadata.generateServiceKey();
 
             // load ServiceListeners from extension
             ExtensionLoader<ServiceListener> extensionLoader = this.getExtensionLoader(ServiceListener.class);
             this.serviceListeners.addAll(extensionLoader.getSupportedExtensionInstances());
         }
-
-        initServiceMetadata(provider);
-        serviceMetadata.setServiceType(getInterfaceClass());
-        serviceMetadata.setTarget(getRef());
-        serviceMetadata.generateServiceKey();
     }
 
     @Override
     public synchronized void export() {
-        if (this.shouldExport() && !this.exported) {
-            this.init();
-
-            // check bootstrap state
-            if (!bootstrap.isInitialized()) {
-                throw new IllegalStateException("DubboBootstrap is not initialized");
-            }
-
-            if (!this.isRefreshed()) {
-                this.refresh();
-            }
+        if (this.exported) {
+            return;
+        }
+        // prepare for export
+        ModuleDeployer moduleDeployer = getScopeModel().getDeployer();
+        moduleDeployer.prepare();
 
-            if (!shouldExport()) {
-                return;
-            }
+        if (!this.isRefreshed()) {
+            this.refresh();
+        }
+        if (this.shouldExport()) {
+            this.init();
 
             if (shouldDelay()) {
                 doDelayExport();
@@ -240,9 +229,27 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
                 doExport();
             }
 
-            if (this.bootstrap.getTakeoverMode() == BootstrapTakeoverMode.AUTO) {
-                this.bootstrap.start();
-            }
+            // notify export this service
+            moduleDeployer.notifyExportService(this);
+        }
+    }
+
+    /**
+     * export service only, do not register application instance, for exporting services in batches by module
+     */
+    @Override
+    public synchronized void exportOnly() {
+        if (this.exported) {
+            return;
+        }
+        if (!this.isRefreshed()) {
+            this.refresh();
+        }
+        if (this.shouldExport()) {
+            this.init();
+
+            // just do export, delay export is done by caller
+            doExport();
         }
     }
 
@@ -813,14 +820,6 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
         configPostProcessors.forEach(component -> component.postProcessServiceConfig(this));
     }
 
-    public DubboBootstrap getBootstrap() {
-        return bootstrap;
-    }
-
-    public void setBootstrap(DubboBootstrap bootstrap) {
-        this.bootstrap = bootstrap;
-    }
-
     public void addServiceListener(ServiceListener listener) {
         this.serviceListeners.add(listener);
     }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/BootstrapTakeoverMode.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/BootstrapTakeoverMode.java
index 091de85..f2f3319 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/BootstrapTakeoverMode.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/BootstrapTakeoverMode.java
@@ -23,7 +23,7 @@ import org.apache.dubbo.config.ServiceConfig;
  * SPRING: will be controlled by spring context
  * MANUAL: will be controlled by users, after all services init, should call {@link DubboBootstrap#start()} to init app-level env
  * AUTO: env will be init once {@link ServiceConfig#export()} finished
- * SERVLET: will be controlled by tomcat
+ * SERVLET: will be controlled by java servlet container
  */
 public enum BootstrapTakeoverMode {
     SPRING, MANUAL, AUTO, SERVLET
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DefaultApplicationDeployer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DefaultApplicationDeployer.java
new file mode 100644
index 0000000..d8b7703
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DefaultApplicationDeployer.java
@@ -0,0 +1,941 @@
+/*
+ * 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.bootstrap;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.ConfigurationUtils;
+import org.apache.dubbo.common.config.Environment;
+import org.apache.dubbo.common.config.ReferenceCache;
+import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
+import org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory;
+import org.apache.dubbo.common.config.configcenter.wrapper.CompositeDynamicConfiguration;
+import org.apache.dubbo.common.deploy.ApplicationDeployer;
+import org.apache.dubbo.common.deploy.ModuleDeployer;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
+import org.apache.dubbo.common.utils.ArrayUtils;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ConfigCenterConfig;
+import org.apache.dubbo.config.DubboShutdownHook;
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.utils.CompositeReferenceCache;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+import org.apache.dubbo.metadata.MetadataService;
+import org.apache.dubbo.metadata.MetadataServiceExporter;
+import org.apache.dubbo.metadata.WritableMetadataService;
+import org.apache.dubbo.metadata.report.MetadataReportFactory;
+import org.apache.dubbo.metadata.report.MetadataReportInstance;
+import org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory;
+import org.apache.dubbo.registry.client.DefaultServiceInstance;
+import org.apache.dubbo.registry.client.ServiceInstance;
+import org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils;
+import org.apache.dubbo.registry.client.metadata.store.InMemoryWritableMetadataService;
+import org.apache.dubbo.registry.client.metadata.store.RemoteMetadataServiceImpl;
+import org.apache.dubbo.registry.support.AbstractRegistryFactory;
+import org.apache.dubbo.rpc.Protocol;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.ModuleModel;
+import org.apache.dubbo.rpc.model.ScopeModel;
+import org.apache.dubbo.rpc.model.ScopeModelUtil;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Supplier;
+
+import static java.lang.String.format;
+import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties;
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;
+import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SPLIT_PATTERN;
+import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE;
+import static org.apache.dubbo.common.function.ThrowableAction.execute;
+import static org.apache.dubbo.common.utils.StringUtils.isEmpty;
+import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
+import static org.apache.dubbo.metadata.MetadataConstants.DEFAULT_METADATA_PUBLISH_DELAY;
+import static org.apache.dubbo.metadata.MetadataConstants.METADATA_PUBLISH_DELAY_KEY;
+import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.calInstanceRevision;
+import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.setMetadataStorageType;
+import static org.apache.dubbo.registry.support.AbstractRegistryFactory.getServiceDiscoveries;
+import static org.apache.dubbo.remoting.Constants.CLIENT_KEY;
+
+/**
+ * initialize and start application instance
+ */
+public class DefaultApplicationDeployer implements ApplicationDeployer {
+
+    private static final Logger logger = LoggerFactory.getLogger(DefaultApplicationDeployer.class);
+
+    private final ApplicationModel applicationModel;
+
+    private final ConfigManager configManager;
+
+    private final Environment environment;
+
+    private final ReferenceCache referenceCache;
+
+    private final ExecutorRepository executorRepository;
+
+    protected AtomicBoolean initialized = new AtomicBoolean(false);
+
+    protected AtomicBoolean started = new AtomicBoolean(false);
+
+    protected AtomicBoolean startup = new AtomicBoolean(true);
+
+    protected AtomicBoolean destroyed = new AtomicBoolean(false);
+
+    protected AtomicBoolean shutdown = new AtomicBoolean(false);
+
+    private final Lock destroyLock = new ReentrantLock();
+
+    protected volatile boolean isCurrentlyInStart = false;
+
+    protected volatile ServiceInstance serviceInstance;
+
+    protected AtomicBoolean hasPreparedApplicationInstance = new AtomicBoolean(false);
+
+    protected volatile MetadataService metadataService;
+
+    protected volatile MetadataServiceExporter metadataServiceExporter;
+
+    protected ScheduledFuture<?> asyncMetadataFuture;
+    private String identifier;
+
+
+    public DefaultApplicationDeployer(ApplicationModel applicationModel) {
+        this.applicationModel = applicationModel;
+        configManager = applicationModel.getApplicationConfigManager();
+        environment = applicationModel.getApplicationEnvironment();
+
+        referenceCache = new CompositeReferenceCache(applicationModel);
+        executorRepository = getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
+    }
+
+    public static ApplicationDeployer get(ScopeModel moduleOrApplicationModel) {
+        ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(moduleOrApplicationModel);
+        ApplicationDeployer applicationDeployer = applicationModel.getDeployer();
+        if (applicationDeployer == null) {
+            applicationDeployer = applicationModel.getBeanFactory().getOrRegisterBean(DefaultApplicationDeployer.class);
+        }
+        return applicationDeployer;
+    }
+
+    @Override
+    public ApplicationModel getApplicationModel() {
+        return applicationModel;
+    }
+
+    private <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
+        return applicationModel.getExtensionLoader(type);
+    }
+
+    private void unRegisterShutdownHook() {
+        applicationModel.getBeanFactory().getBean(DubboShutdownHook.class).unregister();
+    }
+
+    private boolean isRegisterConsumerInstance() {
+        Boolean registerConsumer = getApplication().getRegisterConsumer();
+        return Boolean.TRUE.equals(registerConsumer);
+    }
+
+    private String getMetadataType() {
+        String type = getApplication().getMetadataType();
+        if (StringUtils.isEmpty(type)) {
+            type = DEFAULT_METADATA_STORAGE_TYPE;
+        }
+        return type;
+    }
+
+    @Override
+    public ReferenceCache getReferenceCache() {
+        return referenceCache;
+    }
+
+    /**
+     * Initialize
+     */
+    @Override
+    public synchronized void initialize() {
+        if (!initialized.compareAndSet(false, true)) {
+            return;
+        }
+        // register shutdown hook
+        registerShutdownHook();
+
+        startConfigCenter();
+
+        loadApplicationConfigs();
+
+        initModuleDeployers();
+
+        // @since 2.7.8
+        startMetadataCenter();
+
+        initMetadataService();
+
+        if (logger.isInfoEnabled()) {
+            logger.info(getIdentifier() + " has been initialized!");
+        }
+    }
+
+    private void registerShutdownHook() {
+        applicationModel.getBeanFactory().getBean(DubboShutdownHook.class)
+            .addCallback(DefaultApplicationDeployer.this::destroy)
+            .register();
+    }
+
+    private void initModuleDeployers() {
+        // make sure created default module
+        applicationModel.getDefaultModule();
+        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
+            moduleModel.getDeployer().initialize();
+        }
+    }
+
+    private void loadApplicationConfigs() {
+        configManager.loadConfigs();
+    }
+
+    private void startConfigCenter() {
+
+        // load application config
+        configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class);
+
+        // load config centers
+        configManager.loadConfigsOfTypeFromProps(ConfigCenterConfig.class);
+
+        useRegistryAsConfigCenterIfNecessary();
+
+        // check Config Center
+        Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();
+        if (CollectionUtils.isEmpty(configCenters)) {
+            ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
+            configCenterConfig.setScopeModel(applicationModel);
+            configCenterConfig.refresh();
+            ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
+            if (configCenterConfig.isValid()) {
+                configManager.addConfigCenter(configCenterConfig);
+                configCenters = configManager.getConfigCenters();
+            }
+        } else {
+            for (ConfigCenterConfig configCenterConfig : configCenters) {
+                configCenterConfig.refresh();
+                ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
+            }
+        }
+
+        if (CollectionUtils.isNotEmpty(configCenters)) {
+            CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();
+            for (ConfigCenterConfig configCenter : configCenters) {
+                // Pass config from ConfigCenterBean to environment
+                environment.updateExternalConfigMap(configCenter.getExternalConfiguration());
+                environment.updateAppExternalConfigMap(configCenter.getAppExternalConfiguration());
+
+                // Fetch config from remote config center
+                compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));
+            }
+            environment.setDynamicConfiguration(compositeDynamicConfiguration);
+        }
+
+        configManager.refreshAll();
+    }
+
+    private void startMetadataCenter() {
+
+        useRegistryAsMetadataCenterIfNecessary();
+
+        ApplicationConfig applicationConfig = getApplication();
+
+        String metadataType = applicationConfig.getMetadataType();
+        // FIXME, multiple metadata config support.
+        Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();
+        if (CollectionUtils.isEmpty(metadataReportConfigs)) {
+            if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {
+                throw new IllegalStateException("No MetadataConfig found, Metadata Center address is required when 'metadata=remote' is enabled.");
+            }
+            return;
+        }
+
+        MetadataReportInstance metadataReportInstance = applicationModel.getBeanFactory().getBean(MetadataReportInstance.class);
+        for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) {
+            ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);
+            if (!metadataReportConfig.isValid()) {
+                logger.info("Ignore invalid metadata-report config: " + metadataReportConfig);
+                continue;
+            }
+            metadataReportInstance.init(metadataReportConfig);
+        }
+    }
+
+    /**
+     * For compatibility purpose, use registry as the default config center when
+     * there's no config center specified explicitly and
+     * useAsConfigCenter of registryConfig is null or true
+     */
+    private void useRegistryAsConfigCenterIfNecessary() {
+        // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated.
+        if (environment.getDynamicConfiguration().isPresent()) {
+            return;
+        }
+
+        if (CollectionUtils.isNotEmpty(configManager.getConfigCenters())) {
+            return;
+        }
+
+        // load registry
+        configManager.loadConfigsOfTypeFromProps(RegistryConfig.class);
+
+        List<RegistryConfig> defaultRegistries = configManager.getDefaultRegistries();
+        if (defaultRegistries.size() > 0) {
+            defaultRegistries
+                .stream()
+                .filter(this::isUsedRegistryAsConfigCenter)
+                .map(this::registryAsConfigCenter)
+                .forEach(configCenter -> {
+                    if (configManager.getConfigCenter(configCenter.getId()).isPresent()) {
+                        return;
+                    }
+                    configManager.addConfigCenter(configCenter);
+                    logger.info("use registry as config-center: " + configCenter);
+
+                });
+        }
+    }
+
+    private boolean isUsedRegistryAsConfigCenter(RegistryConfig registryConfig) {
+        return isUsedRegistryAsCenter(registryConfig, registryConfig::getUseAsConfigCenter, "config",
+            DynamicConfigurationFactory.class);
+    }
+
+    private ConfigCenterConfig registryAsConfigCenter(RegistryConfig registryConfig) {
+        String protocol = registryConfig.getProtocol();
+        Integer port = registryConfig.getPort();
+        URL url = URL.valueOf(registryConfig.getAddress(), registryConfig.getScopeModel());
+        String id = "config-center-" + protocol + "-" + url.getHost() + "-" + port;
+        ConfigCenterConfig cc = new ConfigCenterConfig();
+        cc.setId(id);
+        cc.setScopeModel(applicationModel);
+        if (cc.getParameters() == null) {
+            cc.setParameters(new HashMap<>());
+        }
+        if (registryConfig.getParameters() != null) {
+            cc.getParameters().putAll(registryConfig.getParameters()); // copy the parameters
+        }
+        cc.getParameters().put(CLIENT_KEY, registryConfig.getClient());
+        cc.setProtocol(protocol);
+        cc.setPort(port);
+        if (StringUtils.isNotEmpty(registryConfig.getGroup())) {
+            cc.setGroup(registryConfig.getGroup());
+        }
+        cc.setAddress(getRegistryCompatibleAddress(registryConfig));
+        cc.setNamespace(registryConfig.getGroup());
+        cc.setUsername(registryConfig.getUsername());
+        cc.setPassword(registryConfig.getPassword());
+        if (registryConfig.getTimeout() != null) {
+            cc.setTimeout(registryConfig.getTimeout().longValue());
+        }
+        cc.setHighestPriority(false);
+        return cc;
+    }
+
+    private void useRegistryAsMetadataCenterIfNecessary() {
+
+        Collection<MetadataReportConfig> metadataConfigs = configManager.getMetadataConfigs();
+
+        if (CollectionUtils.isNotEmpty(metadataConfigs)) {
+            return;
+        }
+
+        List<RegistryConfig> defaultRegistries = configManager.getDefaultRegistries();
+        if (defaultRegistries.size() > 0) {
+            defaultRegistries
+                .stream()
+                .filter(this::isUsedRegistryAsMetadataCenter)
+                .map(this::registryAsMetadataCenter)
+                .forEach(metadataReportConfig -> {
+                    Optional<MetadataReportConfig> configOptional = configManager.getConfig(MetadataReportConfig.class, metadataReportConfig.getId());
+                    if (configOptional.isPresent()) {
+                        return;
+                    }
+                    configManager.addMetadataReport(metadataReportConfig);
+                    logger.info("use registry as metadata-center: " + metadataReportConfig);
+                });
+        }
+    }
+
+    private boolean isUsedRegistryAsMetadataCenter(RegistryConfig registryConfig) {
+        return isUsedRegistryAsCenter(registryConfig, registryConfig::getUseAsMetadataCenter, "metadata",
+            MetadataReportFactory.class);
+    }
+
+    /**
+     * Is used the specified registry as a center infrastructure
+     *
+     * @param registryConfig       the {@link RegistryConfig}
+     * @param usedRegistryAsCenter the configured value on
+     * @param centerType           the type name of center
+     * @param extensionClass       an extension class of a center infrastructure
+     * @return
+     * @since 2.7.8
+     */
+    private boolean isUsedRegistryAsCenter(RegistryConfig registryConfig, Supplier<Boolean> usedRegistryAsCenter,
+                                           String centerType,
+                                           Class<?> extensionClass) {
+        final boolean supported;
+
+        Boolean configuredValue = usedRegistryAsCenter.get();
+        if (configuredValue != null) { // If configured, take its value.
+            supported = configuredValue.booleanValue();
+        } else {                       // Or check the extension existence
+            String protocol = registryConfig.getProtocol();
+            supported = supportsExtension(extensionClass, protocol);
+            if (logger.isInfoEnabled()) {
+                logger.info(format("No value is configured in the registry, the %s extension[name : %s] %s as the %s center"
+                    , extensionClass.getSimpleName(), protocol, supported ? "supports" : "does not support", centerType));
+            }
+        }
+
+        if (logger.isInfoEnabled()) {
+            logger.info(format("The registry[%s] will be %s as the %s center", registryConfig,
+                supported ? "used" : "not used", centerType));
+        }
+        return supported;
+    }
+
+    /**
+     * Supports the extension with the specified class and name
+     *
+     * @param extensionClass the {@link Class} of extension
+     * @param name           the name of extension
+     * @return if supports, return <code>true</code>, or <code>false</code>
+     * @since 2.7.8
+     */
+    private boolean supportsExtension(Class<?> extensionClass, String name) {
+        if (isNotEmpty(name)) {
+            ExtensionLoader extensionLoader = getExtensionLoader(extensionClass);
+            return extensionLoader.hasExtension(name);
+        }
+        return false;
+    }
+
+    private MetadataReportConfig registryAsMetadataCenter(RegistryConfig registryConfig) {
+        String protocol = registryConfig.getProtocol();
+        URL url = URL.valueOf(registryConfig.getAddress(), registryConfig.getScopeModel());
+        String id = "metadata-center-" + protocol + "-" + url.getHost() + "-" + url.getPort();
+        MetadataReportConfig metadataReportConfig = new MetadataReportConfig();
+        metadataReportConfig.setId(id);
+        metadataReportConfig.setScopeModel(applicationModel);
+        if (metadataReportConfig.getParameters() == null) {
+            metadataReportConfig.setParameters(new HashMap<>());
+        }
+        if (registryConfig.getParameters() != null) {
+            metadataReportConfig.getParameters().putAll(registryConfig.getParameters()); // copy the parameters
+        }
+        metadataReportConfig.getParameters().put(CLIENT_KEY, registryConfig.getClient());
+        metadataReportConfig.setGroup(registryConfig.getGroup());
+        metadataReportConfig.setAddress(getRegistryCompatibleAddress(registryConfig));
+        metadataReportConfig.setUsername(registryConfig.getUsername());
+        metadataReportConfig.setPassword(registryConfig.getPassword());
+        metadataReportConfig.setTimeout(registryConfig.getTimeout());
+        return metadataReportConfig;
+    }
+
+    private String getRegistryCompatibleAddress(RegistryConfig registryConfig) {
+        String registryAddress = registryConfig.getAddress();
+        String[] addresses = REGISTRY_SPLIT_PATTERN.split(registryAddress);
+        if (ArrayUtils.isEmpty(addresses)) {
+            throw new IllegalStateException("Invalid registry address found.");
+        }
+        String address = addresses[0];
+        // since 2.7.8
+        // Issue : https://github.com/apache/dubbo/issues/6476
+        StringBuilder metadataAddressBuilder = new StringBuilder();
+        URL url = URL.valueOf(address, registryConfig.getScopeModel());
+        String protocolFromAddress = url.getProtocol();
+        if (isEmpty(protocolFromAddress)) {
+            // If the protocol from address is missing, is like :
+            // "dubbo.registry.address = 127.0.0.1:2181"
+            String protocolFromConfig = registryConfig.getProtocol();
+            metadataAddressBuilder.append(protocolFromConfig).append("://");
+        }
+        metadataAddressBuilder.append(address);
+        return metadataAddressBuilder.toString();
+    }
+
+    /**
+     * Initialize {@link MetadataService} from {@link WritableMetadataService}'s extension
+     */
+    private void initMetadataService() {
+//        startMetadataCenter();
+        this.metadataService = getExtensionLoader(WritableMetadataService.class).getDefaultExtension();
+        // support injection by super type MetadataService
+        applicationModel.getBeanFactory().registerBean(this.metadataService);
+
+        //this.metadataServiceExporter = new ConfigurableMetadataServiceExporter(metadataService);
+        this.metadataServiceExporter = getExtensionLoader(MetadataServiceExporter.class).getDefaultExtension();
+    }
+
+    /**
+     * Start the bootstrap
+     */
+    @Override
+    public synchronized void start() {
+        // avoid re-entry start method multiple times in same thread
+        if (isCurrentlyInStart) {
+            return;
+        }
+
+        isCurrentlyInStart = true;
+        try {
+            if (started.compareAndSet(false, true)) {
+                startup.set(false);
+                shutdown.set(false);
+
+                initialize();
+
+                if (logger.isInfoEnabled()) {
+                    logger.info(getIdentifier() + " is starting...");
+                }
+
+                doStart();
+
+                if (logger.isInfoEnabled()) {
+                    logger.info(getIdentifier() + " has started.");
+                }
+            } else {
+                if (logger.isInfoEnabled()) {
+                    logger.info(getIdentifier() + " is started, export/refer new services.");
+                }
+
+                doStart();
+
+                if (logger.isInfoEnabled()) {
+                    logger.info(getIdentifier() + " finish export/refer new services.");
+                }
+            }
+        } finally {
+            isCurrentlyInStart = false;
+        }
+    }
+
+    private void doStart() {
+        // copy current modules, ignore new module during starting
+        List<ModuleModel> moduleModels = new ArrayList<>(applicationModel.getModuleModels());
+        List<ModuleDeployer> moduleDeployers = new ArrayList<>(moduleModels.size());
+        List<CompletableFuture> futures = new ArrayList<>(moduleModels.size());
+
+        for (ModuleModel moduleModel : moduleModels) {
+            // export services in module
+            ModuleDeployer moduleDeployer = moduleModel.getDeployer();
+            moduleDeployers.add(moduleDeployer);
+            CompletableFuture moduleFuture = moduleDeployer.start();
+            futures.add(moduleFuture);
+        }
+
+        // prepare application instance
+        prepareApplicationInstance();
+
+        // wait async export / refer finish if needed
+        if (isExportBackground(moduleDeployers) || isReferBackground(moduleDeployers)) {
+            new Thread(() -> {
+                awaitDeployFinished(futures);
+                onStarted();
+            }).start();
+        } else {
+            awaitDeployFinished(futures);
+            onStarted();
+        }
+    }
+
+    private void awaitDeployFinished(List<CompletableFuture> futures) {
+        try {
+            CompletableFuture mergedFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
+            mergedFuture.get();
+        } catch (Exception e) {
+            logger.error(getIdentifier() + " await deploy finished failed", e);
+        }
+    }
+
+    @Override
+    public void prepareApplicationInstance() {
+        if (hasPreparedApplicationInstance.get()) {
+            return;
+        }
+        // if register consumer instance or has exported services
+        if (isRegisterConsumerInstance() || hasExportedServices()) {
+            if (!hasPreparedApplicationInstance.compareAndSet(false, true)) {
+                return;
+            }
+            // export MetadataService
+            exportMetadataService();
+            // start internal module
+            ModuleDeployer internalModuleDeployer = applicationModel.getInternalModule().getDeployer();
+            CompletableFuture internalModuleFuture = internalModuleDeployer.start();
+            try {
+                internalModuleFuture.get();
+            } catch (Exception e) {
+                logger.warn("Internal module start waiting was interrupted");
+            }
+            // register the local ServiceInstance if required
+            registerServiceInstance();
+        }
+    }
+
+    private boolean hasExportedServices() {
+        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
+            if (CollectionUtils.isNotEmpty(moduleModel.getServiceRepository().getExportedServices())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isExportBackground(List<ModuleDeployer> moduleDeployers) {
+        // move export background option to application?
+        for (ModuleDeployer moduleDeployer : moduleDeployers) {
+            if (moduleDeployer.isExportBackground()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isReferBackground(List<ModuleDeployer> moduleDeployers) {
+        // move refer background option to application?
+        for (ModuleDeployer moduleDeployer : moduleDeployers) {
+            if (moduleDeployer.isReferBackground()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isInitialized() {
+        return initialized.get();
+    }
+
+    @Override
+    public boolean isStarted() {
+        return started.get();
+    }
+
+    @Override
+    public boolean isStartup() {
+        return startup.get();
+    }
+
+    @Override
+    public boolean isShutdown() {
+        return shutdown.get();
+    }
+
+
+    private DynamicConfiguration prepareEnvironment(ConfigCenterConfig configCenter) {
+        if (configCenter.isValid()) {
+            if (!configCenter.checkOrUpdateInitialized(true)) {
+                return null;
+            }
+
+            DynamicConfiguration dynamicConfiguration = null;
+            try {
+                dynamicConfiguration = getDynamicConfiguration(configCenter.toUrl());
+            } catch (Exception e) {
+                if (!configCenter.isCheck()) {
+                    logger.warn("The configuration center failed to initialize", e);
+                    configCenter.checkOrUpdateInitialized(false);
+                    return null;
+                } else {
+                    throw new IllegalStateException(e);
+                }
+            }
+
+            String configContent = dynamicConfiguration.getProperties(configCenter.getConfigFile(), configCenter.getGroup());
+
+            String appGroup = getApplication().getName();
+            String appConfigContent = null;
+            if (isNotEmpty(appGroup)) {
+                appConfigContent = dynamicConfiguration.getProperties
+                    (isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(),
+                        appGroup
+                    );
+            }
+            try {
+                environment.updateExternalConfigMap(parseProperties(configContent));
+                environment.updateAppExternalConfigMap(parseProperties(appConfigContent));
+            } catch (IOException e) {
+                throw new IllegalStateException("Failed to parse configurations from Config Center.", e);
+            }
+            return dynamicConfiguration;
+        }
+        return null;
+    }
+
+    /**
+     * Get the instance of {@link DynamicConfiguration} by the specified connection {@link URL} of config-center
+     *
+     * @param connectionURL of config-center
+     * @return non-null
+     * @since 2.7.5
+     */
+    private DynamicConfiguration getDynamicConfiguration(URL connectionURL) {
+        String protocol = connectionURL.getProtocol();
+
+        DynamicConfigurationFactory factory = ConfigurationUtils.getDynamicConfigurationFactory(applicationModel, protocol);
+        return factory.getDynamicConfiguration(connectionURL);
+    }
+
+    /**
+     * export {@link MetadataService}
+     */
+    private void exportMetadataService() {
+        metadataServiceExporter.export();
+    }
+
+    private void unexportMetadataService() {
+        if (metadataServiceExporter != null && metadataServiceExporter.isExported()) {
+            try {
+                metadataServiceExporter.unexport();
+            } catch (Exception ignored) {
+                // ignored
+            }
+        }
+    }
+
+    private void registerServiceInstance() {
+        if (isRegisteredServiceInstance()) {
+            return;
+        }
+
+        ApplicationConfig application = getApplication();
+        String serviceName = application.getName();
+        ServiceInstance serviceInstance = createServiceInstance(serviceName);
+        boolean registered = true;
+        try {
+            ServiceInstanceMetadataUtils.registerMetadataAndInstance(serviceInstance);
+        } catch (Exception e) {
+            registered = false;
+            logger.error("Register instance error", e);
+        }
+        if (registered) {
+            // scheduled task for updating Metadata and ServiceInstance
+            asyncMetadataFuture = executorRepository.nextScheduledExecutor().scheduleAtFixedRate(() -> {
+                InMemoryWritableMetadataService localMetadataService = (InMemoryWritableMetadataService) WritableMetadataService.getDefaultExtension(applicationModel);
+                localMetadataService.blockUntilUpdated();
+                try {
+                    ServiceInstanceMetadataUtils.refreshMetadataAndInstance(serviceInstance);
+                } catch (Exception e) {
+                    logger.error("Refresh instance and metadata error", e);
+                } finally {
+                    localMetadataService.releaseBlock();
+                }
+            }, 0, ConfigurationUtils.get(applicationModel, METADATA_PUBLISH_DELAY_KEY, DEFAULT_METADATA_PUBLISH_DELAY), TimeUnit.MILLISECONDS);
+        }
+    }
+
+    private boolean isRegisteredServiceInstance() {
+        return this.serviceInstance != null;
+    }
+
+    private void doRegisterServiceInstance(ServiceInstance serviceInstance) {
+        // register instance only when at least one service is exported.
+        if (serviceInstance.getPort() > 0) {
+            publishMetadataToRemote(serviceInstance);
+            logger.info("Start registering instance address to registry.");
+            getServiceDiscoveries().forEach(serviceDiscovery ->
+            {
+                ServiceInstance serviceInstanceForRegistry = new DefaultServiceInstance((DefaultServiceInstance) serviceInstance);
+                calInstanceRevision(serviceDiscovery, serviceInstanceForRegistry);
+                if (logger.isDebugEnabled()) {
+                    logger.info("Start registering instance address to registry" + serviceDiscovery.getUrl() + ", instance " + serviceInstanceForRegistry);
+                }
+                // register metadata
+                serviceDiscovery.register(serviceInstanceForRegistry);
+            });
+        }
+    }
+
+    private void publishMetadataToRemote(ServiceInstance serviceInstance) {
+//        InMemoryWritableMetadataService localMetadataService = (InMemoryWritableMetadataService)WritableMetadataService.getDefaultExtension();
+//        localMetadataService.blockUntilUpdated();
+        if (logger.isInfoEnabled()) {
+            logger.info("Start publishing metadata to remote center, this only makes sense for applications enabled remote metadata center.");
+        }
+        RemoteMetadataServiceImpl remoteMetadataService = applicationModel.getBeanFactory().getBean(RemoteMetadataServiceImpl.class);
+        remoteMetadataService.publishMetadata(serviceInstance.getServiceName());
+    }
+
+    private void unregisterServiceInstance() {
+        if (isRegisteredServiceInstance()) {
+            getServiceDiscoveries().forEach(serviceDiscovery -> {
+                try {
+                    serviceDiscovery.unregister(serviceInstance);
+                } catch (Exception ignored) {
+                    // ignored
+                }
+            });
+        }
+    }
+
+    private ServiceInstance createServiceInstance(String serviceName) {
+        this.serviceInstance = new DefaultServiceInstance(serviceName, applicationModel);
+        setMetadataStorageType(serviceInstance, getMetadataType());
+        ServiceInstanceMetadataUtils.customizeInstance(this.serviceInstance);
+        return this.serviceInstance;
+    }
+
+    @Override
+    public void destroy() {
+        if (destroyLock.tryLock()
+            && shutdown.compareAndSet(false, true)) {
+            try {
+                if (destroyed.compareAndSet(false, true)) {
+                    if (started.compareAndSet(true, false)) {
+                        unregisterServiceInstance();
+                        unexportMetadataService();
+                        if (asyncMetadataFuture != null) {
+                            asyncMetadataFuture.cancel(true);
+                        }
+                    }
+
+                    destroyRegistries();
+                    destroyServiceDiscoveries();
+                    destroyMetadataReports();
+
+                    applicationModel.destroy();
+                    destroyProtocols(applicationModel.getFrameworkModel());
+                    destroyExecutorRepository();
+
+                    onStop();
+                }
+
+                destroyDynamicConfigurations();
+            } catch (Throwable ignored) {
+                // ignored
+                logger.warn(ignored.getMessage(), ignored);
+            } finally {
+                initialized.set(false);
+                startup.set(false);
+                destroyLock.unlock();
+                unRegisterShutdownHook();
+            }
+
+            applicationModel.destroy();
+        }
+    }
+
+    private void onStarted() {
+        startup.set(true);
+        if (logger.isInfoEnabled()) {
+            logger.info(getIdentifier() + " is ready.");
+        }
+        DubboBootstrap dubboBootstrap = applicationModel.getBeanFactory().getBean(DubboBootstrap.class);
+        ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
+        exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(dubboBootstrap));
+    }
+
+    private void onStop() {
+        DubboBootstrap dubboBootstrap = applicationModel.getBeanFactory().getBean(DubboBootstrap.class);
+        ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
+        exts.getSupportedExtensionInstances().forEach(ext -> ext.onStop(dubboBootstrap));
+    }
+
+    private void destroyExecutorRepository() {
+        getExtensionLoader(ExecutorRepository.class).getDefaultExtension().destroyAll();
+    }
+
+    private void destroyRegistries() {
+        AbstractRegistryFactory.destroyAll();
+    }
+
+    /**
+     * Destroy all the protocols.
+     */
+    private static void destroyProtocols(FrameworkModel frameworkModel) {
+        if (frameworkModel.getApplicationModels().isEmpty()) {
+            //TODO destroy protocol in framework scope
+            ExtensionLoader<Protocol> loader = frameworkModel.getExtensionLoader(Protocol.class);
+            for (String protocolName : loader.getLoadedExtensions()) {
+                try {
+                    Protocol protocol = loader.getLoadedExtension(protocolName);
+                    if (protocol != null) {
+                        protocol.destroy();
+                    }
+                } catch (Throwable t) {
+                    logger.warn(t.getMessage(), t);
+                }
+            }
+        }
+    }
+
+    private static void destroyAllProtocols() {
+        for (FrameworkModel frameworkModel : FrameworkModel.getAllInstances()) {
+            destroyProtocols(frameworkModel);
+        }
+    }
+
+    private void destroyServiceDiscoveries() {
+        getServiceDiscoveries().forEach(serviceDiscovery -> {
+            try {
+                execute(serviceDiscovery::destroy);
+            } catch (Throwable ignored) {
+                logger.warn(ignored.getMessage(), ignored);
+            }
+        });
+        if (logger.isDebugEnabled()) {
+            logger.debug(getIdentifier() + "'s all ServiceDiscoveries have been destroyed.");
+        }
+    }
+
+    private void destroyMetadataReports() {
+        AbstractMetadataReportFactory.destroy();
+        MetadataReportInstance.reset();
+    }
+
+    private void destroyDynamicConfigurations() {
+        // DynamicConfiguration may be cached somewhere, and maybe used during destroy
+        // destroy them may cause some troubles, so just clear instances cache
+        // ExtensionLoader.resetExtensionLoader(DynamicConfigurationFactory.class);
+    }
+
+    private ApplicationConfig getApplication() {
+        return configManager.getApplicationOrElseThrow();
+    }
+
+    private String getIdentifier() {
+        if (identifier == null) {
+            identifier = "Dubbo Application-" + applicationModel.getInternalId();
+        }
+        return identifier;
+    }
+
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DefaultModuleDeployer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DefaultModuleDeployer.java
new file mode 100644
index 0000000..1131741
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DefaultModuleDeployer.java
@@ -0,0 +1,345 @@
+/*
+ * 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.bootstrap;
+
+import org.apache.dubbo.common.config.ReferenceCache;
+import org.apache.dubbo.common.deploy.ApplicationDeployer;
+import org.apache.dubbo.common.deploy.ModuleDeployer;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
+import org.apache.dubbo.config.ConsumerConfig;
+import org.apache.dubbo.config.ProviderConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.ServiceConfigBase;
+import org.apache.dubbo.config.context.ModuleConfigManager;
+import org.apache.dubbo.config.utils.SimpleReferenceCache;
+import org.apache.dubbo.rpc.model.ModelConstants;
+import org.apache.dubbo.rpc.model.ModuleModel;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Export/refer services of module
+ */
+public class DefaultModuleDeployer implements ModuleDeployer {
+
+    private static final Logger logger = LoggerFactory.getLogger(DefaultModuleDeployer.class);
+
+    private final List<CompletableFuture<?>> asyncExportingFutures = new ArrayList<>();
+
+    private final List<CompletableFuture<?>> asyncReferringFutures = new ArrayList<>();
+
+    private List<ServiceConfigBase<?>> exportedServices = new ArrayList<>();
+
+    private ModuleModel moduleModel;
+
+    private ExecutorRepository executorRepository;
+
+    private final ModuleConfigManager configManager;
+
+    private final SimpleReferenceCache referenceCache;
+    private String identifier;
+
+    private volatile boolean startup;
+
+    protected AtomicBoolean initialized = new AtomicBoolean(false);
+
+    private ApplicationDeployer applicationDeployer;
+
+    public static ModuleDeployer get(ModuleModel moduleModel) {
+        return moduleModel.getAttribute(ModelConstants.DEPLOYER, DefaultModuleDeployer.class);
+    }
+
+    public DefaultModuleDeployer(ModuleModel moduleModel) {
+        this.moduleModel = moduleModel;
+        configManager = moduleModel.getConfigManager();
+        executorRepository = moduleModel.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
+        referenceCache = SimpleReferenceCache.newCache();
+        applicationDeployer = DefaultApplicationDeployer.get(moduleModel);
+    }
+
+    @Override
+    public void initialize() throws IllegalStateException {
+        if (!initialized.compareAndSet(false, true)) {
+            return;
+        }
+        loadConfigs();
+    }
+
+    @Override
+    public CompletableFuture start() throws IllegalStateException {
+
+        CompletableFuture startFuture = new CompletableFuture();
+
+        applicationDeployer.initialize();
+
+        // initialize
+        initialize();
+
+        // export services
+        exportServices();
+
+        // prepare application instance
+        if (hasExportedServices()) {
+            applicationDeployer.prepareApplicationInstance();
+        }
+
+        // refer services
+        referServices();
+
+        executorRepository.getSharedExecutor().submit(() -> {
+            awaitFinish();
+            onModuleStarted(startFuture);
+        });
+        return startFuture;
+    }
+
+    private boolean hasExportedServices() {
+        return configManager.getServices().size() > 0;
+    }
+
+    @Override
+    public void destroy() throws IllegalStateException {
+        unexportServices();
+        unreferServices();
+        onModuleStopped();
+    }
+
+    private void onModuleStopped() {
+        startup = false;
+        logger.info(getIdentifier() + " has stopped.");
+        Set<ModuleDeployListener> listeners = moduleModel.getExtensionLoader(ModuleDeployListener.class).getSupportedExtensionInstances();
+        for (ModuleDeployListener listener : listeners) {
+            listener.onModuleStopped(moduleModel);
+        }
+    }
+
+    private void onModuleStarted(CompletableFuture startFuture) {
+        startup = true;
+        logger.info(getIdentifier() + " has started.");
+        startFuture.complete(true);
+        Set<ModuleDeployListener> listeners = moduleModel.getExtensionLoader(ModuleDeployListener.class).getSupportedExtensionInstances();
+        for (ModuleDeployListener listener : listeners) {
+            listener.onModuleStarted(moduleModel);
+        }
+    }
+
+    private void loadConfigs() {
+        // load module configs
+        moduleModel.getConfigManager().loadConfigs();
+        moduleModel.getConfigManager().refreshAll();
+    }
+
+    private void exportServices() {
+        for (ServiceConfigBase sc : configManager.getServices()) {
+            exportServiceInternal(sc);
+        }
+    }
+
+    private void exportServiceInternal(ServiceConfigBase sc) {
+        ServiceConfig<?> serviceConfig = (ServiceConfig<?>) sc;
+        if (!serviceConfig.isRefreshed()) {
+            serviceConfig.refresh();
+        }
+        if (sc.isExported()) {
+            return;
+        }
+        if (sc.shouldExportAsync()) {
+            ExecutorService executor = executorRepository.getServiceExportExecutor();
+            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+                try {
+                    if (!sc.isExported()) {
+                        sc.exportOnly();
+                        exportedServices.add(sc);
+                    }
+                } catch (Throwable t) {
+                    logger.error(getIdentifier() + " export async catch error : " + t.getMessage(), t);
+                }
+            }, executor);
+
+            asyncExportingFutures.add(future);
+        } else {
+            if (!sc.isExported()) {
+                sc.exportOnly();
+                exportedServices.add(sc);
+            }
+        }
+    }
+
+    private void unexportServices() {
+        exportedServices.forEach(sc -> {
+            try {
+                configManager.removeConfig(sc);
+                sc.unexport();
+            } catch (Exception ignored) {
+                // ignored
+            }
+        });
+
+        asyncExportingFutures.forEach(future -> {
+            if (!future.isDone()) {
+                future.cancel(true);
+            }
+        });
+        asyncExportingFutures.clear();
+    }
+
+    private void referServices() {
+        configManager.getReferences().forEach(rc -> {
+            try {
+                // TODO, compatible with  ReferenceConfig.refer()
+                ReferenceConfig<?> referenceConfig = (ReferenceConfig<?>) rc;
+                if (!referenceConfig.isRefreshed()) {
+                    referenceConfig.refresh();
+                }
+
+                if (rc.shouldInit()) {
+                    if (rc.shouldReferAsync()) {
+                        ExecutorService executor = executorRepository.getServiceReferExecutor();
+                        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+                            try {
+                                referenceCache.get(rc);
+                            } catch (Throwable t) {
+                                logger.error(getIdentifier() + " refer async catch error : " + t.getMessage(), t);
+                            }
+                        }, executor);
+
+                        asyncReferringFutures.add(future);
+                    } else {
+                        referenceCache.get(rc);
+                    }
+                }
+            } catch (Throwable t) {
+                logger.error(getIdentifier() + " refer catch error", t);
+                referenceCache.destroy(rc);
+            }
+        });
+    }
+
+    private void unreferServices() {
+        try {
+            asyncReferringFutures.forEach(future -> {
+                if (!future.isDone()) {
+                    future.cancel(true);
+                }
+            });
+            asyncReferringFutures.clear();
+            referenceCache.destroyAll();
+        } catch (Exception ignored) {
+        }
+    }
+
+    private void waitExportFinish() {
+        try {
+            logger.info(getIdentifier() + " waiting services exporting ...");
+            CompletableFuture<?> future = CompletableFuture.allOf(asyncExportingFutures.toArray(new CompletableFuture[0]));
+            future.get();
+        } catch (Exception e) {
+            logger.warn(getIdentifier() + " export services occurred an exception.");
+        } finally {
+            executorRepository.shutdownServiceExportExecutor();
+            logger.info(getIdentifier() + " export services finished.");
+            asyncExportingFutures.clear();
+        }
+    }
+
+    private void waitReferFinish() {
+        try {
+            logger.info(getIdentifier() + " waiting services referring ...");
+            CompletableFuture<?> future = CompletableFuture.allOf(asyncReferringFutures.toArray(new CompletableFuture[0]));
+            future.get();
+        } catch (Exception e) {
+            logger.warn(getIdentifier() + " refer services occurred an exception.");
+        } finally {
+            executorRepository.shutdownServiceReferExecutor();
+            logger.info(getIdentifier() + " refer services finished.");
+            asyncReferringFutures.clear();
+        }
+    }
+
+    private void awaitFinish() {
+        waitExportFinish();
+        waitReferFinish();
+    }
+
+    @Override
+    public boolean isStartup() {
+        return startup;
+    }
+
+    @Override
+    public boolean isInitialized() {
+        return initialized.get();
+    }
+
+    @Override
+    public boolean isExportBackground() {
+        return moduleModel.getConfigManager().getProviders()
+            .stream()
+            .map(ProviderConfig::getExportBackground)
+            .filter(k -> k != null && k)
+            .findAny()
+            .isPresent();
+    }
+
+    @Override
+    public boolean isReferBackground() {
+        return moduleModel.getConfigManager().getConsumers()
+            .stream()
+            .map(ConsumerConfig::getReferBackground)
+            .filter(k -> k != null && k)
+            .findAny()
+            .isPresent();
+    }
+
+    private String getIdentifier() {
+        if (identifier == null) {
+            identifier = "Dubbo Module-" + moduleModel.getInternalId();
+        }
+        return identifier;
+    }
+
+    @Override
+    public ReferenceCache getReferenceCache() {
+        return referenceCache;
+    }
+
+    /**
+     * Prepare for export/refer service, trigger initializing application and module
+     */
+    @Override
+    public void prepare() {
+        applicationDeployer.initialize();
+        this.initialize();
+    }
+
+    /**
+     * After export one service, trigger starting application
+     */
+    @Override
+    public void notifyExportService(ServiceConfigBase<?> sc) {
+        applicationDeployer.prepareApplicationInstance();
+    }
+
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
index 97e8abb..7e69f0e 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/DubboBootstrap.java
@@ -16,27 +16,17 @@
  */
 package org.apache.dubbo.config.bootstrap;
 
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.config.ConfigurationUtils;
 import org.apache.dubbo.common.config.Environment;
-import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
-import org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory;
-import org.apache.dubbo.common.config.configcenter.wrapper.CompositeDynamicConfiguration;
-import org.apache.dubbo.common.constants.CommonConstants;
-import org.apache.dubbo.common.extension.ExtensionDirector;
+import org.apache.dubbo.common.config.ReferenceCache;
+import org.apache.dubbo.common.deploy.ApplicationDeployer;
 import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.common.lang.ShutdownHookCallbacks;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
-import org.apache.dubbo.common.utils.ArrayUtils;
 import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.config.AbstractConfig;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.ConfigCenterConfig;
 import org.apache.dubbo.config.ConsumerConfig;
-import org.apache.dubbo.config.DubboShutdownHook;
 import org.apache.dubbo.config.MetadataReportConfig;
 import org.apache.dubbo.config.MetricsConfig;
 import org.apache.dubbo.config.ModuleConfig;
@@ -44,10 +34,8 @@ import org.apache.dubbo.config.MonitorConfig;
 import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.ProviderConfig;
 import org.apache.dubbo.config.ReferenceConfig;
-import org.apache.dubbo.config.ReferenceConfigBase;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.ServiceConfig;
-import org.apache.dubbo.config.ServiceConfigBase;
 import org.apache.dubbo.config.SslConfig;
 import org.apache.dubbo.config.bootstrap.builders.ApplicationBuilder;
 import org.apache.dubbo.config.bootstrap.builders.ConsumerBuilder;
@@ -57,64 +45,22 @@ import org.apache.dubbo.config.bootstrap.builders.ReferenceBuilder;
 import org.apache.dubbo.config.bootstrap.builders.RegistryBuilder;
 import org.apache.dubbo.config.bootstrap.builders.ServiceBuilder;
 import org.apache.dubbo.config.context.ConfigManager;
-import org.apache.dubbo.config.utils.ConfigValidationUtils;
-import org.apache.dubbo.config.utils.ReferenceConfigCache;
-import org.apache.dubbo.metadata.MetadataService;
-import org.apache.dubbo.metadata.MetadataServiceExporter;
-import org.apache.dubbo.metadata.WritableMetadataService;
-import org.apache.dubbo.metadata.report.MetadataReportFactory;
+import org.apache.dubbo.config.utils.CompositeReferenceCache;
 import org.apache.dubbo.metadata.report.MetadataReportInstance;
-import org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory;
-import org.apache.dubbo.registry.client.DefaultServiceInstance;
-import org.apache.dubbo.registry.client.ServiceInstance;
-import org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils;
-import org.apache.dubbo.registry.client.metadata.store.InMemoryWritableMetadataService;
-import org.apache.dubbo.registry.client.metadata.store.RemoteMetadataServiceImpl;
 import org.apache.dubbo.registry.support.AbstractRegistryFactory;
 import org.apache.dubbo.rpc.Protocol;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 import org.apache.dubbo.rpc.model.ModuleModel;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
 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.function.Supplier;
-import java.util.stream.Collectors;
 
-import static java.lang.String.format;
 import static java.util.Collections.singletonList;
-import static java.util.concurrent.Executors.newSingleThreadExecutor;
-import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties;
-import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
-import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SPLIT_PATTERN;
-import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE;
-import static org.apache.dubbo.common.function.ThrowableAction.execute;
-import static org.apache.dubbo.common.utils.StringUtils.isEmpty;
-import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
-import static org.apache.dubbo.metadata.MetadataConstants.DEFAULT_METADATA_PUBLISH_DELAY;
-import static org.apache.dubbo.metadata.MetadataConstants.METADATA_PUBLISH_DELAY_KEY;
-import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.calInstanceRevision;
-import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.setMetadataStorageType;
-import static org.apache.dubbo.registry.support.AbstractRegistryFactory.getServiceDiscoveries;
-import static org.apache.dubbo.remoting.Constants.CLIENT_KEY;
 
 /**
  * See {@link ApplicationModel} and {@link ExtensionLoader} for why this class is designed to be singleton.
@@ -142,53 +88,17 @@ public final class DubboBootstrap {
 
     private final Condition condition = lock.newCondition();
 
-    private final Lock destroyLock = new ReentrantLock();
-
-    private final ExecutorService executorService = newSingleThreadExecutor();
-
     private ExecutorRepository executorRepository;
 
     private final ApplicationModel applicationModel;
 
-    protected ScheduledFuture<?> asyncMetadataFuture;
-
     protected final ConfigManager configManager;
 
     protected final Environment environment;
 
-    protected ReferenceConfigCache cache;
-
-    protected AtomicBoolean initialized = new AtomicBoolean(false);
-
-    protected AtomicBoolean started = new AtomicBoolean(false);
-
-    protected AtomicBoolean startup = new AtomicBoolean(true);
-
-    protected AtomicBoolean destroyed = new AtomicBoolean(false);
-
-    protected AtomicBoolean shutdown = new AtomicBoolean(false);
-
-    protected volatile boolean isCurrentlyInStart = false;
-
-    protected volatile ServiceInstance serviceInstance;
-
-    protected volatile MetadataService metadataService;
-
-    protected volatile MetadataServiceExporter metadataServiceExporter;
-
-    protected List<ServiceConfigBase<?>> exportedServices = new ArrayList<>();
-
-    protected final List<CompletableFuture<?>> asyncExportingFutures = new ArrayList<>();
-
-    protected final List<CompletableFuture<?>> asyncReferringFutures = new ArrayList<>();
-
-    protected boolean asyncExportFinish = true;
+    protected ReferenceCache referenceCache;
 
-    protected volatile boolean asyncReferFinish = true;
-
-    protected static boolean ignoreConfigState;
-
-    private Module currentModule;
+    private ApplicationDeployer applicationDeployer;
 
     /**
      * See {@link ApplicationModel} and {@link ExtensionLoader} for why DubboBootstrap is designed to be singleton.
@@ -204,31 +114,18 @@ public final class DubboBootstrap {
         return instance;
     }
 
-    public static DubboBootstrap getInstance(ApplicationModel applicationModel) {
-        Map<String, Object> attribute = applicationModel.getAttribute();
-        Object cached = attribute.get(NAME);
-        if (cached instanceof DubboBootstrap) {
-            return (DubboBootstrap) cached;
-        } else {
-            synchronized (applicationModel) {
-                cached = attribute.get(NAME);
-                if (cached instanceof DubboBootstrap) {
-                    return (DubboBootstrap) cached;
-                } else {
-                    return new DubboBootstrap(applicationModel);
-                }
-            }
-        }
-    }
-
     public static DubboBootstrap newInstance() {
-        return new DubboBootstrap(new FrameworkModel());
+        return new DubboBootstrap(FrameworkModel.defaultModel());
     }
 
     public static DubboBootstrap newInstance(FrameworkModel frameworkModel) {
         return new DubboBootstrap(frameworkModel);
     }
 
+    public static DubboBootstrap newInstance(ApplicationModel applicationModel) {
+        return new DubboBootstrap(applicationModel);
+    }
+
     /**
      * Try reset dubbo status for new instance.
      *
@@ -246,7 +143,6 @@ public final class DubboBootstrap {
      */
     @Deprecated
     public static void reset(boolean destroy) {
-        DubboBootstrap.ignoreConfigState = true;
         if (destroy) {
             if (instance != null) {
                 instance.destroy();
@@ -261,7 +157,6 @@ public final class DubboBootstrap {
         }
 
         ApplicationModel.reset();
-        ShutdownHookCallbacks.INSTANCE.clear();
     }
 
     private DubboBootstrap(FrameworkModel frameworkModel) {
@@ -270,49 +165,143 @@ public final class DubboBootstrap {
 
     private DubboBootstrap(ApplicationModel applicationModel) {
         this.applicationModel = applicationModel;
-        applicationModel.getAttribute().put(NAME, this);
         configManager = applicationModel.getApplicationConfigManager();
         environment = applicationModel.getApplicationEnvironment();
 
-        executorRepository = getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
-        DubboShutdownHook.getDubboShutdownHook().register();
-        ShutdownHookCallbacks.INSTANCE.addCallback(DubboBootstrap.this::destroy);
-        cache = ReferenceConfigCache.newCache();
+        referenceCache = new CompositeReferenceCache(applicationModel);
+        executorRepository = applicationModel.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
+        applicationDeployer = applicationModel.getDeployer();
+        // register DubboBootstrap bean
+        applicationModel.getBeanFactory().registerBean(this);
     }
 
-    public ApplicationModel getApplicationModel() {
-        return applicationModel;
+    /**
+     * Initialize
+     */
+    public void initialize() {
+        applicationDeployer.initialize();
     }
 
-    public ConfigManager getConfigManager() {
-        return configManager;
+    /**
+     * Start the bootstrap
+     */
+    public DubboBootstrap start() {
+        applicationDeployer.start();
+        return this;
+    }
+
+    public DubboBootstrap stop() throws IllegalStateException {
+        destroy();
+        return this;
+    }
+
+    public void destroy() {
+        applicationDeployer.destroy();
+    }
+
+    public boolean isInitialized() {
+        return applicationDeployer.isInitialized();
     }
 
-    public ExtensionDirector getExtensionDirector() {
-        return applicationModel.getExtensionDirector();
+    public boolean isStarted() {
+        return applicationDeployer.isStarted();
+    }
+
+    public boolean isStartup() {
+        return applicationDeployer.isStartup();
+    }
+
+    public boolean isShutdown() {
+        return applicationDeployer.isShutdown();
+    }
+
+    /**
+     * Block current thread to be await.
+     *
+     * @return {@link DubboBootstrap}
+     */
+    public DubboBootstrap await() {
+        // if has been waited, no need to wait again, return immediately
+        if (!awaited.get()) {
+            if (!isShutdown()) {
+                executeMutually(() -> {
+                    while (!awaited.get()) {
+                        if (logger.isInfoEnabled()) {
+                            logger.info(NAME + " awaiting ...");
+                        }
+                        try {
+                            condition.await();
+                        } catch (InterruptedException e) {
+                            Thread.currentThread().interrupt();
+                        }
+                    }
+                });
+            }
+        }
+        return this;
     }
 
-    public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
-        return applicationModel.getExtensionLoader(type);
+    public ReferenceCache getCache() {
+        return referenceCache;
     }
 
-    public void unRegisterShutdownHook() {
-        DubboShutdownHook.getDubboShutdownHook().unregister();
+    /**
+     * Destroy all the protocols.
+     */
+    private static void destroyProtocols(FrameworkModel frameworkModel) {
+        //TODO destroy protocol in framework scope
+        ExtensionLoader<Protocol> loader = frameworkModel.getExtensionLoader(Protocol.class);
+        for (String protocolName : loader.getLoadedExtensions()) {
+            try {
+                Protocol protocol = loader.getLoadedExtension(protocolName);
+                if (protocol != null) {
+                    protocol.destroy();
+                }
+            } catch (Throwable t) {
+                logger.warn(t.getMessage(), t);
+            }
+        }
     }
 
-    private boolean isRegisterConsumerInstance() {
-        Boolean registerConsumer = getApplication().getRegisterConsumer();
-        return Boolean.TRUE.equals(registerConsumer);
+    private static void destroyAllProtocols() {
+        for (FrameworkModel frameworkModel : FrameworkModel.getAllInstances()) {
+            destroyProtocols(frameworkModel);
+        }
     }
 
-    private String getMetadataType() {
-        String type = getApplication().getMetadataType();
-        if (StringUtils.isEmpty(type)) {
-            type = DEFAULT_METADATA_STORAGE_TYPE;
+    private void executeMutually(Runnable runnable) {
+        try {
+            lock.lock();
+            runnable.run();
+        } finally {
+            lock.unlock();
         }
-        return type;
     }
 
+    public ApplicationConfig getApplication() {
+        return configManager.getApplicationOrElseThrow();
+    }
+
+    public void setTakeoverMode(BootstrapTakeoverMode takeoverMode) {
+        //TODO this.started.set(false);
+        this.takeoverMode = takeoverMode;
+    }
+
+    public BootstrapTakeoverMode getTakeoverMode() {
+        return takeoverMode;
+    }
+
+    public ApplicationModel getApplicationModel() {
+        return applicationModel;
+    }
+
+    public ConfigManager getConfigManager() {
+        return configManager;
+    }
+
+
+    // MetadataReportConfig correlative methods
+
     public DubboBootstrap metadataReport(MetadataReportConfig metadataReportConfig) {
         configManager.addMetadataReport(metadataReportConfig);
         return this;
@@ -445,93 +434,144 @@ public final class DubboBootstrap {
         return this;
     }
 
-    private Module getCurrentModule() {
-        if (currentModule == null) {
-            currentModule = new Module(applicationModel.getDefaultModule());
-        }
-        return currentModule;
-    }
-
     // {@link ServiceConfig} correlative methods
     public <S> DubboBootstrap service(Consumer<ServiceBuilder<S>> consumerBuilder) {
-        getCurrentModule().service(consumerBuilder);
-        return this;
+        return service(null, consumerBuilder);
     }
 
     public <S> DubboBootstrap service(String id, Consumer<ServiceBuilder<S>> consumerBuilder) {
-        getCurrentModule().service(id, consumerBuilder);
+        return service(createServiceConfig(id, consumerBuilder));
+    }
+
+    private <S> ServiceConfig createServiceConfig(String id, Consumer<ServiceBuilder<S>> consumerBuilder) {
+        ServiceBuilder builder = createServiceBuilder(id);
+        consumerBuilder.accept(builder);
+        ServiceConfig serviceConfig = builder.build();
+        return serviceConfig;
+    }
+
+    public DubboBootstrap services(List<ServiceConfig> serviceConfigs) {
+        if (CollectionUtils.isEmpty(serviceConfigs)) {
+            return this;
+        }
+        for (ServiceConfig serviceConfig : serviceConfigs) {
+            this.service(serviceConfig);
+        }
         return this;
     }
 
     public DubboBootstrap service(ServiceConfig<?> serviceConfig) {
-        getCurrentModule().service(serviceConfig);
+        this.service(serviceConfig, applicationModel.getDefaultModule());
         return this;
     }
 
-    public DubboBootstrap services(List<ServiceConfig> serviceConfigs) {
-        getCurrentModule().services(serviceConfigs);
+    public DubboBootstrap service(ServiceConfig<?> serviceConfig, ModuleModel moduleModel) {
+        serviceConfig.setScopeModel(moduleModel);
+        moduleModel.getConfigManager().addService(serviceConfig);
         return this;
     }
 
     // {@link Reference} correlative methods
     public <S> DubboBootstrap reference(Consumer<ReferenceBuilder<S>> consumerBuilder) {
-        getCurrentModule().reference(consumerBuilder);
-        return this;
+        return reference(null, consumerBuilder);
     }
 
     public <S> DubboBootstrap reference(String id, Consumer<ReferenceBuilder<S>> consumerBuilder) {
-        getCurrentModule().reference(id, consumerBuilder);
+        return reference(createReferenceConfig(id, consumerBuilder));
+    }
+
+    private <S> ReferenceConfig createReferenceConfig(String id, Consumer<ReferenceBuilder<S>> consumerBuilder) {
+        ReferenceBuilder builder = createReferenceBuilder(id);
+        consumerBuilder.accept(builder);
+        ReferenceConfig referenceConfig = builder.build();
+        return referenceConfig;
+    }
+
+    public DubboBootstrap references(List<ReferenceConfig> referenceConfigs) {
+        if (CollectionUtils.isEmpty(referenceConfigs)) {
+            return this;
+        }
+        for (ReferenceConfig referenceConfig : referenceConfigs) {
+            this.reference(referenceConfig);
+        }
         return this;
     }
 
     public DubboBootstrap reference(ReferenceConfig<?> referenceConfig) {
-        getCurrentModule().reference(referenceConfig);
-        return this;
+        return reference(referenceConfig, applicationModel.getDefaultModule());
     }
 
-    public DubboBootstrap references(List<ReferenceConfig> referenceConfigs) {
-        getCurrentModule().references(referenceConfigs);
+    public DubboBootstrap reference(ReferenceConfig<?> referenceConfig, ModuleModel moduleModel) {
+        referenceConfig.setScopeModel(moduleModel);
+        moduleModel.getConfigManager().addReference(referenceConfig);
         return this;
     }
 
     // {@link ProviderConfig} correlative methods
     public DubboBootstrap provider(Consumer<ProviderBuilder> builderConsumer) {
-        getCurrentModule().provider(builderConsumer);
+        provider(null, builderConsumer);
         return this;
     }
 
     public DubboBootstrap provider(String id, Consumer<ProviderBuilder> builderConsumer) {
-        getCurrentModule().provider(id, builderConsumer);
+        this.provider(createProviderConfig(id, builderConsumer));
         return this;
     }
 
+    private ProviderConfig createProviderConfig(String id, Consumer<ProviderBuilder> builderConsumer) {
+        ProviderBuilder builder = createProviderBuilder(id);
+        builderConsumer.accept(builder);
+        ProviderConfig providerConfig = builder.build();
+        return providerConfig;
+    }
+
     public DubboBootstrap provider(ProviderConfig providerConfig) {
-        return providers(singletonList(providerConfig));
+        return this.provider(providerConfig, applicationModel.getDefaultModule());
     }
 
     public DubboBootstrap providers(List<ProviderConfig> providerConfigs) {
-        getCurrentModule().providers(providerConfigs);
+        for (ProviderConfig providerConfig : providerConfigs) {
+            this.provider(providerConfig, applicationModel.getDefaultModule());
+        }
+        return this;
+    }
+
+    public DubboBootstrap provider(ProviderConfig providerConfig, ModuleModel moduleModel) {
+        providerConfig.setScopeModel(moduleModel);
+        moduleModel.getConfigManager().addProvider(providerConfig);
         return this;
     }
 
     // {@link ConsumerConfig} correlative methods
     public DubboBootstrap consumer(Consumer<ConsumerBuilder> builderConsumer) {
-        getCurrentModule().consumer(builderConsumer);
-        return this;
+        return consumer(null, builderConsumer);
     }
 
     public DubboBootstrap consumer(String id, Consumer<ConsumerBuilder> builderConsumer) {
-        getCurrentModule().consumer(id, builderConsumer);
-        return this;
+        return consumer(createConsumerConfig(id, builderConsumer));
+    }
+
+    private ConsumerConfig createConsumerConfig(String id, Consumer<ConsumerBuilder> builderConsumer) {
+        ConsumerBuilder builder = createConsumerBuilder(id);
+        builderConsumer.accept(builder);
+        ConsumerConfig consumerConfig = builder.build();
+        return consumerConfig;
     }
 
     public DubboBootstrap consumer(ConsumerConfig consumerConfig) {
-        getCurrentModule().consumer(consumerConfig);
-        return this;
+        return this.consumer(consumerConfig, applicationModel.getDefaultModule());
     }
 
     public DubboBootstrap consumers(List<ConsumerConfig> consumerConfigs) {
-        getCurrentModule().consumers(consumerConfigs);
+        for (ConsumerConfig consumerConfig : consumerConfigs) {
+            this.consumer(consumerConfig, applicationModel.getDefaultModule());
+        }
+        return this;
+    }
+
+    public DubboBootstrap consumer(ConsumerConfig consumerConfig, ModuleModel moduleModel) {
+        consumerConfig.setScopeModel(moduleModel);
+        moduleModel.getConfigManager().addConsumer(consumerConfig);
         return this;
     }
     // module configs end
@@ -566,7 +606,6 @@ public final class DubboBootstrap {
     }
 
     public DubboBootstrap module(ModuleConfig module) {
-        //TODO module config?
         module.setScopeModel(applicationModel);
         configManager.setModule(module);
         return this;
@@ -578,1307 +617,99 @@ public final class DubboBootstrap {
         return this;
     }
 
-    public ReferenceConfigCache getCache() {
-        return cache;
-    }
+    /* serve for builder apis, begin */
 
-    /**
-     * Initialize
-     */
-    public synchronized void initialize() {
-        if (!initialized.compareAndSet(false, true)) {
-            return;
-        }
+    private ApplicationBuilder createApplicationBuilder(String name) {
+        return new ApplicationBuilder().name(name);
+    }
 
-        startConfigCenter();
+    private RegistryBuilder createRegistryBuilder(String id) {
+        return new RegistryBuilder().id(id);
+    }
 
-        loadConfigsFromProps();
+    private ProtocolBuilder createProtocolBuilder(String id) {
+        return new ProtocolBuilder().id(id);
+    }
 
-        checkGlobalConfigs();
+    private ServiceBuilder createServiceBuilder(String id) {
+        return new ServiceBuilder().id(id);
+    }
 
-        // @since 2.7.8
-        startMetadataCenter();
+    private ReferenceBuilder createReferenceBuilder(String id) {
+        return new ReferenceBuilder().id(id);
+    }
 
-        initMetadataService();
+    private ProviderBuilder createProviderBuilder(String id) {
+        return new ProviderBuilder().id(id);
+    }
 
-        if (logger.isInfoEnabled()) {
-            logger.info(NAME + " has been initialized!");
-        }
+    private ConsumerBuilder createConsumerBuilder(String id) {
+        return new ConsumerBuilder().id(id);
     }
+    /* serve for builder apis, end */
 
-    private void checkGlobalConfigs() {
-        // check config types (ignore metadata-center)
-        List<Class<? extends AbstractConfig>> multipleConfigTypes = Arrays.asList(
-            ApplicationConfig.class,
-            ProtocolConfig.class,
-            RegistryConfig.class,
-            MetadataReportConfig.class,
-            ProviderConfig.class,
-            ConsumerConfig.class,
-            MonitorConfig.class,
-            ModuleConfig.class,
-            MetricsConfig.class,
-            SslConfig.class);
-
-        for (Class<? extends AbstractConfig> configType : multipleConfigTypes) {
-            checkDefaultAndValidateConfigs(configType);
-        }
 
-        // check port conflicts
-        Map<Integer, ProtocolConfig> protocolPortMap = new LinkedHashMap<>();
-        for (ProtocolConfig protocol : configManager.getProtocols()) {
-            Integer port = protocol.getPort();
-            if (port == null || port == -1) {
-                continue;
-            }
-            ProtocolConfig prevProtocol = protocolPortMap.get(port);
-            if (prevProtocol != null) {
-                throw new IllegalStateException("Duplicated port used by protocol configs, port: " + port +
-                    ", configs: " + Arrays.asList(prevProtocol, protocol));
-            }
-            protocolPortMap.put(port, protocol);
-        }
+    public Module newModule() {
+        return new Module(applicationModel.newModule());
+    }
 
-        // check reference and service
-        for (ReferenceConfigBase<?> reference : configManager.getReferences()) {
-            reference.refresh();
-        }
-        for (ServiceConfigBase service : configManager.getServices()) {
-            service.refresh();
-        }
+    public DubboBootstrap endModule() {
+        return this;
     }
 
-    private <T extends AbstractConfig> void checkDefaultAndValidateConfigs(Class<T> configType) {
-        try {
-            if (shouldAddDefaultConfig(configType)) {
-                T config = createConfig(configType);
-                config.refresh();
-                if (!isNeedValidation(config) || config.isValid()) {
-                    configManager.addConfig(config);
-                } else {
-                    logger.info("Ignore invalid config: " + config);
-                }
-            }
-        } catch (Exception e) {
-            throw new IllegalStateException("Add default config failed: " + configType.getSimpleName(), e);
-        }
 
-        //validate configs
-        Collection<T> configs = configManager.getConfigs(configType);
-        for (T config : configs) {
-            validateConfig(config);
-        }
+    public class Module {
+        private ModuleModel moduleModel;
+        private DubboBootstrap bootstrap;
 
-        // check required default
-        if (isRequired(configType) && configs.isEmpty()) {
-            throw new IllegalStateException("Default config not found for " + configType.getSimpleName());
+        public Module(ModuleModel moduleModel) {
+            this.moduleModel = moduleModel;
+            this.bootstrap = DubboBootstrap.this;
         }
-    }
 
-    /**
-     * The component configuration that does not affect the main process does not need to be verified.
-     *
-     * @param config
-     * @param <T>
-     * @return
-     */
-    private <T extends AbstractConfig> boolean isNeedValidation(T config) {
-        if (config instanceof MetadataReportConfig) {
-            return false;
-        }
-        return true;
-    }
-
-    private <T extends AbstractConfig> void validateConfig(T config) {
-        if (config instanceof ProtocolConfig) {
-            ConfigValidationUtils.validateProtocolConfig((ProtocolConfig) config);
-        } else if (config instanceof RegistryConfig) {
-            ConfigValidationUtils.validateRegistryConfig((RegistryConfig) config);
-        } else if (config instanceof MetadataReportConfig) {
-            ConfigValidationUtils.validateMetadataConfig((MetadataReportConfig) config);
-        } else if (config instanceof ProviderConfig) {
-            ConfigValidationUtils.validateProviderConfig((ProviderConfig) config);
-        } else if (config instanceof ConsumerConfig) {
-            ConfigValidationUtils.validateConsumerConfig((ConsumerConfig) config);
-        } else if (config instanceof ApplicationConfig) {
-            ConfigValidationUtils.validateApplicationConfig((ApplicationConfig) config);
-        } else if (config instanceof MonitorConfig) {
-            ConfigValidationUtils.validateMonitorConfig((MonitorConfig) config);
-        } else if (config instanceof ModuleConfig) {
-            ConfigValidationUtils.validateModuleConfig((ModuleConfig) config);
-        } else if (config instanceof MetricsConfig) {
-            ConfigValidationUtils.validateMetricsConfig((MetricsConfig) config);
-        } else if (config instanceof SslConfig) {
-            ConfigValidationUtils.validateSslConfig((SslConfig) config);
+        public DubboBootstrap endModule() {
+            return this.bootstrap.endModule();
         }
-    }
 
-    /**
-     * The configuration that does not affect the main process is not necessary.
-     *
-     * @param clazz
-     * @param <T>
-     * @return
-     */
-    private <T extends AbstractConfig> boolean isRequired(Class<T> clazz) {
-        if (clazz == RegistryConfig.class ||
-            clazz == MetadataReportConfig.class ||
-            clazz == MonitorConfig.class ||
-            clazz == MetricsConfig.class) {
-            return false;
+        public ModuleModel getModuleModel() {
+            return moduleModel;
         }
-        return true;
-    }
 
-    private <T extends AbstractConfig> boolean shouldAddDefaultConfig(Class<T> clazz) {
-        // Configurations that are not required will not be automatically added to the default configuration
-        if (!isRequired(clazz)) {
-            return false;
+        // {@link ServiceConfig} correlative methods
+        public <S> Module service(Consumer<ServiceBuilder<S>> consumerBuilder) {
+            return service(null, consumerBuilder);
         }
 
-        return configManager.getDefaultConfigs(clazz).isEmpty();
-    }
-
-    private void startConfigCenter() {
-
-        // load application config
-        loadConfigs(ApplicationConfig.class);
-
-        // load config centers
-        loadConfigs(ConfigCenterConfig.class);
-
-        useRegistryAsConfigCenterIfNecessary();
+        public <S> Module service(String id, Consumer<ServiceBuilder<S>> consumerBuilder) {
+            return service(createServiceConfig(id, consumerBuilder));
+        }
 
-        // check Config Center
-        Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();
-        if (CollectionUtils.isEmpty(configCenters)) {
-            ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
-            configCenterConfig.setScopeModel(applicationModel);
-            configCenterConfig.refresh();
-            ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
-            if (configCenterConfig.isValid()) {
-                configManager.addConfigCenter(configCenterConfig);
-                configCenters = configManager.getConfigCenters();
+        public Module services(List<ServiceConfig> serviceConfigs) {
+            if (CollectionUtils.isEmpty(serviceConfigs)) {
+                return this;
             }
-        } else {
-            for (ConfigCenterConfig configCenterConfig : configCenters) {
-                configCenterConfig.refresh();
-                ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
+            for (ServiceConfig serviceConfig : serviceConfigs) {
+                this.service(serviceConfig);
             }
+            return this;
         }
 
-        if (CollectionUtils.isNotEmpty(configCenters)) {
-            CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();
-            for (ConfigCenterConfig configCenter : configCenters) {
-                // Pass config from ConfigCenterBean to environment
-                environment.updateExternalConfigMap(configCenter.getExternalConfiguration());
-                environment.updateAppExternalConfigMap(configCenter.getAppExternalConfiguration());
-
-                // Fetch config from remote config center
-                compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));
-            }
-            environment.setDynamicConfiguration(compositeDynamicConfiguration);
+        public Module service(ServiceConfig<?> serviceConfig) {
+            DubboBootstrap.this.service(serviceConfig, moduleModel);
+            return this;
         }
 
-        configManager.refreshAll();
-    }
-
-    private void startMetadataCenter() {
+        // {@link Reference} correlative methods
+        public <S> Module reference(Consumer<ReferenceBuilder<S>> consumerBuilder) {
+            return reference(null, consumerBuilder);
+        }
 
-        useRegistryAsMetadataCenterIfNecessary();
-
-        ApplicationConfig applicationConfig = getApplication();
-
-        String metadataType = applicationConfig.getMetadataType();
-        // FIXME, multiple metadata config support.
-        Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();
-        if (CollectionUtils.isEmpty(metadataReportConfigs)) {
-            if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {
-                throw new IllegalStateException("No MetadataConfig found, Metadata Center address is required when 'metadata=remote' is enabled.");
-            }
-            return;
-        }
-
-        MetadataReportInstance metadataReportInstance = applicationModel.getBeanFactory().getBean(MetadataReportInstance.class);
-        for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) {
-            ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);
-            if (!metadataReportConfig.isValid()) {
-                logger.info("Ignore invalid metadata-report config: " + metadataReportConfig);
-                continue;
-            }
-            metadataReportInstance.init(metadataReportConfig);
-        }
-    }
-
-    /**
-     * For compatibility purpose, use registry as the default config center when
-     * there's no config center specified explicitly and
-     * useAsConfigCenter of registryConfig is null or true
-     */
-    private void useRegistryAsConfigCenterIfNecessary() {
-        // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated.
-        if (environment.getDynamicConfiguration().isPresent()) {
-            return;
-        }
-
-        if (CollectionUtils.isNotEmpty(configManager.getConfigCenters())) {
-            return;
-        }
-
-        // load registry
-        loadConfigs(RegistryConfig.class);
-
-        List<RegistryConfig> defaultRegistries = configManager.getDefaultRegistries();
-        if (defaultRegistries.size() > 0) {
-            defaultRegistries
-                .stream()
-                .filter(this::isUsedRegistryAsConfigCenter)
-                .map(this::registryAsConfigCenter)
-                .forEach(configCenter -> {
-                    if (configManager.getConfigCenter(configCenter.getId()).isPresent()) {
-                        return;
-                    }
-                    configManager.addConfigCenter(configCenter);
-                    logger.info("use registry as config-center: " + configCenter);
-
-                });
-        }
-    }
-
-    private boolean isUsedRegistryAsConfigCenter(RegistryConfig registryConfig) {
-        return isUsedRegistryAsCenter(registryConfig, registryConfig::getUseAsConfigCenter, "config",
-            DynamicConfigurationFactory.class);
-    }
-
-    private ConfigCenterConfig registryAsConfigCenter(RegistryConfig registryConfig) {
-        String protocol = registryConfig.getProtocol();
-        Integer port = registryConfig.getPort();
-        URL url = URL.valueOf(registryConfig.getAddress(), registryConfig.getScopeModel());
-        String id = "config-center-" + protocol + "-" + url.getHost() + "-" + port;
-        ConfigCenterConfig cc = new ConfigCenterConfig();
-        cc.setId(id);
-        cc.setScopeModel(applicationModel);
-        if (cc.getParameters() == null) {
-            cc.setParameters(new HashMap<>());
-        }
-        if (registryConfig.getParameters() != null) {
-            cc.getParameters().putAll(registryConfig.getParameters()); // copy the parameters
-        }
-        cc.getParameters().put(CLIENT_KEY, registryConfig.getClient());
-        cc.setProtocol(protocol);
-        cc.setPort(port);
-        if (StringUtils.isNotEmpty(registryConfig.getGroup())) {
-            cc.setGroup(registryConfig.getGroup());
-        }
-        cc.setAddress(getRegistryCompatibleAddress(registryConfig));
-        cc.setNamespace(registryConfig.getGroup());
-        cc.setUsername(registryConfig.getUsername());
-        cc.setPassword(registryConfig.getPassword());
-        if (registryConfig.getTimeout() != null) {
-            cc.setTimeout(registryConfig.getTimeout().longValue());
-        }
-        cc.setHighestPriority(false);
-        return cc;
-    }
-
-    private void useRegistryAsMetadataCenterIfNecessary() {
-
-        Collection<MetadataReportConfig> metadataConfigs = configManager.getMetadataConfigs();
-
-        if (CollectionUtils.isNotEmpty(metadataConfigs)) {
-            return;
-        }
-
-        List<RegistryConfig> defaultRegistries = configManager.getDefaultRegistries();
-        if (defaultRegistries.size() > 0) {
-            defaultRegistries
-                .stream()
-                .filter(this::isUsedRegistryAsMetadataCenter)
-                .map(this::registryAsMetadataCenter)
-                .forEach(metadataReportConfig -> {
-                    Optional<MetadataReportConfig> configOptional = configManager.getConfig(MetadataReportConfig.class, metadataReportConfig.getId());
-                    if (configOptional.isPresent()) {
-                        return;
-                    }
-                    configManager.addMetadataReport(metadataReportConfig);
-                    logger.info("use registry as metadata-center: " + metadataReportConfig);
-                });
-        }
-    }
-
-    private boolean isUsedRegistryAsMetadataCenter(RegistryConfig registryConfig) {
-        return isUsedRegistryAsCenter(registryConfig, registryConfig::getUseAsMetadataCenter, "metadata",
-            MetadataReportFactory.class);
-    }
-
-    /**
-     * Is used the specified registry as a center infrastructure
-     *
-     * @param registryConfig       the {@link RegistryConfig}
-     * @param usedRegistryAsCenter the configured value on
-     * @param centerType           the type name of center
-     * @param extensionClass       an extension class of a center infrastructure
-     * @return
-     * @since 2.7.8
-     */
-    private boolean isUsedRegistryAsCenter(RegistryConfig registryConfig, Supplier<Boolean> usedRegistryAsCenter,
-                                           String centerType,
-                                           Class<?> extensionClass) {
-        final boolean supported;
-
-        Boolean configuredValue = usedRegistryAsCenter.get();
-        if (configuredValue != null) { // If configured, take its value.
-            supported = configuredValue.booleanValue();
-        } else {                       // Or check the extension existence
-            String protocol = registryConfig.getProtocol();
-            supported = supportsExtension(extensionClass, protocol);
-            if (logger.isInfoEnabled()) {
-                logger.info(format("No value is configured in the registry, the %s extension[name : %s] %s as the %s center"
-                    , extensionClass.getSimpleName(), protocol, supported ? "supports" : "does not support", centerType));
-            }
-        }
-
-        if (logger.isInfoEnabled()) {
-            logger.info(format("The registry[%s] will be %s as the %s center", registryConfig,
-                supported ? "used" : "not used", centerType));
-        }
-        return supported;
-    }
-
-    /**
-     * Supports the extension with the specified class and name
-     *
-     * @param extensionClass the {@link Class} of extension
-     * @param name           the name of extension
-     * @return if supports, return <code>true</code>, or <code>false</code>
-     * @since 2.7.8
-     */
-    private boolean supportsExtension(Class<?> extensionClass, String name) {
-        if (isNotEmpty(name)) {
-            ExtensionLoader extensionLoader = getExtensionLoader(extensionClass);
-            return extensionLoader.hasExtension(name);
-        }
-        return false;
-    }
-
-    private MetadataReportConfig registryAsMetadataCenter(RegistryConfig registryConfig) {
-        String protocol = registryConfig.getProtocol();
-        URL url = URL.valueOf(registryConfig.getAddress(), registryConfig.getScopeModel());
-        String id = "metadata-center-" + protocol + "-" + url.getHost() + "-" + url.getPort();
-        MetadataReportConfig metadataReportConfig = new MetadataReportConfig();
-        metadataReportConfig.setId(id);
-        metadataReportConfig.setScopeModel(applicationModel);
-        if (metadataReportConfig.getParameters() == null) {
-            metadataReportConfig.setParameters(new HashMap<>());
-        }
-        if (registryConfig.getParameters() != null) {
-            metadataReportConfig.getParameters().putAll(registryConfig.getParameters()); // copy the parameters
-        }
-        metadataReportConfig.getParameters().put(CLIENT_KEY, registryConfig.getClient());
-        metadataReportConfig.setGroup(registryConfig.getGroup());
-        metadataReportConfig.setAddress(getRegistryCompatibleAddress(registryConfig));
-        metadataReportConfig.setUsername(registryConfig.getUsername());
-        metadataReportConfig.setPassword(registryConfig.getPassword());
-        metadataReportConfig.setTimeout(registryConfig.getTimeout());
-        return metadataReportConfig;
-    }
-
-    private String getRegistryCompatibleAddress(RegistryConfig registryConfig) {
-        String registryAddress = registryConfig.getAddress();
-        String[] addresses = REGISTRY_SPLIT_PATTERN.split(registryAddress);
-        if (ArrayUtils.isEmpty(addresses)) {
-            throw new IllegalStateException("Invalid registry address found.");
-        }
-        String address = addresses[0];
-        // since 2.7.8
-        // Issue : https://github.com/apache/dubbo/issues/6476
-        StringBuilder metadataAddressBuilder = new StringBuilder();
-        URL url = URL.valueOf(address, registryConfig.getScopeModel());
-        String protocolFromAddress = url.getProtocol();
-        if (isEmpty(protocolFromAddress)) {
-            // If the protocol from address is missing, is like :
-            // "dubbo.registry.address = 127.0.0.1:2181"
-            String protocolFromConfig = registryConfig.getProtocol();
-            metadataAddressBuilder.append(protocolFromConfig).append("://");
-        }
-        metadataAddressBuilder.append(address);
-        return metadataAddressBuilder.toString();
-    }
-
-    private void loadConfigsFromProps() {
-
-        // application config has load before starting config center
-        // load dubbo.applications.xxx
-        loadConfigs(ApplicationConfig.class);
-
-        // load dubbo.modules.xxx
-        loadConfigs(ModuleConfig.class);
-
-        // load dubbo.monitors.xxx
-        loadConfigs(MonitorConfig.class);
-
-        // load dubbo.metricses.xxx
-        loadConfigs(MetricsConfig.class);
-
-        // load multiple config types:
-        // load dubbo.protocols.xxx
-        loadConfigs(ProtocolConfig.class);
-
-        // load dubbo.registries.xxx
-        loadConfigs(RegistryConfig.class);
-
-        // load dubbo.providers.xxx
-        loadConfigs(ProviderConfig.class);
-
-        // load dubbo.consumers.xxx
-        loadConfigs(ConsumerConfig.class);
-
-        // load dubbo.metadata-report.xxx
-        loadConfigs(MetadataReportConfig.class);
-
-        // config centers has bean loaded before starting config center
-        //loadConfigs(ConfigCenterConfig.class);
-
-    }
-
-    private <T extends AbstractConfig> void loadConfigs(Class<T> cls) {
-        // load multiple configs with id
-        Set<String> configIds = this.getConfigIds(cls);
-        configIds.forEach(id -> {
-            if (!configManager.getConfig(cls, id).isPresent()) {
-                T config = null;
-                try {
-                    config = createConfig(cls);
-                    config.setId(id);
-                } catch (Exception e) {
-                    throw new IllegalStateException("create config instance failed, id: " + id + ", type:" + cls.getSimpleName());
-                }
-
-                String key = null;
-                boolean addDefaultNameConfig = false;
-                try {
-                    // add default name config (same as id), e.g. dubbo.protocols.rest.port=1234
-                    key = DUBBO + "." + AbstractConfig.getPluralTagName(cls) + "." + id + ".name";
-                    if (applicationModel.getApplicationEnvironment().getPropertiesConfiguration().getProperty(key) == null) {
-                        applicationModel.getApplicationEnvironment().getPropertiesConfiguration().setProperty(key, id);
-                        addDefaultNameConfig = true;
-                    }
-
-                    config.refresh();
-                    configManager.addConfig(config);
-                } catch (Exception e) {
-                    logger.error("load config failed, id: " + id + ", type:" + cls.getSimpleName(), e);
-                    throw new IllegalStateException("load config failed, id: " + id + ", type:" + cls.getSimpleName());
-                } finally {
-                    if (addDefaultNameConfig && key != null) {
-                        applicationModel.getApplicationEnvironment().getPropertiesConfiguration().remove(key);
-                    }
-                }
-            }
-        });
-
-        // If none config of the type, try load single config
-        if (configManager.getConfigs(cls).isEmpty()) {
-            // load single config
-            List<Map<String, String>> configurationMaps = environment.getConfigurationMaps();
-            if (ConfigurationUtils.hasSubProperties(configurationMaps, AbstractConfig.getTypePrefix(cls))) {
-                T config = null;
-                try {
-                    config = createConfig(cls);
-                    config.refresh();
-                } catch (Exception e) {
-                    throw new IllegalStateException("create default config instance failed, type:" + cls.getSimpleName());
-                }
-
-                configManager.addConfig(config);
-            }
-        }
-
-    }
-
-    private <T extends AbstractConfig> T createConfig(Class<T> cls) throws InstantiationException, IllegalAccessException {
-        T config = cls.newInstance();
-        if (config instanceof ProviderConfig || config instanceof ConsumerConfig || config instanceof ReferenceConfigBase
-            || config instanceof ServiceConfigBase) {
-            config.setScopeModel(getCurrentModule().moduleModel);
-        } else {
-            config.setScopeModel(applicationModel);
-        }
-        return config;
-    }
-
-    /**
-     * Search props and extract config ids of specify type.
-     * <pre>
-     * # properties
-     * dubbo.registries.registry1.address=xxx
-     * dubbo.registries.registry2.port=xxx
-     *
-     * # extract
-     * Set configIds = getConfigIds(RegistryConfig.class)
-     *
-     * # result
-     * configIds: ["registry1", "registry2"]
-     * </pre>
-     *
-     * @param clazz config type
-     * @return ids of specify config type
-     */
-    private Set<String> getConfigIds(Class<? extends AbstractConfig> clazz) {
-        String prefix = CommonConstants.DUBBO + "." + AbstractConfig.getPluralTagName(clazz) + ".";
-        return ConfigurationUtils.getSubIds(environment.getConfigurationMaps(), prefix);
-    }
-
-    /**
-     * Initialize {@link MetadataService} from {@link WritableMetadataService}'s extension
-     */
-    private void initMetadataService() {
-//        startMetadataCenter();
-        this.metadataService = getExtensionLoader(WritableMetadataService.class).getDefaultExtension();
-        // support injection by super type MetadataService
-        applicationModel.getBeanFactory().registerBean(this.metadataService);
-
-        //this.metadataServiceExporter = new ConfigurableMetadataServiceExporter(metadataService);
-        this.metadataServiceExporter = getExtensionLoader(MetadataServiceExporter.class).getDefaultExtension();
-    }
-
-    /**
-     * Start the bootstrap
-     */
-    public synchronized DubboBootstrap start() {
-        // avoid re-entry start method multiple times in same thread
-        if (isCurrentlyInStart) {
-            return this;
-        }
-
-        isCurrentlyInStart = true;
-        try {
-            if (started.compareAndSet(false, true)) {
-                startup.set(false);
-                shutdown.set(false);
-                awaited.set(false);
-
-                initialize();
-
-                if (logger.isInfoEnabled()) {
-                    logger.info(NAME + " is starting...");
-                }
-
-                doStart();
-
-                if (logger.isInfoEnabled()) {
-                    logger.info(NAME + " has started.");
-                }
-            } else {
-                if (logger.isInfoEnabled()) {
-                    logger.info(NAME + " is started, export/refer new services.");
-                }
-
-                doStart();
-
-                if (logger.isInfoEnabled()) {
-                    logger.info(NAME + " finish export/refer new services.");
-                }
-            }
-            return this;
-        } finally {
-            isCurrentlyInStart = false;
-        }
-    }
-
-    private void doStart() {
-        // 1. export Dubbo Services
-        exportServices();
-
-        // If register consumer instance or has exported services
-        if (isRegisterConsumerInstance() || hasExportedServices()) {
-            // 2. export MetadataService
-            exportMetadataService();
-            // 3. Register the local ServiceInstance if required
-            registerServiceInstance();
-        }
-
-        referServices();
-
-        // wait async export / refer finish if needed
-        awaitFinish();
-
-        if (isExportBackground() || isReferBackground()) {
-            new Thread(() -> {
-                while (!asyncExportFinish || !asyncReferFinish) {
-                    try {
-                        Thread.sleep(1000);
-                    } catch (InterruptedException e) {
-                        logger.error(NAME + " waiting async export / refer occurred and error.", e);
-                    }
-                }
-                onStarted();
-            }).start();
-        } else {
-            onStarted();
-        }
-    }
-
-    private boolean hasExportedServices() {
-        return CollectionUtils.isNotEmpty(configManager.getServices());
-    }
-
-    /**
-     * Block current thread to be await.
-     *
-     * @return {@link DubboBootstrap}
-     */
-    public DubboBootstrap await() {
-        // if has been waited, no need to wait again, return immediately
-        if (!awaited.get()) {
-            if (!executorService.isShutdown()) {
-                executeMutually(() -> {
-                    while (!awaited.get()) {
-                        if (logger.isInfoEnabled()) {
-                            logger.info(NAME + " awaiting ...");
-                        }
-                        try {
-                            condition.await();
-                        } catch (InterruptedException e) {
-                            Thread.currentThread().interrupt();
-                        }
-                    }
-                });
-            }
-        }
-        return this;
-    }
-
-    private void waitAsyncExportIfNeeded() {
-        if (asyncExportingFutures.size() > 0) {
-            asyncExportFinish = false;
-            if (isExportBackground()) {
-                new Thread(this::waitExportFinish).start();
-            } else {
-                waitExportFinish();
-            }
-        }
-    }
-
-    private boolean isExportBackground() {
-        List<Boolean> list = configManager.getProviders()
-            .stream()
-            .map(ProviderConfig::getExportBackground)
-            .filter(k -> k != null && k)
-            .collect(Collectors.toList());
-
-        return CollectionUtils.isNotEmpty(list);
-    }
-
-    private void waitExportFinish() {
-        try {
-            logger.info(NAME + " waiting services exporting asynchronously...");
-            CompletableFuture<?> future = CompletableFuture.allOf(asyncExportingFutures.toArray(new CompletableFuture[0]));
-            future.get();
-        } catch (Exception e) {
-            logger.warn(NAME + " asynchronous export occurred an exception.");
-        } finally {
-            executorRepository.shutdownServiceExportExecutor();
-            logger.info(NAME + " asynchronous export finished.");
-            asyncExportFinish = true;
-        }
-    }
-
-    private void waitAsyncReferIfNeeded() {
-        if (asyncReferringFutures.size() > 0) {
-            asyncReferFinish = false;
-            if (isReferBackground()) {
-                new Thread(this::waitReferFinish).start();
-            } else {
-                waitReferFinish();
-            }
-        }
-    }
-
-    private boolean isReferBackground() {
-        List<Boolean> list = configManager.getConsumers()
-            .stream()
-            .map(ConsumerConfig::getReferBackground)
-            .filter(k -> k != null && k)
-            .collect(Collectors.toList());
-
-        return CollectionUtils.isNotEmpty(list);
-    }
-
-    private void waitReferFinish() {
-        try {
-            logger.info(NAME + " waiting services referring asynchronously...");
-            CompletableFuture<?> future = CompletableFuture.allOf(asyncReferringFutures.toArray(new CompletableFuture[0]));
-            future.get();
-        } catch (Exception e) {
-            logger.warn(NAME + " asynchronous refer occurred an exception.");
-        } finally {
-            executorRepository.shutdownServiceExportExecutor();
-            logger.info(NAME + " asynchronous refer finished.");
-            asyncReferFinish = true;
-        }
-    }
-
-    private void awaitFinish() {
-        waitAsyncExportIfNeeded();
-        waitAsyncReferIfNeeded();
-    }
-
-    public boolean isInitialized() {
-        return initialized.get();
-    }
-
-    public boolean isStarted() {
-        return started.get();
-    }
-
-    public boolean isStartup() {
-        return startup.get();
-    }
-
-    public boolean isShutdown() {
-        return shutdown.get();
-    }
-
-
-    public DubboBootstrap stop() throws IllegalStateException {
-        destroy();
-        return this;
-    }
-    /* serve for builder apis, begin */
-
-    private ApplicationBuilder createApplicationBuilder(String name) {
-        return new ApplicationBuilder().name(name);
-    }
-
-    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 ProviderBuilder createProviderBuilder(String id) {
-        return new ProviderBuilder().id(id);
-    }
-
-    private ConsumerBuilder createConsumerBuilder(String id) {
-        return new ConsumerBuilder().id(id);
-    }
-    /* serve for builder apis, end */
-
-    private DynamicConfiguration prepareEnvironment(ConfigCenterConfig configCenter) {
-        if (configCenter.isValid()) {
-            if (!configCenter.checkOrUpdateInitialized(true)) {
-                return null;
-            }
-
-            DynamicConfiguration dynamicConfiguration = null;
-            try {
-                dynamicConfiguration = getDynamicConfiguration(configCenter.toUrl());
-            } catch (Exception e) {
-                if (!configCenter.isCheck()) {
-                    logger.warn("The configuration center failed to initialize", e);
-                    configCenter.checkOrUpdateInitialized(false);
-                    return null;
-                } else {
-                    throw new IllegalStateException(e);
-                }
-            }
-
-            String configContent = dynamicConfiguration.getProperties(configCenter.getConfigFile(), configCenter.getGroup());
-
-            String appGroup = getApplication().getName();
-            String appConfigContent = null;
-            if (isNotEmpty(appGroup)) {
-                appConfigContent = dynamicConfiguration.getProperties
-                    (isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(),
-                        appGroup
-                    );
-            }
-            try {
-                environment.updateExternalConfigMap(parseProperties(configContent));
-                environment.updateAppExternalConfigMap(parseProperties(appConfigContent));
-            } catch (IOException e) {
-                throw new IllegalStateException("Failed to parse configurations from Config Center.", e);
-            }
-            return dynamicConfiguration;
-        }
-        return null;
-    }
-
-    /**
-     * Get the instance of {@link DynamicConfiguration} by the specified connection {@link URL} of config-center
-     *
-     * @param connectionURL of config-center
-     * @return non-null
-     * @since 2.7.5
-     */
-    private DynamicConfiguration getDynamicConfiguration(URL connectionURL) {
-        String protocol = connectionURL.getProtocol();
-
-        DynamicConfigurationFactory factory = ConfigurationUtils.getDynamicConfigurationFactory(applicationModel, protocol);
-        return factory.getDynamicConfiguration(connectionURL);
-    }
-
-    /**
-     * export {@link MetadataService}
-     */
-    private void exportMetadataService() {
-        metadataServiceExporter.export();
-    }
-
-    private void unexportMetadataService() {
-        if (metadataServiceExporter != null && metadataServiceExporter.isExported()) {
-            try {
-                metadataServiceExporter.unexport();
-            } catch (Exception ignored) {
-                // ignored
-            }
-        }
-    }
-
-    private void exportServices() {
-        for (ServiceConfigBase sc : configManager.getServices()) {
-            // TODO, compatible with ServiceConfig.export()
-            ServiceConfig<?> serviceConfig = (ServiceConfig<?>) sc;
-            serviceConfig.setBootstrap(this);
-            if (!serviceConfig.isRefreshed()) {
-                serviceConfig.refresh();
-            }
-            if (sc.isExported()) {
-                continue;
-            }
-            if (sc.shouldExportAsync()) {
-                ExecutorService executor = executorRepository.getServiceExportExecutor();
-                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
-                    try {
-                        if (!sc.isExported()) {
-                            sc.export();
-                            exportedServices.add(sc);
-                        }
-                    } catch (Throwable t) {
-                        logger.error("export async catch error : " + t.getMessage(), t);
-                    }
-                }, executor);
-
-                asyncExportingFutures.add(future);
-            } else {
-                if (!sc.isExported()) {
-                    sc.export();
-                    exportedServices.add(sc);
-                }
-            }
-        }
-    }
-
-    private void unexportServices() {
-        exportedServices.forEach(sc -> {
-            try {
-                configManager.removeConfig(sc);
-                sc.unexport();
-            } catch (Exception ignored) {
-                // ignored
-            }
-        });
-
-        asyncExportingFutures.forEach(future -> {
-            if (!future.isDone()) {
-                future.cancel(true);
-            }
-        });
-        asyncExportingFutures.clear();
-        exportedServices.clear();
-    }
-
-    private void referServices() {
-        configManager.getReferences().forEach(rc -> {
-            try {
-                // TODO, compatible with  ReferenceConfig.refer()
-                ReferenceConfig<?> referenceConfig = (ReferenceConfig<?>) rc;
-                referenceConfig.setBootstrap(this);
-                if (!referenceConfig.isRefreshed()) {
-                    referenceConfig.refresh();
-                }
-
-                if (rc.shouldInit()) {
-                    if (rc.shouldReferAsync()) {
-                        ExecutorService executor = executorRepository.getServiceReferExecutor();
-                        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
-                            try {
-                                cache.get(rc);
-                            } catch (Throwable t) {
-                                logger.error("refer async catch error : " + t.getMessage(), t);
-                            }
-                        }, executor);
-
-                        asyncReferringFutures.add(future);
-                    } else {
-                        cache.get(rc);
-                    }
-                }
-            } catch (Throwable t) {
-                logger.error("refer catch error", t);
-                cache.destroy(rc);
-            }
-        });
-    }
-
-    private void unreferServices() {
-        try {
-            asyncReferringFutures.forEach(future -> {
-                if (!future.isDone()) {
-                    future.cancel(true);
-                }
-            });
-            asyncReferringFutures.clear();
-            cache.destroyAll();
-        } catch (Exception ignored) {
-        }
-    }
-
-    protected void registerServiceInstance() {
-        if (this.serviceInstance != null) {
-            return;
-        }
-
-        ApplicationConfig application = getApplication();
-        String serviceName = application.getName();
-        ServiceInstance serviceInstance = createServiceInstance(serviceName);
-        boolean registered = true;
-        try {
-            ServiceInstanceMetadataUtils.registerMetadataAndInstance(serviceInstance);
-        } catch (Exception e) {
-            registered = false;
-            logger.error("Register instance error", e);
-        }
-        if (registered) {
-            // scheduled task for updating Metadata and ServiceInstance
-            asyncMetadataFuture = executorRepository.nextScheduledExecutor().scheduleAtFixedRate(() -> {
-                InMemoryWritableMetadataService localMetadataService = (InMemoryWritableMetadataService) WritableMetadataService.getDefaultExtension(applicationModel);
-                localMetadataService.blockUntilUpdated();
-                try {
-                    ServiceInstanceMetadataUtils.refreshMetadataAndInstance(serviceInstance);
-                } catch (Exception e) {
-                    logger.error("Refresh instance and metadata error", e);
-                } finally {
-                    localMetadataService.releaseBlock();
-                }
-            }, 0, ConfigurationUtils.get(applicationModel, METADATA_PUBLISH_DELAY_KEY, DEFAULT_METADATA_PUBLISH_DELAY), TimeUnit.MILLISECONDS);
-        }
-    }
-
-    private void doRegisterServiceInstance(ServiceInstance serviceInstance) {
-        // register instance only when at least one service is exported.
-        if (serviceInstance.getPort() > 0) {
-            publishMetadataToRemote(serviceInstance);
-            logger.info("Start registering instance address to registry.");
-            getServiceDiscoveries().forEach(serviceDiscovery ->
-            {
-                ServiceInstance serviceInstanceForRegistry = new DefaultServiceInstance((DefaultServiceInstance) serviceInstance);
-                calInstanceRevision(serviceDiscovery, serviceInstanceForRegistry);
-                if (logger.isDebugEnabled()) {
-                    logger.info("Start registering instance address to registry" + serviceDiscovery.getUrl() + ", instance " + serviceInstanceForRegistry);
-                }
-                // register metadata
-                serviceDiscovery.register(serviceInstanceForRegistry);
-            });
-        }
-    }
-
-    private void publishMetadataToRemote(ServiceInstance serviceInstance) {
-//        InMemoryWritableMetadataService localMetadataService = (InMemoryWritableMetadataService)WritableMetadataService.getDefaultExtension();
-//        localMetadataService.blockUntilUpdated();
-        if (logger.isInfoEnabled()) {
-            logger.info("Start publishing metadata to remote center, this only makes sense for applications enabled remote metadata center.");
-        }
-        RemoteMetadataServiceImpl remoteMetadataService = applicationModel.getBeanFactory().getBean(RemoteMetadataServiceImpl.class);
-        remoteMetadataService.publishMetadata(serviceInstance.getServiceName());
-    }
-
-
-    private void unregisterServiceInstance() {
-        if (serviceInstance != null) {
-            getServiceDiscoveries().forEach(serviceDiscovery -> {
-                try {
-                    serviceDiscovery.unregister(serviceInstance);
-                } catch (Exception ignored) {
-                    // ignored
-                }
-            });
-        }
-    }
-
-    private ServiceInstance createServiceInstance(String serviceName) {
-        this.serviceInstance = new DefaultServiceInstance(serviceName, applicationModel);
-        setMetadataStorageType(serviceInstance, getMetadataType());
-        ServiceInstanceMetadataUtils.customizeInstance(this.serviceInstance);
-        return this.serviceInstance;
-    }
-
-    public void destroy() {
-        if (destroyLock.tryLock()
-            && shutdown.compareAndSet(false, true)) {
-            try {
-                if (destroyed.compareAndSet(false, true)) {
-                    if (started.compareAndSet(true, false)) {
-                        unregisterServiceInstance();
-                        unexportMetadataService();
-                        unexportServices();
-                        unreferServices();
-                        if (asyncMetadataFuture != null) {
-                            asyncMetadataFuture.cancel(true);
-                        }
-                    }
-
-                    destroyRegistries();
-                    destroyProtocols(applicationModel.getFrameworkModel());
-                    destroyServiceDiscoveries();
-                    destroyExecutorRepository();
-                    destroyMetadataReports();
-
-                    // check config
-                    checkConfigState();
-
-                    clear();
-                    shutdown();
-                    release();
-
-                    onStop();
-                }
-
-                destroyDynamicConfigurations();
-                ShutdownHookCallbacks.INSTANCE.clear();
-            } catch (Throwable ignored) {
-                // ignored
-                logger.warn(ignored.getMessage(), ignored);
-            } finally {
-                initialized.set(false);
-                startup.set(false);
-                destroyLock.unlock();
-            }
-
-            applicationModel.destroy();
-        }
-    }
-
-    private void onStarted() {
-        startup.set(true);
-        if (logger.isInfoEnabled()) {
-            logger.info(NAME + " is ready.");
-        }
-        ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
-        exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));
-    }
-
-    private void onStop() {
-        ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
-        exts.getSupportedExtensionInstances().forEach(ext -> ext.onStop(this));
-    }
-
-    private void checkConfigState() {
-        // config manager should not be cleared at this moment
-        if (!ignoreConfigState && !configManager.getApplication().isPresent()) {
-            logger.error("Dubbo config was cleaned prematurely");
-            throw new IllegalStateException("Dubbo config was cleaned prematurely");
-        }
-    }
-
-    private void destroyExecutorRepository() {
-        getExtensionLoader(ExecutorRepository.class).getDefaultExtension().destroyAll();
-    }
-
-    private void destroyRegistries() {
-        AbstractRegistryFactory.destroyAll();
-    }
-
-    /**
-     * Destroy all the protocols.
-     */
-    private static void destroyProtocols(FrameworkModel frameworkModel) {
-        //TODO destroy protocol in framework scope
-        ExtensionLoader<Protocol> loader = frameworkModel.getExtensionLoader(Protocol.class);
-        for (String protocolName : loader.getLoadedExtensions()) {
-            try {
-                Protocol protocol = loader.getLoadedExtension(protocolName);
-                if (protocol != null) {
-                    protocol.destroy();
-                }
-            } catch (Throwable t) {
-                logger.warn(t.getMessage(), t);
-            }
-        }
-    }
-
-    private static void destroyAllProtocols() {
-        for (FrameworkModel frameworkModel : FrameworkModel.getAllInstances()) {
-            destroyProtocols(frameworkModel);
-        }
-    }
-
-    private void destroyServiceDiscoveries() {
-        getServiceDiscoveries().forEach(serviceDiscovery -> {
-            try {
-                execute(serviceDiscovery::destroy);
-            } catch (Throwable ignored) {
-                logger.warn(ignored.getMessage(), ignored);
-            }
-        });
-        if (logger.isDebugEnabled()) {
-            logger.debug(NAME + "'s all ServiceDiscoveries have been destroyed.");
-        }
-    }
-
-    private void destroyMetadataReports() {
-        AbstractMetadataReportFactory.destroy();
-        MetadataReportInstance.reset();
-    }
-
-    private void destroyDynamicConfigurations() {
-        // DynamicConfiguration may be cached somewhere, and maybe used during destroy
-        // destroy them may cause some troubles, so just clear instances cache
-        // ExtensionLoader.resetExtensionLoader(DynamicConfigurationFactory.class);
-    }
-
-    private void clear() {
-        clearConfigs();
-        clearApplicationModel();
-    }
-
-    private void clearApplicationModel() {
-
-    }
-
-    private void clearConfigs() {
-        configManager.destroy();
-        if (logger.isDebugEnabled()) {
-            logger.debug(NAME + "'s configs have been clear.");
-        }
-    }
-
-    private void release() {
-        executeMutually(() -> {
-            if (awaited.compareAndSet(false, true)) {
-                if (logger.isInfoEnabled()) {
-                    logger.info(NAME + " is about to shutdown...");
-                }
-                condition.signalAll();
-            }
-        });
-    }
-
-    private void shutdown() {
-        if (!executorService.isShutdown()) {
-            // Shutdown executorService
-            try {
-                executorService.shutdown();
-            } catch (Throwable ignored) {
-                // ignored
-                logger.warn(ignored.getMessage(), ignored);
-            }
-        }
-    }
-
-    private void executeMutually(Runnable runnable) {
-        try {
-            lock.lock();
-            runnable.run();
-        } finally {
-            lock.unlock();
-        }
-    }
-
-    public ApplicationConfig getApplication() {
-        return configManager.getApplicationOrElseThrow();
-    }
-
-    public void setTakeoverMode(BootstrapTakeoverMode takeoverMode) {
-        this.started.set(false);
-        this.takeoverMode = takeoverMode;
-    }
-
-    public BootstrapTakeoverMode getTakeoverMode() {
-        return takeoverMode;
-    }
-
-    public Module addModule(ModuleModel moduleModel) {
-        applicationModel.addModule(moduleModel);
-        currentModule = new Module(moduleModel);
-        return currentModule;
-    }
-
-    public Module addModule() {
-        return this.addModule(new ModuleModel(applicationModel));
-    }
-
-    public DubboBootstrap endModule() {
-        currentModule = new Module(applicationModel.getDefaultModule());
-        return this;
-    }
-
-    public class Module {
-        private ModuleModel moduleModel;
-        private DubboBootstrap bootstrap;
-
-        public Module(ModuleModel moduleModel) {
-            this.moduleModel = moduleModel;
-            this.bootstrap = DubboBootstrap.this;
-        }
-
-        public DubboBootstrap endModule() {
-            return this.bootstrap.endModule();
-        }
-
-        // {@link ServiceConfig} correlative methods
-        public <S> Module service(Consumer<ServiceBuilder<S>> consumerBuilder) {
-            return service(null, consumerBuilder);
-        }
-
-        public <S> Module service(String id, Consumer<ServiceBuilder<S>> consumerBuilder) {
-            ServiceBuilder builder = createServiceBuilder(id);
-            consumerBuilder.accept(builder);
-            return service(builder.build());
-        }
-
-        public Module service(ServiceConfig<?> serviceConfig) {
-            serviceConfig.setBootstrap(this.bootstrap);
-            serviceConfig.setScopeModel(moduleModel);
-            configManager.addService(serviceConfig);
-            return this;
-        }
-
-        public Module services(List<ServiceConfig> serviceConfigs) {
-            if (CollectionUtils.isEmpty(serviceConfigs)) {
-                return this;
-            }
-            serviceConfigs.forEach(configManager::addService);
-            return this;
-        }
-
-        // {@link Reference} correlative methods
-        public <S> Module reference(Consumer<ReferenceBuilder<S>> consumerBuilder) {
-            return reference(null, consumerBuilder);
-        }
-
-        public <S> Module reference(String id, Consumer<ReferenceBuilder<S>> consumerBuilder) {
-            ReferenceBuilder builder = createReferenceBuilder(id);
-            consumerBuilder.accept(builder);
-            return reference(builder.build());
-        }
+        public <S> Module reference(String id, Consumer<ReferenceBuilder<S>> consumerBuilder) {
+            return reference(createReferenceConfig(id, consumerBuilder));
+        }
 
         public Module reference(ReferenceConfig<?> referenceConfig) {
-            referenceConfig.setBootstrap(this.bootstrap);
-            referenceConfig.setScopeModel(moduleModel);
-            configManager.addReference(referenceConfig);
+            DubboBootstrap.this.reference(referenceConfig, moduleModel);
             return this;
         }
 
@@ -1886,8 +717,9 @@ public final class DubboBootstrap {
             if (CollectionUtils.isEmpty(referenceConfigs)) {
                 return this;
             }
-
-            referenceConfigs.forEach(configManager::addReference);
+            for (ReferenceConfig referenceConfig : referenceConfigs) {
+                this.reference(referenceConfig);
+            }
             return this;
         }
 
@@ -1897,13 +729,12 @@ public final class DubboBootstrap {
         }
 
         public Module provider(String id, Consumer<ProviderBuilder> builderConsumer) {
-            ProviderBuilder builder = createProviderBuilder(id);
-            builderConsumer.accept(builder);
-            return provider(builder.build());
+            return provider(createProviderConfig(id, builderConsumer));
         }
 
         public Module provider(ProviderConfig providerConfig) {
-            return providers(singletonList(providerConfig));
+            DubboBootstrap.this.provider(providerConfig, moduleModel);
+            return this;
         }
 
         public Module providers(List<ProviderConfig> providerConfigs) {
@@ -1911,8 +742,7 @@ public final class DubboBootstrap {
                 return this;
             }
             for (ProviderConfig providerConfig : providerConfigs) {
-                providerConfig.setScopeModel(moduleModel);
-                configManager.addProvider(providerConfig);
+                DubboBootstrap.this.provider(providerConfig, moduleModel);
             }
             return this;
         }
@@ -1923,13 +753,12 @@ public final class DubboBootstrap {
         }
 
         public Module consumer(String id, Consumer<ConsumerBuilder> builderConsumer) {
-            ConsumerBuilder builder = createConsumerBuilder(id);
-            builderConsumer.accept(builder);
-            return consumer(builder.build());
+            return consumer(createConsumerConfig(id, builderConsumer));
         }
 
         public Module consumer(ConsumerConfig consumerConfig) {
-            return consumers(singletonList(consumerConfig));
+            DubboBootstrap.this.consumer(consumerConfig, moduleModel);
+            return this;
         }
 
         public Module consumers(List<ConsumerConfig> consumerConfigs) {
@@ -1937,10 +766,10 @@ public final class DubboBootstrap {
                 return this;
             }
             for (ConsumerConfig consumerConfig : consumerConfigs) {
-                consumerConfig.setScopeModel(moduleModel);
-                configManager.addConsumer(consumerConfig);
+                DubboBootstrap.this.consumer(consumerConfig, moduleModel);
             }
             return this;
         }
     }
+
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelPostProcessor.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/ModuleDeployListener.java
similarity index 66%
rename from dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelPostProcessor.java
rename to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/ModuleDeployListener.java
index 5a78a3f..18cc9e3 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelPostProcessor.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/bootstrap/ModuleDeployListener.java
@@ -14,21 +14,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.rpc.model;
+package org.apache.dubbo.config.bootstrap;
 
 import org.apache.dubbo.common.extension.ExtensionScope;
 import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.rpc.model.ModuleModel;
 
 /**
- * A post-processor after scope model is created (one of FrameworkModel/ApplicationModel/ModuleModel)
+ * Module deploy listener
  */
-@SPI(scope = ExtensionScope.FRAMEWORK)
-public interface ScopeModelPostProcessor {
+@SPI(scope = ExtensionScope.MODULE)
+public interface ModuleDeployListener {
 
     /**
-     * Post-process after a scope model is created.
-     * @param scopeModel
+     * Notify after module is started (export/refer services)
+     * @param moduleModel
      */
-    void postProcessScopeModel(ScopeModel scopeModel);
+    void onModuleStarted(ModuleModel moduleModel);
+
+    /**
+     * Notify after module is stopped
+     * @param moduleModel
+     */
+    void onModuleStopped(ModuleModel moduleModel);
 
 }
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
index 6c796ad..a1d30b3 100644
--- 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
@@ -26,7 +26,6 @@ import org.apache.dubbo.config.MethodConfig;
 import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.ServiceConfig;
-import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.context.ConfigManager;
 import org.apache.dubbo.metadata.MetadataService;
 import org.apache.dubbo.metadata.MetadataServiceExporter;
@@ -83,7 +82,6 @@ public class ConfigurableMetadataServiceExporter implements MetadataServiceExpor
             ApplicationConfig applicationConfig = getApplicationConfig();
             ServiceConfig<MetadataService> serviceConfig = new ServiceConfig<>();
             serviceConfig.setScopeModel(applicationModel.getInternalModule());
-            serviceConfig.setBootstrap(applicationModel.getBeanFactory().getBean(DubboBootstrap.class));
             serviceConfig.setApplication(applicationConfig);
             serviceConfig.setRegistry(new RegistryConfig("N/A"));
             serviceConfig.setProtocol(generateMetadataProtocol());
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/CompositeReferenceCache.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/CompositeReferenceCache.java
new file mode 100644
index 0000000..827dca2
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/CompositeReferenceCache.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.utils;
+
+import org.apache.dubbo.common.config.ReferenceCache;
+import org.apache.dubbo.config.ReferenceConfigBase;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.ModuleModel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A impl of ReferenceCache for Application
+ */
+public class CompositeReferenceCache implements ReferenceCache {
+    private ApplicationModel applicationModel;
+
+    public CompositeReferenceCache(ApplicationModel applicationModel) {
+        this.applicationModel = applicationModel;
+    }
+
+    @Override
+    public <T> T get(ReferenceConfigBase<T> referenceConfig) {
+        return referenceConfig.get();
+    }
+
+    @Override
+    public <T> T get(String key, Class<T> type) {
+        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
+            T proxy = moduleModel.getDeployer().getReferenceCache().get(key, type);
+            if (proxy != null) {
+                return proxy;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public <T> T get(String key) {
+        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
+            T proxy = moduleModel.getDeployer().getReferenceCache().get(key);
+            if (proxy != null) {
+                return proxy;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public <T> List<T> getAll(Class<T> type) {
+        List<T> proxies = new ArrayList<>();
+        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
+            proxies.addAll(moduleModel.getDeployer().getReferenceCache().getAll(type));
+        }
+        return proxies;
+    }
+
+    @Override
+    public <T> T get(Class<T> type) {
+        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
+            T proxy = moduleModel.getDeployer().getReferenceCache().get(type);
+            if (proxy != null) {
+                return proxy;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void destroy(String key, Class<?> type) {
+        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
+            moduleModel.getDeployer().getReferenceCache().destroy(key, type);
+        }
+    }
+
+    @Override
+    public void destroy(Class<?> type) {
+        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
+            moduleModel.getDeployer().getReferenceCache().destroy(type);
+        }
+    }
+
+    @Override
+    public <T> void destroy(ReferenceConfigBase<T> referenceConfig) {
+        referenceConfig.getScopeModel().getDeployer().getReferenceCache().destroy(referenceConfig);
+    }
+
+    @Override
+    public void destroyAll() {
+        for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
+            moduleModel.getDeployer().getReferenceCache().destroyAll();
+        }
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/DefaultConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/DefaultConfigValidator.java
new file mode 100644
index 0000000..69fdafa
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/DefaultConfigValidator.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.utils;
+
+import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ConsumerConfig;
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.MetricsConfig;
+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.SslConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+
+public class DefaultConfigValidator implements ConfigValidator {
+
+    @Override
+    public void validate(AbstractConfig config) {
+        if (config instanceof ProtocolConfig) {
+            ConfigValidationUtils.validateProtocolConfig((ProtocolConfig) config);
+        } else if (config instanceof RegistryConfig) {
+            ConfigValidationUtils.validateRegistryConfig((RegistryConfig) config);
+        } else if (config instanceof MetadataReportConfig) {
+            ConfigValidationUtils.validateMetadataConfig((MetadataReportConfig) config);
+        } else if (config instanceof ProviderConfig) {
+            ConfigValidationUtils.validateProviderConfig((ProviderConfig) config);
+        } else if (config instanceof ConsumerConfig) {
+            ConfigValidationUtils.validateConsumerConfig((ConsumerConfig) config);
+        } else if (config instanceof ApplicationConfig) {
+            ConfigValidationUtils.validateApplicationConfig((ApplicationConfig) config);
+        } else if (config instanceof MonitorConfig) {
+            ConfigValidationUtils.validateMonitorConfig((MonitorConfig) config);
+        } else if (config instanceof ModuleConfig) {
+            ConfigValidationUtils.validateModuleConfig((ModuleConfig) config);
+        } else if (config instanceof MetricsConfig) {
+            ConfigValidationUtils.validateMetricsConfig((MetricsConfig) config);
+        } else if (config instanceof SslConfig) {
+            ConfigValidationUtils.validateSslConfig((SslConfig) config);
+        }
+    }
+
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ReferenceConfigCache.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/SimpleReferenceCache.java
similarity index 55%
rename from dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ReferenceConfigCache.java
rename to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/SimpleReferenceCache.java
index f95e00f..c35a708 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ReferenceConfigCache.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/SimpleReferenceCache.java
@@ -16,10 +16,10 @@
  */
 package org.apache.dubbo.config.utils;
 
+import org.apache.dubbo.common.config.ReferenceCache;
 import org.apache.dubbo.common.utils.CollectionUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.ReferenceConfigBase;
-import org.apache.dubbo.rpc.model.ScopeModelUtil;
 import org.apache.dubbo.rpc.service.Destroyable;
 
 import java.util.ArrayList;
@@ -38,7 +38,7 @@ import java.util.concurrent.atomic.AtomicInteger;
  * <p>
  * You can implement and use your own {@link ReferenceConfigBase} cache if you need use complicate strategy.
  */
-public class ReferenceConfigCache {
+public class SimpleReferenceCache implements ReferenceCache {
     public static final String DEFAULT_NAME = "_DEFAULT_";
     /**
      * Create the key with the <b>Group</b>, <b>Interface</b> and <b>version</b> attribute of {@link ReferenceConfigBase}.
@@ -68,15 +68,15 @@ public class ReferenceConfigCache {
 
     private static final AtomicInteger nameIndex = new AtomicInteger();
 
-    static final ConcurrentMap<String, ReferenceConfigCache> CACHE_HOLDER = new ConcurrentHashMap<String, ReferenceConfigCache>();
+    static final ConcurrentMap<String, SimpleReferenceCache> CACHE_HOLDER = new ConcurrentHashMap<>();
     private final String name;
     private final KeyGenerator generator;
 
-    private final ConcurrentMap<String, ReferenceConfigBase<?>> referredReferences = new ConcurrentHashMap<>();
+    private final Map<String, List<ReferenceConfigBase<?>>> referenceKeyMap = new ConcurrentHashMap<>();
+    private final Map<Class<?>, List<ReferenceConfigBase<?>>> referenceTypeMap = new ConcurrentHashMap<>();
+    private final Map<ReferenceConfigBase<?>, Object> references = new ConcurrentHashMap<>();
 
-    private final ConcurrentMap<Class<?>, ConcurrentMap<String, Object>> proxies = new ConcurrentHashMap<>();
-
-    private ReferenceConfigCache(String name, KeyGenerator generator) {
+    protected SimpleReferenceCache(String name, KeyGenerator generator) {
         this.name = name;
         this.generator = generator;
     }
@@ -85,11 +85,11 @@ public class ReferenceConfigCache {
      * Get the cache use default name and {@link #DEFAULT_KEY_GENERATOR} to generate cache key.
      * Create cache if not existed yet.
      */
-    public static ReferenceConfigCache getCache() {
+    public static SimpleReferenceCache getCache() {
         return getCache(DEFAULT_NAME);
     }
 
-    public static ReferenceConfigCache newCache() {
+    public static SimpleReferenceCache newCache() {
         return getCache(DEFAULT_NAME + "#" + nameIndex.incrementAndGet());
     }
 
@@ -97,7 +97,7 @@ public class ReferenceConfigCache {
      * Get the cache use specified name and {@link KeyGenerator}.
      * Create cache if not existed yet.
      */
-    public static ReferenceConfigCache getCache(String name) {
+    public static SimpleReferenceCache getCache(String name) {
         return getCache(name, DEFAULT_KEY_GENERATOR);
     }
 
@@ -105,22 +105,26 @@ public class ReferenceConfigCache {
      * Get the cache use specified {@link KeyGenerator}.
      * Create cache if not existed yet.
      */
-    public static ReferenceConfigCache getCache(String name, KeyGenerator keyGenerator) {
-        return CACHE_HOLDER.computeIfAbsent(name, k -> new ReferenceConfigCache(k, keyGenerator));
+    public static SimpleReferenceCache getCache(String name, KeyGenerator keyGenerator) {
+        return CACHE_HOLDER.computeIfAbsent(name, k -> new SimpleReferenceCache(k, keyGenerator));
     }
 
+    @Override
     @SuppressWarnings("unchecked")
-    public <T> T get(ReferenceConfigBase<T> referenceConfig) {
-        String key = generator.generateKey(referenceConfig);
-        Class<?> type = referenceConfig.getInterfaceClass();
-
-        ConcurrentMap<String, Object> proxiesOfType = proxies.computeIfAbsent(type, _t -> new ConcurrentHashMap<>());
-
-        return (T) proxiesOfType.computeIfAbsent(key, _k -> {
-            Object proxy = referenceConfig.get();
-            referredReferences.put(key, referenceConfig);
+    public <T> T get(ReferenceConfigBase<T> rc) {
+        String key = generator.generateKey(rc);
+        Class<?> type = rc.getInterfaceClass();
+        Object proxy = rc.get();
+
+        references.computeIfAbsent(rc, _rc -> {
+            List<ReferenceConfigBase<?>> referencesOfType = referenceTypeMap.computeIfAbsent(type, _t -> Collections.synchronizedList(new ArrayList<>()));
+            referencesOfType.add(rc);
+            List<ReferenceConfigBase<?>> referenceConfigList = referenceKeyMap.computeIfAbsent(key, _k -> Collections.synchronizedList(new ArrayList<>()));
+            referenceConfigList.add(rc);
             return proxy;
         });
+
+        return (T) proxy;
     }
 
     /**
@@ -133,71 +137,75 @@ public class ReferenceConfigCache {
      * @return object from the cached ReferenceConfigBase
      * @see KeyGenerator#generateKey(ReferenceConfigBase)
      */
+    @Override
     @SuppressWarnings("unchecked")
     public <T> T get(String key, Class<T> type) {
-        Map<String, Object> proxiesOfType = proxies.get(type);
-        if (CollectionUtils.isEmptyMap(proxiesOfType)) {
-            return null;
+        List<ReferenceConfigBase<?>> referenceConfigs = referenceKeyMap.get(key);
+        if (referenceConfigs != null && referenceConfigs.size() > 0) {
+            return (T) referenceConfigs.get(0).get();
         }
-        return (T) proxiesOfType.get(key);
+        return null;
     }
 
+    @Override
     @SuppressWarnings("unchecked")
     public <T> T get(String key) {
-        ReferenceConfigBase<?> rc = referredReferences.get(key);
-        if (rc == null) {
-            return null;
+        List<ReferenceConfigBase<?>> referenceConfigs = referenceKeyMap.get(key);
+        if (referenceConfigs != null && referenceConfigs.size() > 0) {
+            return (T) referenceConfigs.get(0).get();
         }
-
-        return (T) get(key, rc.getInterfaceClass());
+        return null;
     }
 
+    @Override
     @SuppressWarnings("unchecked")
     public <T> List<T> getAll(Class<T> type) {
-        Map<String, Object> proxiesOfType = proxies.get(type);
-        if (CollectionUtils.isEmptyMap(proxiesOfType)) {
-            return Collections.emptyList();
+        List<ReferenceConfigBase<?>> referenceConfigBases = referenceTypeMap.get(type);
+        if (CollectionUtils.isEmpty(referenceConfigBases)) {
+            return Collections.EMPTY_LIST;
         }
-
-        List<T> proxySet = new ArrayList<>();
-        proxiesOfType.values().forEach(obj -> proxySet.add((T) obj));
-        return proxySet;
+        List proxiesOfType = new ArrayList(referenceConfigBases.size());
+        for (ReferenceConfigBase<?> rc : referenceConfigBases) {
+            proxiesOfType.add(rc.get());
+        }
+        return Collections.unmodifiableList(proxiesOfType);
     }
 
+    @Override
     @SuppressWarnings("unchecked")
     public <T> T get(Class<T> type) {
-        Map<String, Object> proxiesOfType = proxies.get(type);
-        if (CollectionUtils.isEmptyMap(proxiesOfType)) {
-            return null;
+        List<ReferenceConfigBase<?>> referenceConfigBases = referenceTypeMap.get(type);
+        if (referenceConfigBases != null && referenceConfigBases.size() > 0) {
+            return (T) referenceConfigBases.get(0).get();
         }
-
-        return (T) proxiesOfType.values().iterator().next();
+        return null;
     }
 
+    @Override
     public void destroy(String key, Class<?> type) {
-        ReferenceConfigBase<?> rc = referredReferences.remove(key);
-        if (rc == null) {
+        List<ReferenceConfigBase<?>> referencesOfKey = referenceKeyMap.remove(key);
+        if (CollectionUtils.isEmpty(referencesOfKey)) {
             return;
         }
-
-        ScopeModelUtil.getApplicationModel(rc.getScopeModel()).getApplicationConfigManager().removeConfig(rc);
-        rc.destroy();
-
-        Map<String, Object> proxiesOftype = proxies.get(type);
-        if (CollectionUtils.isNotEmptyMap(proxiesOftype)) {
-            proxiesOftype.remove(key);
-            if (proxiesOftype.isEmpty()) {
-                proxies.remove(type);
-            }
+        List<ReferenceConfigBase<?>> referencesOfType = referenceTypeMap.get(type);
+        if (CollectionUtils.isEmpty(referencesOfType)) {
+            return;
         }
+        for (ReferenceConfigBase<?> rc : referencesOfKey) {
+            referencesOfType.remove(rc);
+            destroyReference(rc);
+        }
+
     }
 
+    @Override
     public void destroy(Class<?> type) {
-        Map<String, Object> proxiesOfType = proxies.remove(type);
-        proxiesOfType.forEach((k, v) -> {
-            ReferenceConfigBase rc = referredReferences.remove(k);
-            rc.destroy();
-        });
+        List<ReferenceConfigBase<?>> referencesOfType = referenceTypeMap.remove(type);
+        for (ReferenceConfigBase<?> rc : referencesOfType) {
+            String key = generator.generateKey(rc);
+            referenceKeyMap.remove(key);
+            destroyReference(rc);
+        }
     }
 
     /**
@@ -205,49 +213,49 @@ public class ReferenceConfigCache {
      *
      * @param referenceConfig use for create key.
      */
+    @Override
     public <T> void destroy(ReferenceConfigBase<T> referenceConfig) {
         String key = generator.generateKey(referenceConfig);
         Class<?> type = referenceConfig.getInterfaceClass();
-
         destroy(key, type);
     }
 
     /**
      * clear and destroy all {@link ReferenceConfigBase} in the cache.
      */
+    @Override
     public void destroyAll() {
-        if (CollectionUtils.isEmptyMap(referredReferences)) {
+        if (CollectionUtils.isEmptyMap(referenceKeyMap)) {
             return;
         }
 
-        referredReferences.forEach((_k, referenceConfig) -> {
-            referenceConfig.destroy();
-            ScopeModelUtil.getApplicationModel(referenceConfig.getScopeModel()).getApplicationConfigManager().removeConfig(referenceConfig);
+        referenceKeyMap.forEach((_k, referencesOfKey) -> {
+            for (ReferenceConfigBase<?> rc : referencesOfKey) {
+                destroyReference(rc);
+            }
         });
 
-        proxies.forEach((_type, proxiesOfType) -> {
-            proxiesOfType.forEach((_k, v) -> {
-                Destroyable proxy = (Destroyable) v;
-                proxy.$destroy();
-            });
-        });
+        referenceKeyMap.clear();
+        referenceTypeMap.clear();
+    }
 
-        referredReferences.clear();
-        proxies.clear();
+    private void destroyReference(ReferenceConfigBase<?> rc) {
+        Destroyable proxy = (Destroyable) rc.get();
+        proxy.$destroy();
+        rc.destroy();
     }
 
-    public ConcurrentMap<String, ReferenceConfigBase<?>> getReferredReferences() {
-        return referredReferences;
+    public Map<String, List<ReferenceConfigBase<?>>> getReferenceMap() {
+        return referenceKeyMap;
     }
 
-    public ConcurrentMap<Class<?>, ConcurrentMap<String, Object>> getProxies() {
-        return proxies;
+    public Map<Class<?>, List<ReferenceConfigBase<?>>> getReferenceTypeMap() {
+        return referenceTypeMap;
     }
 
     @Override
     public String toString() {
-        return "ReferenceConfigCache(name: " + name
-            + ")";
+        return "ReferenceCache(name: " + name + ")";
     }
 
     public interface KeyGenerator {
diff --git a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer
new file mode 100644
index 0000000..3122307
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer
@@ -0,0 +1 @@
+dubbo-config-api=org.apache.dubbo.config.ConfigScopeModelInitializer
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
index 7f03914..4cb8d97 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
@@ -22,7 +22,6 @@ import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.support.Parameter;
 import org.apache.dubbo.config.utils.ConfigValidationUtils;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.hamcrest.Matchers;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigCenterConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigCenterConfigTest.java
index 92a7282..d563351 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigCenterConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigCenterConfigTest.java
@@ -21,7 +21,6 @@ package org.apache.dubbo.config;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java
index 2e06f0d..3e68025 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java
@@ -20,7 +20,6 @@ package org.apache.dubbo.config;
 import org.apache.dubbo.config.api.DemoService;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
@@ -117,7 +116,7 @@ public class ConsumerConfigTest {
                     .consumer(consumerConfig)
                     .initialize();
 
-            Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel().getApplicationConfigManager().getConsumers();
+            Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel().getDefaultModule().getConfigManager().getConsumers();
             Assertions.assertEquals(1, consumers.size());
             Assertions.assertEquals(consumerConfig, consumers.iterator().next());
             Assertions.assertEquals(false, consumerConfig.isCheck());
@@ -147,7 +146,7 @@ public class ConsumerConfigTest {
                     .consumer(consumerConfig)
                     .initialize();
 
-            Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel().getApplicationConfigManager().getConsumers();
+            Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel().getDefaultModule().getConfigManager().getConsumers();
             Assertions.assertEquals(1, consumers.size());
             Assertions.assertEquals(consumerConfig, consumers.iterator().next());
             Assertions.assertEquals(false, consumerConfig.isCheck());
@@ -180,7 +179,7 @@ public class ConsumerConfigTest {
                     .consumer(consumerConfig)
                     .initialize();
 
-            Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel().getApplicationConfigManager().getConsumers();
+            Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel().getDefaultModule().getConfigManager().getConsumers();
             Assertions.assertEquals(1, consumers.size());
             Assertions.assertEquals(consumerConfig, consumers.iterator().next());
             Assertions.assertEquals(true, consumerConfig.isCheck());
@@ -209,7 +208,7 @@ public class ConsumerConfigTest {
                     .consumer(consumerConfig)
                     .initialize();
 
-            Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel().getApplicationConfigManager().getConsumers();
+            Collection<ConsumerConfig> consumers = ApplicationModel.defaultModel().getDefaultModule().getConfigManager().getConsumers();
             Assertions.assertEquals(1, consumers.size());
             Assertions.assertEquals(consumerConfig, consumers.iterator().next());
             Assertions.assertEquals(false, consumerConfig.isCheck());
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
index 576b396..f75aa8a 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
@@ -16,6 +16,13 @@
  */
 package org.apache.dubbo.config;
 
+import demo.MultiClassLoaderService;
+import demo.MultiClassLoaderServiceImpl;
+import demo.MultiClassLoaderServiceRequest;
+import demo.MultiClassLoaderServiceResult;
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.NotFoundException;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.Version;
 import org.apache.dubbo.common.compiler.support.CtClassBuilder;
@@ -29,6 +36,7 @@ import org.apache.dubbo.config.annotation.Method;
 import org.apache.dubbo.config.annotation.Reference;
 import org.apache.dubbo.config.api.DemoService;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.config.context.ModuleConfigManager;
 import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
 import org.apache.dubbo.registry.client.migration.MigrationInvoker;
 import org.apache.dubbo.registrycenter.RegistryCenter;
@@ -43,14 +51,6 @@ import org.apache.dubbo.rpc.model.ModuleModel;
 import org.apache.dubbo.rpc.model.ServiceMetadata;
 import org.apache.dubbo.rpc.protocol.injvm.InjvmInvoker;
 import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;
-
-import demo.MultiClassLoaderService;
-import demo.MultiClassLoaderServiceImpl;
-import demo.MultiClassLoaderServiceRequest;
-import demo.MultiClassLoaderServiceResult;
-import javassist.CannotCompileException;
-import javassist.CtClass;
-import javassist.NotFoundException;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
@@ -62,6 +62,7 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -69,7 +70,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.ArrayList;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
@@ -774,6 +774,8 @@ public class ReferenceConfigTest {
     @Test
     public void testLargeReferences() throws InterruptedException {
         int amount = 10000;
+        ModuleConfigManager configManager = DubboBootstrap.getInstance().getApplicationModel().getDefaultModule().getConfigManager();
+
         ApplicationConfig applicationConfig = new ApplicationConfig();
         applicationConfig.setName("test-app");
         MetadataReportConfig metadataReportConfig = new MetadataReportConfig();
@@ -782,9 +784,9 @@ public class ReferenceConfigTest {
         configCenterConfig.setAddress("diamond://");
 
         testInitReferences(0, amount, applicationConfig, metadataReportConfig, configCenterConfig);
-        ApplicationModel.defaultModel().getApplicationConfigManager().clear();
+        configManager.clear();
         testInitReferences(0, 1, applicationConfig, metadataReportConfig, configCenterConfig);
-        ApplicationModel.defaultModel().getApplicationConfigManager().clear();
+        configManager.clear();
 
         long t1 = System.currentTimeMillis();
         int nThreads = 8;
@@ -808,7 +810,7 @@ public class ReferenceConfigTest {
         long t2 = System.currentTimeMillis();
         long cost = t2 - t1;
         System.out.println("Init large references cost: " + cost + "ms");
-        Assertions.assertEquals(amount, DubboBootstrap.getInstance().getConfigManager().getReferences().size());
+        Assertions.assertEquals(amount, configManager.getReferences().size());
         Assertions.assertTrue(cost < 1000, "Init large references too slowly: " + cost);
 
         //test equals
@@ -818,7 +820,7 @@ public class ReferenceConfigTest {
 
     private void testSearchReferences() {
         long t1 = System.currentTimeMillis();
-        Collection<ReferenceConfigBase<?>> references = DubboBootstrap.getInstance().getConfigManager().getReferences();
+        Collection<ReferenceConfigBase<?>> references = DubboBootstrap.getInstance().getApplicationModel().getDefaultModule().getConfigManager().getReferences();
         List<ReferenceConfigBase<?>> results = references.stream().filter(rc -> rc.equals(references.iterator().next()))
             .collect(Collectors.toList());
         long t2 = System.currentTimeMillis();
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapMultiInstanceTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapMultiInstanceTest.java
index a96e0f5..6fa0d00 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapMultiInstanceTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapMultiInstanceTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.dubbo.config.bootstrap;
 
+import org.apache.dubbo.common.deploy.ModuleDeployer;
 import org.apache.dubbo.common.utils.NetUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.ProtocolConfig;
@@ -24,11 +25,14 @@ import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.ServiceConfig;
 import org.apache.dubbo.config.SysProps;
 import org.apache.dubbo.config.api.DemoService;
+import org.apache.dubbo.config.api.Greeting;
+import org.apache.dubbo.config.mock.GreetingLocal2;
 import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
 import org.apache.dubbo.registrycenter.RegistryCenter;
 import org.apache.dubbo.registrycenter.ZookeeperSingleRegistryCenter;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.FrameworkServiceRepository;
 import org.apache.dubbo.rpc.model.ModuleModel;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
@@ -70,8 +74,8 @@ public class DubboBootstrapMultiInstanceTest {
     @Test
     public void testIsolatedApplications() {
 
-        DubboBootstrap dubboBootstrap1 = DubboBootstrap.newInstance();
-        DubboBootstrap dubboBootstrap2 = DubboBootstrap.newInstance();
+        DubboBootstrap dubboBootstrap1 = DubboBootstrap.newInstance(new FrameworkModel());
+        DubboBootstrap dubboBootstrap2 = DubboBootstrap.newInstance(new FrameworkModel());
         try {
             ApplicationModel applicationModel1 = dubboBootstrap1.getApplicationModel();
             ApplicationModel applicationModel2 = dubboBootstrap2.getApplicationModel();
@@ -160,6 +164,7 @@ public class DubboBootstrapMultiInstanceTest {
 
         String version1 = "1.0";
         String version2 = "2.0";
+        String version3 = "3.0";
 
         DubboBootstrap providerBootstrap = null;
         DubboBootstrap consumerBootstrap = null;
@@ -178,23 +183,31 @@ public class DubboBootstrapMultiInstanceTest {
             serviceConfig2.setRef(new DemoServiceImpl());
             serviceConfig2.setVersion(version2);
 
+            ServiceConfig serviceConfig3 = new ServiceConfig();
+            serviceConfig3.setInterface(DemoService.class);
+            serviceConfig3.setRef(new DemoServiceImpl());
+            serviceConfig3.setVersion(version3);
+
             providerBootstrap
                 .application("provider-app")
                 .registry(registryConfig)
-                .protocol(new ProtocolConfig("dubbo", 2002))
-                .addModule()
+                .protocol(new ProtocolConfig("dubbo", -1))
                 .service(serviceConfig1)
-                .endModule()
-                .addModule()
+                .newModule()
                 .service(serviceConfig2)
+                .endModule()
+                .newModule()
+                .service(serviceConfig3)
                 .endModule();
 
             ApplicationModel applicationModel = providerBootstrap.getApplicationModel();
             List<ModuleModel> moduleModels = applicationModel.getModuleModels();
-            Assertions.assertEquals(3, moduleModels.size());
+            Assertions.assertEquals(4, moduleModels.size());
             Assertions.assertSame(moduleModels.get(0), applicationModel.getInternalModule());
-            Assertions.assertSame(moduleModels.get(1), serviceConfig1.getScopeModel());
+            Assertions.assertSame(moduleModels.get(1), applicationModel.getDefaultModule());
+            Assertions.assertSame(applicationModel.getDefaultModule(), serviceConfig1.getScopeModel());
             Assertions.assertSame(moduleModels.get(2), serviceConfig2.getScopeModel());
+            Assertions.assertSame(moduleModels.get(3), serviceConfig3.getScopeModel());
             Assertions.assertNotSame(applicationModel.getDefaultModule(), applicationModel.getInternalModule());
 
             providerBootstrap.start();
@@ -208,7 +221,7 @@ public class DubboBootstrapMultiInstanceTest {
                     .interfaceClass(DemoService.class)
                     .version(version1)
                     .injvm(false))
-                .addModule()
+                .newModule()
                 .reference(builder -> builder
                     .interfaceClass(DemoService.class)
                     .version(version2)
@@ -232,6 +245,149 @@ public class DubboBootstrapMultiInstanceTest {
 
     }
 
+    @Test
+    public void testMultiModuleDeployAndReload() throws Exception {
+
+        String version1 = "1.0";
+        String version2 = "2.0";
+        String version3 = "3.0";
+
+        String serviceKey1 = DemoService.class.getName() + ":" + version1;
+        String serviceKey2 = DemoService.class.getName() + ":" + version2;
+        String serviceKey3 = DemoService.class.getName() + ":" + version3;
+
+        DubboBootstrap providerBootstrap = null;
+        DubboBootstrap consumerBootstrap = null;
+
+        try {
+            // provider app
+            providerBootstrap = DubboBootstrap.newInstance();
+
+            ServiceConfig serviceConfig1 = new ServiceConfig();
+            serviceConfig1.setInterface(DemoService.class);
+            serviceConfig1.setRef(new DemoServiceImpl());
+            serviceConfig1.setVersion(version1);
+
+            //provider module 1
+            providerBootstrap
+                .application("provider-app")
+                .registry(registryConfig)
+                .protocol(new ProtocolConfig("dubbo", -1))
+                .service(builder -> builder
+                    .interfaceClass(Greeting.class)
+                    .ref(new GreetingLocal2()))
+                .newModule()
+                .service(serviceConfig1)
+                .endModule();
+
+            ApplicationModel applicationModel = providerBootstrap.getApplicationModel();
+            List<ModuleModel> moduleModels = applicationModel.getModuleModels();
+            Assertions.assertEquals(3, moduleModels.size());
+            Assertions.assertSame(moduleModels.get(0), applicationModel.getInternalModule());
+            Assertions.assertSame(moduleModels.get(1), applicationModel.getDefaultModule());
+            Assertions.assertSame(moduleModels.get(2), serviceConfig1.getScopeModel());
+
+            ModuleDeployer moduleDeployer1 = serviceConfig1.getScopeModel().getDeployer();
+            moduleDeployer1.start().get();
+            Assertions.assertTrue(moduleDeployer1.isStartup());
+            ModuleDeployer internalModuleDeployer = applicationModel.getInternalModule().getDeployer();
+            Assertions.assertTrue(internalModuleDeployer.isStartup());
+
+            FrameworkServiceRepository frameworkServiceRepository = applicationModel.getFrameworkModel().getServiceRepository();
+            Assertions.assertNotNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey1));
+            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey2));
+            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey3));
+
+            // consumer module 1
+            consumerBootstrap = DubboBootstrap.newInstance();
+            consumerBootstrap.application("consumer-app")
+                .registry(registryConfig)
+                .reference(builder -> builder
+                    .interfaceClass(DemoService.class)
+                    .version(version1)
+                    .injvm(false));
+            consumerBootstrap.start();
+
+            DemoService referProxy1 = consumerBootstrap.getCache().get(serviceKey1);
+            String result1 = referProxy1.sayName("dubbo");
+            Assertions.assertEquals("say:dubbo", result1);
+
+            // destroy provider module 1
+            serviceConfig1.getScopeModel().destroy();
+
+            // provider module 2
+            ServiceConfig serviceConfig2 = new ServiceConfig();
+            serviceConfig2.setInterface(DemoService.class);
+            serviceConfig2.setRef(new DemoServiceImpl());
+            serviceConfig2.setVersion(version2);
+
+            providerBootstrap.newModule()
+                .service(serviceConfig2)
+                .endModule();
+
+            serviceConfig2.getScopeModel().getDeployer().start();
+            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey1));
+            Assertions.assertNotNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey2));
+            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey3));
+
+            // consumer module2
+            ModuleModel consumerModule2 = consumerBootstrap.newModule()
+                .reference(builder -> builder
+                    .interfaceClass(DemoService.class)
+                    .version(version2)
+                    .injvm(false))
+                .getModuleModel();
+
+            ModuleDeployer moduleDeployer2 = consumerModule2.getDeployer();
+            moduleDeployer2.start().get();
+
+            DemoService referProxy2 = moduleDeployer2.getReferenceCache().get(serviceKey2);
+            String result2 = referProxy2.sayName("dubbo2");
+            Assertions.assertEquals("say:dubbo2", result2);
+
+            // destroy provider module 2
+            serviceConfig2.getScopeModel().destroy();
+
+            // provider module 3
+            ServiceConfig serviceConfig3 = new ServiceConfig();
+            serviceConfig3.setInterface(DemoService.class);
+            serviceConfig3.setRef(new DemoServiceImpl());
+            serviceConfig3.setVersion(version3);
+
+            providerBootstrap.newModule()
+                .service(serviceConfig3)
+                .endModule();
+
+            serviceConfig3.getScopeModel().getDeployer().start().get();
+            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey1));
+            Assertions.assertNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey2));
+            Assertions.assertNotNull(frameworkServiceRepository.lookupExportedServiceWithoutGroup(serviceKey3));
+
+            // consumer module3
+            ModuleModel consumerModule3 = consumerBootstrap.newModule()
+                .reference(builder -> builder
+                    .interfaceClass(DemoService.class)
+                    .version(version3)
+                    .injvm(false))
+                .getModuleModel();
+
+            consumerBootstrap.start();
+
+            DemoService referProxy3 = consumerModule3.getDeployer().getReferenceCache().get(serviceKey3);
+            String result3 = referProxy3.sayName("dubbo3");
+            Assertions.assertEquals("say:dubbo3", result3);
+
+        } finally {
+            if (providerBootstrap != null) {
+                providerBootstrap.destroy();
+            }
+            if (consumerBootstrap != null) {
+                consumerBootstrap.destroy();
+            }
+        }
+    }
+
+
     private DubboBootstrap configConsumerApp(DubboBootstrap dubboBootstrap) {
         ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<>();
         referenceConfig.setInterface(DemoService.class);
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
index 0abaa22..b1c1b03 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.dubbo.config.bootstrap;
 
+import org.apache.curator.test.TestingServer;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.common.url.component.ServiceConfigURL;
@@ -39,8 +40,6 @@ import org.apache.dubbo.registry.RegistryService;
 import org.apache.dubbo.rpc.Exporter;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;
-
-import org.apache.curator.test.TestingServer;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
@@ -153,7 +152,7 @@ public class DubboBootstrapTest {
 
         // load configs from props
         DubboBootstrap.getInstance()
-                .initialize();
+            .initialize();
 
         serviceConfig.refresh();
 
@@ -258,9 +257,15 @@ public class DubboBootstrapTest {
         Assertions.assertTrue(bootstrap.isStarted());
         Assertions.assertFalse(bootstrap.isShutdown());
 
-        Assertions.assertNotNull(bootstrap.serviceInstance);
-        Assertions.assertTrue(bootstrap.exportedServices.size() > 0);
-        Assertions.assertNotNull(bootstrap.asyncMetadataFuture);
+        ApplicationModel applicationModel = bootstrap.getApplicationModel();
+        DefaultApplicationDeployer applicationDeployer = getApplicationDeployer(applicationModel);
+        Assertions.assertNotNull(applicationDeployer.serviceInstance);
+        Assertions.assertNotNull(applicationDeployer.asyncMetadataFuture);
+        Assertions.assertTrue(applicationModel.getDefaultModule().getServiceRepository().getExportedServices().size() > 0);
+    }
+
+    private DefaultApplicationDeployer getApplicationDeployer(ApplicationModel applicationModel) {
+        return (DefaultApplicationDeployer) DefaultApplicationDeployer.get(applicationModel);
     }
 
     @Test
@@ -327,7 +332,8 @@ public class DubboBootstrapTest {
     }
 
     private void assertMetadataService(DubboBootstrap bootstrap, int availablePort, boolean shouldReport) {
-        Assertions.assertTrue(bootstrap.metadataServiceExporter.isExported());
+        DefaultApplicationDeployer applicationDeployer = getApplicationDeployer(bootstrap.getApplicationModel());
+        Assertions.assertTrue(applicationDeployer.metadataServiceExporter.isExported());
         DubboProtocol protocol = DubboProtocol.getDubboProtocol(bootstrap.getApplicationModel());
         Map<String, Exporter<?>> exporters = protocol.getExporterMap();
         Assertions.assertEquals(2, exporters.size());
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ServiceInstanceHostPortCustomizerTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ServiceInstanceHostPortCustomizerTest.java
index 1dab33e..17da2f4 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ServiceInstanceHostPortCustomizerTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ServiceInstanceHostPortCustomizerTest.java
@@ -23,7 +23,6 @@ import org.apache.dubbo.registry.client.DefaultServiceInstance;
 import org.apache.dubbo.registry.client.ServiceInstance;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
-
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/MockReferenceConfig.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/MockReferenceConfig.java
index 464356f..f6d0967 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/MockReferenceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/MockReferenceConfig.java
@@ -54,6 +54,7 @@ public class MockReferenceConfig extends ReferenceConfig<FooService> {
 
     @Override
     public synchronized void destroy() {
+        super.destroy();
         destroyMethodRun = true;
     }
 }
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ReferenceConfigCacheTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ReferenceCacheTest.java
similarity index 84%
rename from dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ReferenceConfigCacheTest.java
rename to dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ReferenceCacheTest.java
index 6797e60..2a74228 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ReferenceConfigCacheTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ReferenceCacheTest.java
@@ -16,30 +16,29 @@
  */
 package org.apache.dubbo.config.utils;
 
+import org.apache.dubbo.common.config.ReferenceCache;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.utils.service.FooService;
-
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class ReferenceConfigCacheTest {
+public class ReferenceCacheTest {
 
     @BeforeEach
     public void setUp() throws Exception {
         DubboBootstrap.reset();
         MockReferenceConfig.setCounter(0);
-        ReferenceConfigCache.CACHE_HOLDER.clear();
+        SimpleReferenceCache.CACHE_HOLDER.clear();
     }
 
     @Test
     public void testGetCacheSameReference() throws Exception {
-        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
+        ReferenceCache cache = SimpleReferenceCache.getCache();
         MockReferenceConfig config = buildMockReferenceConfig("org.apache.dubbo.config.utils.service.FooService", "group1", "1.0.0");
         assertEquals(0L, config.getCounter());
         cache.get(config);
@@ -48,15 +47,15 @@ public class ReferenceConfigCacheTest {
         MockReferenceConfig configCopy = buildMockReferenceConfig("org.apache.dubbo.config.utils.service.FooService", "group1", "1.0.0");
         assertEquals(1L, configCopy.getCounter());
         cache.get(configCopy);
-        assertFalse(configCopy.isGetMethodRun());
+        assertTrue(configCopy.isGetMethodRun());
 
-        assertEquals(1L, config.getCounter());
-        assertEquals(1L, configCopy.getCounter());
+        assertEquals(2L, config.getCounter());
+        assertEquals(2L, configCopy.getCounter());
     }
 
     @Test
     public void testGetCacheDiffReference() throws Exception {
-        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
+        ReferenceCache cache = SimpleReferenceCache.getCache();
         MockReferenceConfig config = buildMockReferenceConfig("org.apache.dubbo.config.utils.service.FooService", "group1", "1.0.0");
         assertEquals(0L, config.getCounter());
         cache.get(config);
@@ -74,7 +73,7 @@ public class ReferenceConfigCacheTest {
 
     @Test
     public void testGetCacheWithKey() throws Exception {
-        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
+        ReferenceCache cache = SimpleReferenceCache.getCache();
         MockReferenceConfig config = buildMockReferenceConfig("org.apache.dubbo.config.utils.service.FooService", "group1", "1.0.0");
         FooService value = cache.get(config);
         assertEquals(value, cache.get("group1/org.apache.dubbo.config.utils.service.FooService:1.0.0", FooService.class));
@@ -82,14 +81,14 @@ public class ReferenceConfigCacheTest {
 
 //    @Test
 //    public void testGetCacheDiffName() throws Exception {
-//        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
+//        ReferenceCache cache = ReferenceCache.getCache();
 //        MockReferenceConfig config = buildMockReferenceConfig("org.apache.dubbo.config.utils.service.FooService", "group1", "1.0.0");
 //        assertEquals(0L, config.getCounter());
 //        cache.get(config);
 //        assertTrue(config.isGetMethodRun());
 //        assertEquals(1L, config.getCounter());
 //
-//        cache = ReferenceConfigCache.getCache("foo");
+//        cache = ReferenceCache.getCache("foo");
 //        config = buildMockReferenceConfig("org.apache.dubbo.config.utils.service.FooService", "group1", "1.0.0");
 //        assertEquals(1L, config.getCounter());
 //        cache.get(config);
@@ -100,32 +99,32 @@ public class ReferenceConfigCacheTest {
 
     @Test
     public void testDestroy() throws Exception {
-        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
+        SimpleReferenceCache cache = SimpleReferenceCache.getCache();
         MockReferenceConfig config = buildMockReferenceConfig("org.apache.dubbo.config.utils.service.FooService", "group1", "1.0.0");
         cache.get(config);
         XxxMockReferenceConfig configCopy = buildXxxMockReferenceConfig("org.apache.dubbo.config.utils.service.XxxService", "group1", "1.0.0");
         cache.get(configCopy);
-        assertEquals(2, cache.getReferredReferences().size());
+        assertEquals(2, cache.getReferenceMap().size());
         cache.destroy(config);
         assertTrue(config.isDestroyMethodRun());
-        assertEquals(1, cache.getReferredReferences().size());
+        assertEquals(1, cache.getReferenceMap().size());
         cache.destroy(configCopy);
         assertTrue(configCopy.isDestroyMethodRun());
-        assertEquals(0, cache.getReferredReferences().size());
+        assertEquals(0, cache.getReferenceMap().size());
     }
 
     @Test
     public void testDestroyAll() throws Exception {
-        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
+        SimpleReferenceCache cache = SimpleReferenceCache.getCache();
         MockReferenceConfig config = buildMockReferenceConfig("org.apache.dubbo.config.utils.service.FooService", "group1", "1.0.0");
         cache.get(config);
         XxxMockReferenceConfig configCopy = buildXxxMockReferenceConfig("org.apache.dubbo.config.utils.service.XxxService", "group1", "1.0.0");
         cache.get(configCopy);
-        assertEquals(2, cache.getReferredReferences().size());
+        assertEquals(2, cache.getReferenceMap().size());
         cache.destroyAll();
         assertTrue(config.isDestroyMethodRun());
         assertTrue(configCopy.isDestroyMethodRun());
-        assertEquals(0, cache.getReferredReferences().size());
+        assertEquals(0, cache.getReferenceMap().size());
     }
 
     private MockReferenceConfig buildMockReferenceConfig(String service, String group, String version) {
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/XxxMockReferenceConfig.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/XxxMockReferenceConfig.java
index 56667b6..fbddd6d 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/XxxMockReferenceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/XxxMockReferenceConfig.java
@@ -54,6 +54,7 @@ public class XxxMockReferenceConfig extends ReferenceConfig<XxxService> {
 
     @Override
     public synchronized void destroy() {
+        super.destroy();
         destroyMethodRun = true;
     }
 }
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderIntegrationTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderIntegrationTest.java
index 322d6da..7b80c23 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderIntegrationTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderIntegrationTest.java
@@ -35,7 +35,6 @@ import org.apache.dubbo.registrycenter.ZookeeperMultipleRegistryCenter;
 import org.apache.dubbo.rpc.ExporterListener;
 import org.apache.dubbo.rpc.Filter;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
@@ -173,7 +172,6 @@ public class MultipleRegistryCenterExportProviderIntegrationTest implements Inte
         afterExport();
         ReferenceConfig<MultipleRegistryCenterExportProviderService> referenceConfig = new ReferenceConfig<>();
         referenceConfig.setInterface(MultipleRegistryCenterExportProviderService.class);
-        referenceConfig.setBootstrap(DubboBootstrap.getInstance());
         referenceConfig.get().hello(PROVIDER_APPLICATION_NAME);
         afterInvoke();
     }
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmIntegrationTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmIntegrationTest.java
index b67c65b..0c7cf66 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmIntegrationTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/injvm/MultipleRegistryCenterInjvmIntegrationTest.java
@@ -17,12 +17,12 @@
 package org.apache.dubbo.integration.multiple.injvm;
 
 import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.config.ServiceConfig;
-import org.apache.dubbo.config.ReferenceConfig;
-import org.apache.dubbo.config.ServiceListener;
 import org.apache.dubbo.config.ApplicationConfig;
-import org.apache.dubbo.config.RegistryConfig;
 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.ServiceListener;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.integration.IntegrationTest;
 import org.apache.dubbo.registrycenter.RegistryCenter;
@@ -145,7 +145,6 @@ public class MultipleRegistryCenterInjvmIntegrationTest implements IntegrationTe
         afterExport();
         ReferenceConfig<MultipleRegistryCenterInjvmService> referenceConfig = new ReferenceConfig<>();
         referenceConfig.setInterface(MultipleRegistryCenterInjvmService.class);
-        referenceConfig.setBootstrap(DubboBootstrap.getInstance());
         referenceConfig.setScope(SCOPE_LOCAL);
         referenceConfig.get().hello("Dubbo in multiple registry center");
         afterInvoke();
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest.java
index acb4aa0..fed2bae 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/multiple/servicediscoveryregistry/MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest.java
@@ -18,11 +18,11 @@ package org.apache.dubbo.integration.multiple.servicediscoveryregistry;
 
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.config.RegistryConfig;
-import org.apache.dubbo.config.ServiceConfig;
-import org.apache.dubbo.config.ReferenceConfig;
 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.bootstrap.DubboBootstrap;
 import org.apache.dubbo.integration.IntegrationTest;
 import org.apache.dubbo.registry.RegistryServiceListener;
@@ -156,7 +156,6 @@ public class MultipleRegistryCenterServiceDiscoveryRegistryIntegrationTest imple
         afterExport();
         ReferenceConfig<MultipleRegistryCenterServiceDiscoveryRegistryService> referenceConfig = new ReferenceConfig<>();
         referenceConfig.setInterface(MultipleRegistryCenterServiceDiscoveryRegistryService.class);
-        referenceConfig.setBootstrap(DubboBootstrap.getInstance());
         referenceConfig.get().hello("Dubbo in multiple registry center");
         afterInvoke();
     }
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java
index cfb9df8..3516bbc 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/SingleRegistryCenterDubboProtocolIntegrationTest.java
@@ -41,7 +41,6 @@ import org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery;
 import org.apache.dubbo.registrycenter.RegistryCenter;
 import org.apache.dubbo.registrycenter.ZookeeperSingleRegistryCenter;
 import org.apache.dubbo.rpc.cluster.Directory;
-
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
@@ -310,7 +309,6 @@ public class SingleRegistryCenterDubboProtocolIntegrationTest implements Integra
     private void initConsumer() {
         referenceConfig = new ReferenceConfig<>();
         referenceConfig.setInterface(SingleRegistryCenterIntegrationService.class);
-        referenceConfig.setBootstrap(DubboBootstrap.getInstance());
         DubboBootstrap.getInstance().reference(referenceConfig);
         referenceConfig.setRegistry(registryConfig);
         referenceConfig.setScope(SCOPE_REMOTE);
@@ -326,7 +324,7 @@ public class SingleRegistryCenterDubboProtocolIntegrationTest implements Integra
      */
     private void beforeRefer() {
         // ReferenceConfig has integrated into DubboBootstrap or not
-        Assertions.assertEquals(referenceConfig.getBootstrap(), DubboBootstrap.getInstance());
+        Assertions.assertEquals(referenceConfig.getScopeModel(), DubboBootstrap.getInstance().getApplicationModel().getDefaultModule());
     }
 
     /**
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/exportprovider/SingleRegistryCenterExportProviderIntegrationTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/exportprovider/SingleRegistryCenterExportProviderIntegrationTest.java
index ec806b9..bb511cc 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/exportprovider/SingleRegistryCenterExportProviderIntegrationTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/exportprovider/SingleRegistryCenterExportProviderIntegrationTest.java
@@ -35,7 +35,6 @@ import org.apache.dubbo.registrycenter.ZookeeperMultipleRegistryCenter;
 import org.apache.dubbo.rpc.ExporterListener;
 import org.apache.dubbo.rpc.Filter;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
@@ -176,7 +175,6 @@ public class SingleRegistryCenterExportProviderIntegrationTest implements Integr
         afterExport();
         ReferenceConfig<SingleRegistryCenterExportProviderService> referenceConfig = new ReferenceConfig<>();
         referenceConfig.setInterface(SingleRegistryCenterExportProviderService.class);
-        referenceConfig.setBootstrap(DubboBootstrap.getInstance());
         referenceConfig.setScope(SCOPE_LOCAL);
         referenceConfig.get().hello(PROVIDER_APPLICATION_NAME);
         afterInvoke();
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java
index 0c5cc47..c13fcab 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/integration/single/injvm/SingleRegistryCenterInjvmIntegrationTest.java
@@ -18,12 +18,12 @@ package org.apache.dubbo.integration.single.injvm;
 
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.config.ServiceConfig;
-import org.apache.dubbo.config.ReferenceConfig;
-import org.apache.dubbo.config.ServiceListener;
 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.ServiceListener;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.integration.IntegrationTest;
 import org.apache.dubbo.registrycenter.RegistryCenter;
@@ -144,7 +144,6 @@ public class SingleRegistryCenterInjvmIntegrationTest implements IntegrationTest
         afterExport();
         ReferenceConfig<SingleRegistryCenterInjvmService> referenceConfig = new ReferenceConfig<>();
         referenceConfig.setInterface(SingleRegistryCenterInjvmService.class);
-        referenceConfig.setBootstrap(DubboBootstrap.getInstance());
         referenceConfig.setScope(SCOPE_LOCAL);
         referenceConfig.get().hello("Dubbo");
         afterInvoke();
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ConfigCenterBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ConfigCenterBean.java
index 6374cdb..d0f1263 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ConfigCenterBean.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ConfigCenterBean.java
@@ -19,8 +19,6 @@ package org.apache.dubbo.config.spring;
 import org.apache.dubbo.common.config.ConfigurationUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.ConfigCenterConfig;
-import org.apache.dubbo.config.spring.extension.SpringExtensionInjector;
-
 import org.springframework.beans.factory.DisposableBean;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
@@ -46,7 +44,6 @@ public class ConfigCenterBean extends ConfigCenterConfig implements ApplicationC
     @Override
     public void setApplicationContext(ApplicationContext applicationContext) {
         this.applicationContext = applicationContext;
-        SpringExtensionInjector.addApplicationContext(applicationContext);
     }
 
     @Override
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java
index d07128e..71add7b 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java
@@ -21,9 +21,10 @@ import org.apache.dubbo.common.utils.ClassUtils;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.ReferenceConfig;
 import org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer;
+import org.apache.dubbo.config.spring.reference.ReferenceAttributes;
 import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
 import org.apache.dubbo.config.spring.reference.ReferenceBeanSupport;
-import org.apache.dubbo.config.spring.reference.ReferenceAttributes;
+import org.apache.dubbo.config.spring.schema.DubboBeanDefinitionParser;
 import org.apache.dubbo.config.support.Parameter;
 import org.apache.dubbo.rpc.proxy.AbstractProxyFactory;
 import org.springframework.aop.framework.ProxyFactory;
@@ -158,9 +159,15 @@ public class ReferenceBean<T> implements FactoryBean<T>,
 
     /**
      * Create bean instance.
+     *
+     * <p></p>
+     * Why we need a lazy proxy?
+     *
      * <p/>
      * When Spring searches beans by type, if Spring cannot determine the type of a factory bean, it may try to initialize it.
      * The ReferenceBean is also a FactoryBean.
+     * <br/>
+     * (This has already been resolved by decorating the BeanDefinition: {@link DubboBeanDefinitionParser#configReferenceBean})
      *
      * <p/>
      * In addition, if some ReferenceBeans are dependent on beans that are initialized very early,
@@ -172,13 +179,10 @@ public class ReferenceBean<T> implements FactoryBean<T>,
      * <br/>
      * In this way, the influence of Spring is eliminated, and the dubbo configuration initialization is controllable.
      *
-     * <p/>
-     * Dubbo config beans are initialized in DubboConfigBeanInitializer.
-     * <br/>
-     * The actual references will be processing in DubboBootstrap.referServices().
      *
      * @see DubboConfigBeanInitializer
-     * @see org.apache.dubbo.config.bootstrap.DubboBootstrap
+     * @see ReferenceBeanManager#initReferenceBean(ReferenceBean)
+     * @see DubboBeanDefinitionParser#configReferenceBean
      */
     @Override
     public T getObject() {
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
index 94af84a..6d7158f 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java
@@ -19,11 +19,10 @@ package org.apache.dubbo.config.spring;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.ServiceConfig;
 import org.apache.dubbo.config.annotation.Service;
-import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.config.spring.context.DubboSpringInitializationContext;
 import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
-import org.apache.dubbo.config.spring.extension.SpringExtensionInjector;
+import org.apache.dubbo.config.spring.util.DubboBeanUtils;
 import org.apache.dubbo.config.support.Parameter;
-
 import org.springframework.aop.support.AopUtils;
 import org.springframework.beans.factory.BeanNameAware;
 import org.springframework.beans.factory.DisposableBean;
@@ -65,8 +64,6 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
     @Override
     public void setApplicationContext(ApplicationContext applicationContext) {
         this.applicationContext = applicationContext;
-        //TODO remove SpringExtensionInjector.addApplicationContext();
-        SpringExtensionInjector.addApplicationContext(applicationContext);
     }
 
     @Override
@@ -91,7 +88,8 @@ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean
             }
         }
         //register service bean and set bootstrap
-        DubboBootstrap.getInstance().service(this);
+        DubboSpringInitializationContext dubboContext = DubboBeanUtils.getInitializationContext(applicationContext);
+        dubboContext.getDubboBootstrap().service(this, dubboContext.getModuleModel());
     }
 
     /**
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapApplicationListener.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapApplicationListener.java
index ffb1335..4192949 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapApplicationListener.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapApplicationListener.java
@@ -21,8 +21,8 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.dubbo.config.DubboShutdownHook;
 import org.apache.dubbo.config.bootstrap.BootstrapTakeoverMode;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
-
 import org.apache.dubbo.config.spring.context.event.DubboAnnotationInitedEvent;
+import org.apache.dubbo.config.spring.util.DubboBeanUtils;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
@@ -52,25 +52,23 @@ public class DubboBootstrapApplicationListener implements ApplicationListener, A
 
     private final Log logger = LogFactory.getLog(getClass());
 
-    private final DubboBootstrap dubboBootstrap;
     private ApplicationContext applicationContext;
+    private DubboBootstrap bootstrap;
     private boolean shouldInitConfigBeans;
 
     public DubboBootstrapApplicationListener() {
-        this.dubboBootstrap = initBootstrap();
     }
 
     public DubboBootstrapApplicationListener(boolean shouldInitConfigBeans) {
-        this.dubboBootstrap = initBootstrap();
+        // maybe register DubboBootstrapApplicationListener manual during spring context starting
         this.shouldInitConfigBeans = shouldInitConfigBeans;
     }
 
-    private DubboBootstrap initBootstrap() {
-        DubboBootstrap dubboBootstrap = DubboBootstrap.getInstance();
-        if (dubboBootstrap.getTakeoverMode() != BootstrapTakeoverMode.MANUAL) {
-            dubboBootstrap.setTakeoverMode(BootstrapTakeoverMode.SPRING);
+    private void setBootstrap(DubboBootstrap bootstrap) {
+        this.bootstrap = bootstrap;
+        if (bootstrap.getTakeoverMode() != BootstrapTakeoverMode.MANUAL) {
+            bootstrap.setTakeoverMode(BootstrapTakeoverMode.SPRING);
         }
-        return dubboBootstrap;
     }
 
     @Override
@@ -95,7 +93,7 @@ public class DubboBootstrapApplicationListener implements ApplicationListener, A
         }
 
         // All infrastructure config beans are loaded, initialize dubbo here
-        DubboBootstrap.getInstance().initialize();
+        bootstrap.initialize();
     }
 
     private void onApplicationContextEvent(ApplicationContextEvent event) {
@@ -111,15 +109,15 @@ public class DubboBootstrapApplicationListener implements ApplicationListener, A
     }
 
     private void onContextRefreshedEvent(ContextRefreshedEvent event) {
-        if (dubboBootstrap.getTakeoverMode() == BootstrapTakeoverMode.SPRING) {
-            dubboBootstrap.start();
+        if (bootstrap.getTakeoverMode() == BootstrapTakeoverMode.SPRING) {
+            bootstrap.start();
         }
     }
 
     private void onContextClosedEvent(ContextClosedEvent event) {
-        if (dubboBootstrap.getTakeoverMode() == BootstrapTakeoverMode.SPRING) {
+        if (bootstrap.getTakeoverMode() == BootstrapTakeoverMode.SPRING) {
             // will call dubboBootstrap.stop() through shutdown callback.
-            DubboShutdownHook.getDubboShutdownHook().run();
+            bootstrap.getApplicationModel().getBeanFactory().getBean(DubboShutdownHook.class).run();
         }
     }
 
@@ -147,7 +145,7 @@ public class DubboBootstrapApplicationListener implements ApplicationListener, A
     @Override
     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
         this.applicationContext = applicationContext;
-
+        this.setBootstrap(DubboBeanUtils.getBootstrap(applicationContext));
         if (shouldInitConfigBeans) {
             checkCallStackAndInit();
         }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapServletContextListener.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapServletContextListener.java
deleted file mode 100644
index c270b8b..0000000
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboBootstrapServletContextListener.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.spring.context;
-
-import org.apache.dubbo.config.DubboShutdownHook;
-import org.apache.dubbo.config.bootstrap.BootstrapTakeoverMode;
-import org.apache.dubbo.config.bootstrap.DubboBootstrap;
-
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.annotation.WebListener;
-
-/**
- * DubboBootstrap lifecycle controller for Servlet container.
- *
- * @see DubboBootstrapApplicationListener
- */
-@WebListener
-public class DubboBootstrapServletContextListener implements ServletContextListener {
-
-    public DubboBootstrapServletContextListener() {
-        // Set takeover mode when servlet container is starting
-        if (DubboBootstrap.getInstance().getTakeoverMode() == BootstrapTakeoverMode.AUTO) {
-            DubboBootstrap.getInstance().setTakeoverMode(BootstrapTakeoverMode.SERVLET);
-        }
-    }
-
-    @Override
-    public void contextInitialized(ServletContextEvent servletContextEvent) {
-        // If takeover mode is not changed on servlet container is initialized, it means dubbo does not running in Spring context.
-        // Otherwise, the takeover mode will be changed if dubbo is loaded by Spring.
-        if (DubboBootstrap.getInstance().getTakeoverMode() == BootstrapTakeoverMode.SERVLET) {
-            DubboBootstrap.getInstance().start();
-        }
-    }
-
-    @Override
-    public void contextDestroyed(ServletContextEvent servletContextEvent) {
-        if (DubboBootstrap.getInstance().getTakeoverMode() == BootstrapTakeoverMode.SERVLET) {
-            DubboShutdownHook.getDubboShutdownHook().run();
-        }
-    }
-
-}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboConfigBeanInitializer.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboConfigBeanInitializer.java
index f51bb35..bd8714c 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboConfigBeanInitializer.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboConfigBeanInitializer.java
@@ -16,6 +16,8 @@
  */
 package org.apache.dubbo.config.spring.context;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.dubbo.config.AbstractConfig;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.ConsumerConfig;
@@ -27,18 +29,17 @@ import org.apache.dubbo.config.ProtocolConfig;
 import org.apache.dubbo.config.ProviderConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.SslConfig;
+import org.apache.dubbo.config.context.AbstractConfigManager;
 import org.apache.dubbo.config.context.ConfigManager;
 import org.apache.dubbo.config.spring.ConfigCenterBean;
 import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
-import org.apache.dubbo.rpc.model.ApplicationModel;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.apache.dubbo.rpc.model.ModuleModel;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.FatalBeanException;
 import org.springframework.beans.factory.BeanFactory;
 import org.springframework.beans.factory.BeanFactoryAware;
 import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -60,8 +61,13 @@ public class DubboConfigBeanInitializer implements BeanFactoryAware, Initializin
     private AtomicBoolean initialized = new AtomicBoolean(false);
     private ConfigurableListableBeanFactory beanFactory;
     private ReferenceBeanManager referenceBeanManager;
+
+    @Autowired
     private ConfigManager configManager;
 
+    @Autowired
+    private ModuleModel moduleModel;
+
     @Override
     public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
         this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
@@ -74,7 +80,6 @@ public class DubboConfigBeanInitializer implements BeanFactoryAware, Initializin
 
     private void init() {
         if (initialized.compareAndSet(false, true)) {
-            configManager = ApplicationModel.defaultModel().getApplicationConfigManager();
             referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
             try {
                 prepareDubboConfigBeans();
@@ -92,22 +97,25 @@ public class DubboConfigBeanInitializer implements BeanFactoryAware, Initializin
         logger.info("loading dubbo config beans ...");
 
         //Make sure all these config beans are inited and registered to ConfigManager
-        loadConfigBeansOfType(ApplicationConfig.class);
-        loadConfigBeansOfType(ModuleConfig.class);
-        loadConfigBeansOfType(RegistryConfig.class);
-        loadConfigBeansOfType(ProtocolConfig.class);
-        loadConfigBeansOfType(MonitorConfig.class);
-        loadConfigBeansOfType(ProviderConfig.class);
-        loadConfigBeansOfType(ConsumerConfig.class);
-        loadConfigBeansOfType(ConfigCenterBean.class);
-        loadConfigBeansOfType(MetadataReportConfig.class);
-        loadConfigBeansOfType(MetricsConfig.class);
-        loadConfigBeansOfType(SslConfig.class);
+        // load application configs
+        loadConfigBeansOfType(ApplicationConfig.class, configManager);
+        loadConfigBeansOfType(ModuleConfig.class, configManager);
+        loadConfigBeansOfType(RegistryConfig.class, configManager);
+        loadConfigBeansOfType(ProtocolConfig.class, configManager);
+        loadConfigBeansOfType(MonitorConfig.class, configManager);
+        loadConfigBeansOfType(ConfigCenterBean.class, configManager);
+        loadConfigBeansOfType(MetadataReportConfig.class, configManager);
+        loadConfigBeansOfType(MetricsConfig.class, configManager);
+        loadConfigBeansOfType(SslConfig.class, configManager);
+
+        // load module configs
+        loadConfigBeansOfType(ProviderConfig.class, moduleModel.getConfigManager());
+        loadConfigBeansOfType(ConsumerConfig.class, moduleModel.getConfigManager());
 
         logger.info("dubbo config beans are loaded.");
     }
 
-    private void loadConfigBeansOfType(Class<? extends AbstractConfig> configClass) {
+    private void loadConfigBeansOfType(Class<? extends AbstractConfig> configClass, AbstractConfigManager configManager) {
         String[] beanNames = beanFactory.getBeanNamesForType(configClass, true, false);
         for (String beanName : beanNames) {
             AbstractConfig configBean = beanFactory.getBean(beanName, configClass);
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboInfraBeanRegisterPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboInfraBeanRegisterPostProcessor.java
index 0f79d22..4818fe0 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboInfraBeanRegisterPostProcessor.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboInfraBeanRegisterPostProcessor.java
@@ -22,7 +22,6 @@ import org.apache.dubbo.config.spring.extension.SpringExtensionInjector;
 import org.apache.dubbo.config.spring.util.DubboBeanUtils;
 import org.apache.dubbo.config.spring.util.EnvironmentUtils;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -71,19 +70,23 @@ public class DubboInfraBeanRegisterPostProcessor implements BeanDefinitionRegist
             DubboBeanUtils.registerPlaceholderConfigurerBeanIfNotExists(beanFactory, registry);
         }
 
+        ApplicationModel applicationModel = DubboBeanUtils.getApplicationModel(beanFactory);
+
+        // Initialize SpringExtensionInjector
+        SpringExtensionInjector.get(applicationModel).init(applicationContext);
+
         // Initialize dubbo Environment before ConfigManager
         // Extract dubbo props from Spring env and put them to app config
         ConfigurableEnvironment environment = (ConfigurableEnvironment) applicationContext.getEnvironment();
         SortedMap<String, String> dubboProperties = EnvironmentUtils.filterDubboProperties(environment);
-        ApplicationModel.defaultModel().getApplicationEnvironment().setAppConfigMap(dubboProperties);
+        applicationModel.getApplicationEnvironment().setAppConfigMap(dubboProperties);
 
         // register ConfigManager singleton
-        beanFactory.registerSingleton(ConfigManager.BEAN_NAME, ApplicationModel.defaultModel().getApplicationConfigManager());
+        beanFactory.registerSingleton(ConfigManager.BEAN_NAME, applicationModel.getApplicationConfigManager());
     }
 
     @Override
     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
         this.applicationContext = applicationContext;
-        SpringExtensionInjector.addApplicationContext(applicationContext);
     }
 }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java
index 08a5e09..1bca441 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationContext.java
@@ -16,7 +16,12 @@
  */
 package org.apache.dubbo.config.spring.context;
 
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.ModuleModel;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.ApplicationContext;
 
 /**
  * Dubbo spring initialization context object
@@ -25,6 +30,20 @@ public class DubboSpringInitializationContext {
 
     private BeanDefinitionRegistry registry;
 
+    private ConfigurableListableBeanFactory beanFactory;
+
+    private ApplicationContext applicationContext;
+
+    private ModuleModel moduleModel;
+
+    private DubboBootstrap dubboBootstrap;
+
+    private volatile boolean bound;
+
+    public void markAsBound() {
+        bound = true;
+    }
+
     public BeanDefinitionRegistry getRegistry() {
         return registry;
     }
@@ -33,4 +52,59 @@ public class DubboSpringInitializationContext {
         this.registry = registry;
     }
 
+    public ConfigurableListableBeanFactory getBeanFactory() {
+        return beanFactory;
+    }
+
+    void setBeanFactory(ConfigurableListableBeanFactory beanFactory) {
+        this.beanFactory = beanFactory;
+    }
+
+    public ApplicationContext getApplicationContext() {
+        return applicationContext;
+    }
+
+    void setApplicationContext(ApplicationContext applicationContext) {
+        this.applicationContext = applicationContext;
+    }
+
+    public ApplicationModel getApplicationModel() {
+        return (moduleModel == null) ? null : moduleModel.getApplicationModel();
+    }
+
+    public ModuleModel getModuleModel() {
+        return moduleModel;
+    }
+
+    /**
+     * Change the binding ModuleModel, the ModuleModel and DubboBootstrap must be matched.
+     *
+     * @see #setDubboBootstrap(DubboBootstrap)
+     * @param moduleModel
+     */
+    public void setModuleModel(ModuleModel moduleModel) {
+        if (bound) {
+            throw new IllegalStateException("Cannot change ModuleModel after bound context");
+        }
+        this.moduleModel = moduleModel;
+    }
+
+    public DubboBootstrap getDubboBootstrap() {
+        return dubboBootstrap;
+    }
+
+    /**
+     * Change the binding DubboBootstrap instance, the ModuleModel and DubboBootstrap must be matched.
+     * <p></p>
+     * By default, DubboBoostrap is created using the ApplicationModel in which the ModuleModel resides.
+     *
+     * @see #setModuleModel(ModuleModel)
+     * @param dubboBootstrap
+     */
+    public void setDubboBootstrap(DubboBootstrap dubboBootstrap) {
+        if (bound) {
+            throw new IllegalStateException("Cannot change DubboBootstrap after bound context");
+        }
+        this.dubboBootstrap = dubboBootstrap;
+    }
 }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationCustomizer.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationCustomizer.java
index 9637996..223307a 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationCustomizer.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializationCustomizer.java
@@ -17,18 +17,22 @@
 package org.apache.dubbo.config.spring.context;
 
 import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.rpc.model.ModuleModel;
 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
 import org.springframework.beans.factory.config.BeanPostProcessor;
 
+import static org.apache.dubbo.common.extension.ExtensionScope.FRAMEWORK;
+
 /**
  * Custom dubbo spring initialization
  */
-@SPI
+@SPI(scope = FRAMEWORK)
 public interface DubboSpringInitializationCustomizer {
 
     /**
      * <p>Customize dubbo spring initialization on bean registry processing phase.</p>
      * <p>You can register a {@link BeanFactoryPostProcessor} or {@link BeanPostProcessor} for custom processing.</p>
+     * <p>Or change the bind module model via {@link DubboSpringInitializationContext#setModuleModel(ModuleModel)}.</p>
      *
      * <p><b>Note:</b></p>
      * <p>1. The bean factory may be not ready yet when triggered by parsing dubbo xml definition.</p>
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializer.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializer.java
index 2ae3d37..4272e3b 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializer.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboSpringInitializer.java
@@ -16,9 +16,18 @@
  */
 package org.apache.dubbo.config.spring.context;
 
-import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.config.spring.extension.SpringExtensionInjector;
 import org.apache.dubbo.config.spring.util.DubboBeanUtils;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.ModuleModel;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.support.GenericApplicationContext;
 
 import java.util.Map;
 import java.util.Set;
@@ -31,28 +40,128 @@ public class DubboSpringInitializer {
 
     private static Map<BeanDefinitionRegistry, DubboSpringInitializationContext> contextMap = new ConcurrentHashMap<>();
 
+    private DubboSpringInitializer() {
+    }
+
     public static void initialize(BeanDefinitionRegistry registry) {
 
         if (contextMap.putIfAbsent(registry, new DubboSpringInitializationContext()) != null) {
             return;
         }
 
-        // register common beans
-        DubboBeanUtils.registerCommonBeans(registry);
-
         // prepare context and do customize
         DubboSpringInitializationContext context = contextMap.get(registry);
+
+        // find beanFactory and applicationContext
+        ConfigurableListableBeanFactory beanFactory = findBeanFactory(registry);
+        ApplicationContext applicationContext = findApplicationContext(registry, beanFactory);
+
+        // init dubbo context
+        initContext(context, registry, beanFactory, applicationContext);
+    }
+
+
+    private static void initContext(DubboSpringInitializationContext context, BeanDefinitionRegistry registry,
+                                    ConfigurableListableBeanFactory beanFactory, ApplicationContext applicationContext) {
         context.setRegistry(registry);
+        context.setApplicationContext(applicationContext);
+
+        // customize context, you can change the bind module model via DubboSpringInitializationCustomizer SPI
         customize(context);
+
+        // init ApplicationModel
+        ApplicationModel applicationModel = context.getApplicationModel();
+        if (applicationModel == null) {
+            if (findContextForApplication(ApplicationModel.defaultModel()) == null) {
+                // first spring context use default application instance
+                applicationModel = ApplicationModel.defaultModel();
+            } else {
+                // create an new application instance for later spring context
+                applicationModel = FrameworkModel.defaultModel().newApplication();
+            }
+
+            // init ModuleModel
+            ModuleModel moduleModel = applicationModel.getDefaultModule();
+            context.setModuleModel(moduleModel);
+        }
+
+        // Init SpringExtensionInjector
+        // Maybe the applicationContext is null, that means the Spring ApplicationContext is not completely created, so can not retrieve bean from it.
+        // We will reinitialize it again in DubboInfraBeanRegisterPostProcessor
+        if (applicationContext != null) {
+            SpringExtensionInjector.get(context.getApplicationModel()).init(applicationContext);
+        }
+
+        // create DubboBootstrap
+        DubboBootstrap bootstrap = context.getDubboBootstrap();
+        if (bootstrap == null) {
+            if (applicationModel == ApplicationModel.defaultModel()) {
+                bootstrap = DubboBootstrap.getInstance();
+            } else {
+                bootstrap = DubboBootstrap.newInstance(applicationModel);
+            }
+            context.setDubboBootstrap(bootstrap);
+        }
+
+        // bind dubbo initialization context to spring context
+        registerContextBeans(beanFactory, context);
+
+        // mark context as bound
+        context.markAsBound();
+
+        // register common beans
+        DubboBeanUtils.registerCommonBeans(registry);
     }
 
-    private DubboSpringInitializer() {
+    private static ConfigurableListableBeanFactory findBeanFactory(BeanDefinitionRegistry registry) {
+        ConfigurableListableBeanFactory beanFactory = null;
+        if (registry instanceof ConfigurableListableBeanFactory) {
+            beanFactory = (ConfigurableListableBeanFactory) registry;
+        } else if (registry instanceof GenericApplicationContext) {
+            GenericApplicationContext genericApplicationContext = (GenericApplicationContext) registry;
+            beanFactory = genericApplicationContext.getBeanFactory();
+        } else {
+            throw new IllegalStateException("Can not find Spring BeanFactory from registry: " + registry.getClass().getName());
+        }
+        return beanFactory;
+    }
+
+    private static ApplicationContext findApplicationContext(BeanDefinitionRegistry registry, ConfigurableListableBeanFactory beanFactory) {
+        // GenericApplicationContext
+        if (registry instanceof ApplicationContext) {
+            return (ApplicationContext) registry;
+        }
+        // find by ApplicationContextAware
+        ApplicationContextAwareBean contextBean = new ApplicationContextAwareBean();
+        beanFactory.initializeBean(contextBean, ApplicationContextAwareBean.class.getSimpleName());
+        return contextBean.applicationContext;
+    }
+
+    private static void registerContextBeans(ConfigurableListableBeanFactory beanFactory, DubboSpringInitializationContext context) {
+        // register singleton
+        registerSingleton(beanFactory, context);
+        registerSingleton(beanFactory, context.getApplicationModel());
+        registerSingleton(beanFactory, context.getModuleModel());
+        registerSingleton(beanFactory, context.getDubboBootstrap());
+    }
+
+    private static void registerSingleton(ConfigurableListableBeanFactory beanFactory, Object bean) {
+        beanFactory.registerSingleton(bean.getClass().getName(), bean);
+    }
+
+    private static DubboSpringInitializationContext findContextForApplication(ApplicationModel applicationModel) {
+        for (DubboSpringInitializationContext initializationContext : contextMap.values()) {
+            if (initializationContext.getApplicationModel() == applicationModel) {
+                return initializationContext;
+            }
+        }
+        return null;
     }
 
     private static void customize(DubboSpringInitializationContext context) {
 
         // find initialization customizers
-        Set<DubboSpringInitializationCustomizer> customizers = ExtensionLoader
+        Set<DubboSpringInitializationCustomizer> customizers = FrameworkModel.defaultModel()
             .getExtensionLoader(DubboSpringInitializationCustomizer.class)
             .getSupportedExtensionInstances();
 
@@ -60,4 +169,14 @@ public class DubboSpringInitializer {
             customizer.customize(context);
         }
     }
+
+    static class ApplicationContextAwareBean implements ApplicationContextAware {
+
+        private ApplicationContext applicationContext;
+
+        @Override
+        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+            this.applicationContext = applicationContext;
+        }
+    }
 }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/DubboAnnotationInitedEvent.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/DubboAnnotationInitedEvent.java
index 1295f04..b53e730 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/DubboAnnotationInitedEvent.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/DubboAnnotationInitedEvent.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.config.spring.context.event;
 
 import org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer;
+import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationEvent;
 
 /**
@@ -31,7 +32,15 @@ public class DubboAnnotationInitedEvent extends ApplicationEvent {
      * @param source the object on which the event initially occurred or with
      *               which the event is associated (never {@code null})
      */
-    public DubboAnnotationInitedEvent(Object source) {
+    public DubboAnnotationInitedEvent(ApplicationContext source) {
         super(source);
     }
+
+    /**
+     * Get the {@code ApplicationContext} that the event was raised for.
+     */
+    public final ApplicationContext getApplicationContext() {
+        return (ApplicationContext) getSource();
+    }
+
 }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/extension/SpringExtensionInjector.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/extension/SpringExtensionInjector.java
index c580ab2..6e6a1a8 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/extension/SpringExtensionInjector.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/extension/SpringExtensionInjector.java
@@ -17,18 +17,16 @@
 package org.apache.dubbo.config.spring.extension;
 
 import org.apache.dubbo.common.context.Lifecycle;
+import org.apache.dubbo.common.extension.ExtensionAccessor;
 import org.apache.dubbo.common.extension.ExtensionInjector;
 import org.apache.dubbo.common.extension.SPI;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.ConcurrentHashSet;
-import org.apache.dubbo.config.DubboShutdownHook;
-
-import com.alibaba.spring.util.BeanFactoryUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.springframework.beans.factory.ListableBeanFactory;
 import org.springframework.context.ApplicationContext;
-import org.springframework.context.ConfigurableApplicationContext;
 
-import java.util.Set;
+import java.util.Arrays;
 
 /**
  * SpringExtensionInjector
@@ -36,50 +34,87 @@ import java.util.Set;
 public class SpringExtensionInjector implements ExtensionInjector, Lifecycle {
     private static final Logger logger = LoggerFactory.getLogger(SpringExtensionInjector.class);
 
-    private static final Set<ApplicationContext> CONTEXTS = new ConcurrentHashSet<ApplicationContext>();
+    public static final String NAME = "spring";
+
+    private ApplicationContext context;
 
+    @Deprecated
     public static void addApplicationContext(ApplicationContext context) {
-        CONTEXTS.add(context);
-        if (context instanceof ConfigurableApplicationContext) {
-            ((ConfigurableApplicationContext) context).registerShutdownHook();
-            // see https://github.com/apache/dubbo/issues/7093
-            DubboShutdownHook.getDubboShutdownHook().unregister();
-        }
+//        CONTEXTS.add(context);
+//        if (context instanceof ConfigurableApplicationContext) {
+//            ((ConfigurableApplicationContext) context).registerShutdownHook();
+//            // see https://github.com/apache/dubbo/issues/7093
+//            DubboShutdownHook.getDubboShutdownHook().unregister();
+//        }
+    }
+
+//    @Deprecated
+//    public static Set<ApplicationContext> getContexts() {
+//        // return contexts;
+//        return Collections.emptySet();
+//    }
+
+//    @Deprecated
+//    public static void clearContexts() {
+//        //contexts.clear();
+//    }
+
+    public static SpringExtensionInjector get(ExtensionAccessor extensionAccessor) {
+        return (SpringExtensionInjector) extensionAccessor.getExtension(ExtensionInjector.class, NAME);
     }
 
-    public static Set<ApplicationContext> getContexts() {
-        return CONTEXTS;
+    public ApplicationContext getContext() {
+        return context;
     }
 
-    // currently for test purpose
-    public static void clearContexts() {
-        CONTEXTS.clear();
+    public void init(ApplicationContext context) {
+        this.context = context;
     }
 
     @Override
     @SuppressWarnings("unchecked")
     public <T> T getInstance(Class<T> type, String name) {
 
-        //SPI should be get from SpiExtensionInjector
+        if (context == null) {
+            // ignore if spring context is not bound
+            return null;
+        }
+
+        //check @SPI annotation
         if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
             return null;
         }
 
-        for (ApplicationContext context : CONTEXTS) {
-            T bean = BeanFactoryUtils.getOptionalBean(context, name, type);
-            if (bean != null) {
-                return bean;
-            }
+        T bean = getOptionalBean(context, name, type);
+        if (bean != null) {
+            return bean;
         }
 
         //logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());
+        return null;
+    }
 
+    private <T> T getOptionalBean(ListableBeanFactory beanFactory, String name, Class<T> type) {
+        if (StringUtils.isEmpty(name)) {
+            String[] beanNamesForType = beanFactory.getBeanNamesForType(type, true, false);
+            if (beanNamesForType != null) {
+                if (beanNamesForType.length == 1) {
+                    return beanFactory.getBean(beanNamesForType[0], type);
+                } else if (beanNamesForType.length > 1) {
+                    throw new IllegalStateException("Expect single but found " + beanNamesForType.length + " beans in spring context: " +
+                        Arrays.toString(beanNamesForType));
+                }
+            }
+        } else {
+            if (beanFactory.containsBean(name)) {
+                return beanFactory.getBean(name, type);
+            }
+        }
         return null;
     }
 
     @Override
     public void initialize() throws IllegalStateException {
-        clearContexts();
     }
 
     @Override
@@ -89,6 +124,5 @@ public class SpringExtensionInjector implements ExtensionInjector, Lifecycle {
 
     @Override
     public void destroy() {
-        clearContexts();
     }
 }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanManager.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanManager.java
index c87a068..ce5d42b 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanManager.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/reference/ReferenceBeanManager.java
@@ -22,6 +22,8 @@ import org.apache.dubbo.common.utils.Assert;
 import org.apache.dubbo.config.ReferenceConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.spring.ReferenceBean;
+import org.apache.dubbo.config.spring.context.DubboSpringInitializationContext;
+import org.apache.dubbo.config.spring.util.DubboBeanUtils;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
@@ -52,7 +54,9 @@ public class ReferenceBeanManager implements ApplicationContextAware {
     private Map<String, ReferenceConfig> referenceConfigMap = new ConcurrentHashMap<>();
 
     private ApplicationContext applicationContext;
+    private DubboBootstrap dubboBootstrap;
     private volatile boolean initialized = false;
+    private DubboSpringInitializationContext initializationContext;
 
     public void addReference(ReferenceBean referenceBean) throws Exception {
         String referenceBeanName = referenceBean.getId();
@@ -115,6 +119,8 @@ public class ReferenceBeanManager implements ApplicationContextAware {
     @Override
     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
         this.applicationContext = applicationContext;
+        this.dubboBootstrap = DubboBeanUtils.getBootstrap(applicationContext);
+        initializationContext = DubboBeanUtils.getInitializationContext(applicationContext);
     }
 
     /**
@@ -169,7 +175,7 @@ public class ReferenceBeanManager implements ApplicationContextAware {
             referenceConfigMap.put(referenceKey, referenceConfig);
 
             // register ReferenceConfig
-            DubboBootstrap.getInstance().reference(referenceConfig);
+            dubboBootstrap.reference(referenceConfig, initializationContext.getModuleModel());
         }
 
         // associate referenceConfig to referenceBean
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java
index 7993feb..200e57c 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java
@@ -31,7 +31,6 @@ import org.apache.dubbo.config.spring.ConfigCenterBean;
 import org.apache.dubbo.config.spring.ReferenceBean;
 import org.apache.dubbo.config.spring.ServiceBean;
 import org.apache.dubbo.config.spring.beans.factory.config.ConfigurableSourceBeanMetadataElement;
-
 import org.apache.dubbo.config.spring.context.DubboSpringInitializer;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -83,7 +82,7 @@ public class DubboNamespaceHandler extends NamespaceHandlerSupport implements Co
         registerAnnotationConfigProcessors(registry);
 
         // initialize dubbo beans
-        DubboSpringInitializer.initialize(registry);
+        DubboSpringInitializer.initialize(parserContext.getRegistry());
 
         BeanDefinition beanDefinition = super.parse(element, parserContext);
         setSource(beanDefinition);
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/DataSourceStatusChecker.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/DataSourceStatusChecker.java
index c28db37..c9cd8b6 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/DataSourceStatusChecker.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/DataSourceStatusChecker.java
@@ -23,7 +23,7 @@ import org.apache.dubbo.common.status.Status;
 import org.apache.dubbo.common.status.StatusChecker;
 import org.apache.dubbo.common.utils.CollectionUtils;
 import org.apache.dubbo.config.spring.extension.SpringExtensionInjector;
-
+import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.springframework.context.ApplicationContext;
 
 import javax.sql.DataSource;
@@ -31,8 +31,6 @@ import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.ResultSet;
 import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
 
 /**
  * DataSourceStatusChecker
@@ -42,17 +40,31 @@ public class DataSourceStatusChecker implements StatusChecker {
 
     private static final Logger logger = LoggerFactory.getLogger(DataSourceStatusChecker.class);
 
+    private ApplicationModel applicationModel;
+
+    private ApplicationContext applicationContext;
+
+    public DataSourceStatusChecker(ApplicationModel applicationModel) {
+        this.applicationModel = applicationModel;
+    }
+
+    public DataSourceStatusChecker(ApplicationContext context) {
+        this.applicationContext = context;
+    }
+
     @Override
     public Status check() {
-        Optional<ApplicationContext> context =
-                SpringExtensionInjector.getContexts().stream().filter(Objects::nonNull).findFirst();
+        if (applicationContext == null) {
+            SpringExtensionInjector springExtensionInjector = SpringExtensionInjector.get(applicationModel);
+            applicationContext = springExtensionInjector.getContext();
+        }
 
-        if (!context.isPresent()) {
+        if (applicationContext == null) {
             return new Status(Status.Level.UNKNOWN);
         }
 
         Map<String, DataSource> dataSources =
-                context.get().getBeansOfType(DataSource.class, false, false);
+            applicationContext.getBeansOfType(DataSource.class, false, false);
         if (CollectionUtils.isEmptyMap(dataSources)) {
             return new Status(Status.Level.UNKNOWN);
         }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/SpringStatusChecker.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/SpringStatusChecker.java
index cae9260..fad4121 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/SpringStatusChecker.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/SpringStatusChecker.java
@@ -22,10 +22,9 @@ import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.status.Status;
 import org.apache.dubbo.common.status.StatusChecker;
 import org.apache.dubbo.config.spring.extension.SpringExtensionInjector;
-
+import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.Lifecycle;
-import org.springframework.web.context.support.GenericWebApplicationContext;
 
 import java.lang.reflect.Method;
 
@@ -37,29 +36,47 @@ public class SpringStatusChecker implements StatusChecker {
 
     private static final Logger logger = LoggerFactory.getLogger(SpringStatusChecker.class);
 
+    private ApplicationModel applicationModel;
+
+    private ApplicationContext applicationContext;
+
+    public SpringStatusChecker(ApplicationModel applicationModel) {
+        this.applicationModel = applicationModel;
+    }
+
+    public SpringStatusChecker(ApplicationContext applicationContext) {
+        this.applicationContext = applicationContext;
+    }
+
     @Override
     public Status check() {
-        ApplicationContext context = null;
-        for (ApplicationContext c : SpringExtensionInjector.getContexts()) {
-            // [Issue] SpringStatusChecker execute errors on non-XML Spring configuration
-            // issue : https://github.com/apache/dubbo/issues/3615
-            if(c instanceof GenericWebApplicationContext) { // ignore GenericXmlApplicationContext
-                continue;
-            }
+        // TODO It seems to be ok with GenericWebApplicationContext, need further confirmation
+//        ApplicationContext context = null;
+//        for (ApplicationContext c : SpringExtensionInjector.getContexts()) {
+//            // [Issue] SpringStatusChecker execute errors on non-XML Spring configuration
+//            // issue : https://github.com/apache/dubbo/issues/3615
+//            if(c instanceof GenericWebApplicationContext) { // ignore GenericXmlApplicationContext
+//                continue;
+//            }
+//
+//            if (c != null) {
+//                context = c;
+//                break;
+//            }
+//        }
 
-            if (c != null) {
-                context = c;
-                break;
-            }
+        if (applicationContext == null && applicationModel != null) {
+            SpringExtensionInjector springExtensionInjector = SpringExtensionInjector.get(applicationModel);
+            applicationContext = springExtensionInjector.getContext();
         }
 
-        if (context == null) {
+        if (applicationContext == null) {
             return new Status(Status.Level.UNKNOWN);
         }
 
         Status.Level level;
-        if (context instanceof Lifecycle) {
-            if (((Lifecycle) context).isRunning()) {
+        if (applicationContext instanceof Lifecycle) {
+            if (((Lifecycle) applicationContext).isRunning()) {
                 level = Status.Level.OK;
             } else {
                 level = Status.Level.ERROR;
@@ -69,7 +86,7 @@ public class SpringStatusChecker implements StatusChecker {
         }
         StringBuilder buf = new StringBuilder();
         try {
-            Class<?> cls = context.getClass();
+            Class<?> cls = applicationContext.getClass();
             Method method = null;
             while (cls != null && method == null) {
                 try {
@@ -82,7 +99,7 @@ public class SpringStatusChecker implements StatusChecker {
                 if (!method.isAccessible()) {
                     method.setAccessible(true);
                 }
-                String[] configs = (String[]) method.invoke(context, new Object[0]);
+                String[] configs = (String[]) method.invoke(applicationContext, new Object[0]);
                 if (configs != null && configs.length > 0) {
                     for (String config : configs) {
                         if (buf.length() > 0) {
@@ -92,6 +109,8 @@ public class SpringStatusChecker implements StatusChecker {
                     }
                 }
             }
+        } catch (UnsupportedOperationException t) {
+            logger.debug(t.getMessage(), t);
         } catch (Throwable t) {
             logger.warn(t.getMessage(), t);
         }
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java
index 72f2177..2cc878b 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/DubboBeanUtils.java
@@ -18,14 +18,18 @@ package org.apache.dubbo.config.spring.util;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.dubbo.config.spring.beans.factory.annotation.ServicePackagesHolder;
-import org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer;
-import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigAliasPostProcessor;
 import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor;
+import org.apache.dubbo.config.spring.beans.factory.annotation.ServicePackagesHolder;
 import org.apache.dubbo.config.spring.beans.factory.config.DubboConfigDefaultPropertyValueBeanPostProcessor;
 import org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener;
+import org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer;
 import org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor;
+import org.apache.dubbo.config.spring.context.DubboSpringInitializationContext;
+import org.apache.dubbo.config.spring.reference.ReferenceBeanManager;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.springframework.beans.factory.BeanFactory;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.config.BeanPostProcessor;
 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -65,20 +69,20 @@ public interface DubboBeanUtils {
 
         // Since 2.5.7 Register @Reference Annotation Bean Processor as an infrastructure Bean
         registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,
-                ReferenceAnnotationBeanPostProcessor.class);
+            ReferenceAnnotationBeanPostProcessor.class);
 
         // TODO Whether DubboConfigAliasPostProcessor can be removed ?
         // Since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093
         registerInfrastructureBean(registry, DubboConfigAliasPostProcessor.BEAN_NAME,
-                DubboConfigAliasPostProcessor.class);
+            DubboConfigAliasPostProcessor.class);
 
         // Since 2.7.4 Register DubboBootstrapApplicationListener as an infrastructure Bean
         registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME,
-                DubboBootstrapApplicationListener.class);
+            DubboBootstrapApplicationListener.class);
 
         // Since 2.7.6 Register DubboConfigDefaultPropertyValueBeanPostProcessor as an infrastructure Bean
         registerInfrastructureBean(registry, DubboConfigDefaultPropertyValueBeanPostProcessor.BEAN_NAME,
-                DubboConfigDefaultPropertyValueBeanPostProcessor.class);
+            DubboConfigDefaultPropertyValueBeanPostProcessor.class);
 
         // Dubbo config initializer
         registerInfrastructureBean(registry, DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);
@@ -96,8 +100,8 @@ public interface DubboBeanUtils {
      * @return if it's a first time to register, return <code>true</code>, or <code>false</code>
      */
     static boolean registerInfrastructureBean(BeanDefinitionRegistry beanDefinitionRegistry,
-                                                     String beanName,
-                                                     Class<?> beanType) {
+                                              String beanName,
+                                              Class<?> beanType) {
 
         boolean registered = false;
 
@@ -109,7 +113,7 @@ public interface DubboBeanUtils {
 
             if (log.isDebugEnabled()) {
                 log.debug("The Infrastructure bean definition [" + beanDefinition
-                        + "with name [" + beanName + "] has been registered.");
+                    + "with name [" + beanName + "] has been registered.");
             }
         }
 
@@ -120,10 +124,11 @@ public interface DubboBeanUtils {
      * Register a placeholder configurer beans if not exists.
      * Call this method in BeanDefinitionRegistryPostProcessor,
      * in order to enable the registered BeanFactoryPostProcessor bean to be loaded and executed.
-     * @see DubboInfraBeanRegisterPostProcessor
-     * @see org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List)
+     *
      * @param beanFactory
      * @param registry
+     * @see DubboInfraBeanRegisterPostProcessor
+     * @see org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List)
      */
     static void registerPlaceholderConfigurerBeanIfNotExists(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry) {
         // Auto register a PropertyPlaceholderConfigurer bean to resolve placeholders with Spring Environment PropertySources
@@ -133,12 +138,12 @@ public interface DubboBeanUtils {
             propertySourcesPlaceholderPropertyValues.put("ignoreUnresolvablePlaceholders", true);
 
             registerBeanDefinition(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
-                    PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);
+                PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);
         }
     }
 
     static boolean registerBeanDefinition(BeanDefinitionRegistry registry, String beanName,
-                                                     Class<?> beanClass, Map<String, Object> extraPropertyValues) {
+                                          Class<?> beanClass, Map<String, Object> extraPropertyValues) {
         if (registry.containsBeanDefinition(beanName)) {
             return false;
         }
@@ -172,4 +177,29 @@ public interface DubboBeanUtils {
     static ReferenceAnnotationBeanPostProcessor getReferenceAnnotationBeanPostProcessor(ApplicationContext applicationContext) {
         return getReferenceAnnotationBeanPostProcessor((AbstractBeanFactory) applicationContext.getAutowireCapableBeanFactory());
     }
+
+    static DubboSpringInitializationContext getInitializationContext(BeanFactory beanFactory) {
+        String beanName = DubboSpringInitializationContext.class.getName();
+        if (beanFactory.containsBean(beanName)) {
+            return beanFactory.getBean(beanName, DubboSpringInitializationContext.class);
+        }
+        return null;
+    }
+
+    static DubboBootstrap getBootstrap(BeanFactory beanFactory) {
+        String beanName = DubboBootstrap.class.getName();
+        if (beanFactory.containsBean(beanName)) {
+            return beanFactory.getBean(beanName, DubboBootstrap.class);
+        }
+        return null;
+    }
+
+    static ApplicationModel getApplicationModel(BeanFactory beanFactory) {
+        String beanName = ApplicationModel.class.getName();
+        if (beanFactory.containsBean(beanName)) {
+            return beanFactory.getBean(beanName, ApplicationModel.class);
+        }
+        return null;
+    }
+
 }
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java
index a320f36..5fd0ad6 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java
@@ -30,6 +30,7 @@ import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.ServiceConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.context.ModuleConfigManager;
 import org.apache.dubbo.config.spring.action.DemoActionByAnnotation;
 import org.apache.dubbo.config.spring.action.DemoActionBySetter;
 import org.apache.dubbo.config.spring.annotation.consumer.AnnotationAction;
@@ -52,7 +53,6 @@ import org.apache.dubbo.rpc.RpcContext;
 import org.apache.dubbo.rpc.RpcException;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.service.GenericService;
-
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
@@ -133,9 +133,6 @@ public class ConfigTest {
         try {
             ctx.start();
 
-            // clear config manager
-            ApplicationModel.defaultModel().getApplicationConfigManager().destroy();
-
             DemoService demoService = refer("dubbo://127.0.0.1:20887");
             String hello = demoService.sayName("hello");
             assertEquals("welcome:hello", hello);
@@ -158,7 +155,7 @@ public class ConfigTest {
             reference.setInterface(HelloService.class);
             reference.setUrl("dubbo://127.0.0.1:12345");
 
-            DubboBootstrap bootstrap = DubboBootstrap.getInstance()
+            DubboBootstrap bootstrap = DubboBootstrap.newInstance()
                     .application(new ApplicationConfig("consumer"))
                     .reference(reference)
                     .start();
@@ -197,7 +194,7 @@ public class ConfigTest {
         reference.setInterface(DemoService.class);
         reference.setUrl(url);
 
-        DubboBootstrap bootstrap = DubboBootstrap.getInstance()
+        DubboBootstrap bootstrap = DubboBootstrap.newInstance()
                 .application(new ApplicationConfig("consumer"))
                 .reference(reference)
                 .start();
@@ -241,9 +238,6 @@ public class ConfigTest {
         try {
             ctx.start();
 
-            // clear config manager
-            ApplicationModel.defaultModel().getApplicationConfigManager().destroy();
-
             DemoService demoService = refer("dubbo://127.0.0.1:20881");
             String hello = demoService.sayName("hello");
             assertEquals("say:hello", hello);
@@ -481,18 +475,16 @@ public class ConfigTest {
         try {
             providerContext.start();
 
-            // clear config manager
-            ApplicationModel.defaultModel().getApplicationConfigManager().destroy();
-
-            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(resourcePath + "/init-reference.xml",
+            // consumer app
+            ClassPathXmlApplicationContext consumerContext = new ClassPathXmlApplicationContext(resourcePath + "/init-reference.xml",
                     resourcePath + "/init-reference-properties.xml");
             try {
-                ctx.start();
+                consumerContext.start();
 
-                NotifyService notifyService = ctx.getBean(NotifyService.class);
+                NotifyService notifyService = consumerContext.getBean(NotifyService.class);
 
                 // check reference bean
-                Map<String, ReferenceBean> referenceBeanMap = ctx.getBeansOfType(ReferenceBean.class);
+                Map<String, ReferenceBean> referenceBeanMap = consumerContext.getBeansOfType(ReferenceBean.class);
                 Assertions.assertEquals(2, referenceBeanMap.size());
                 ReferenceBean referenceBean = referenceBeanMap.get("&demoService");
                 Assertions.assertNotNull(referenceBean);
@@ -524,15 +516,15 @@ public class ConfigTest {
 
 
                 // do call
-                DemoService demoService = (DemoService) ctx.getBean("demoService");
+                DemoService demoService = (DemoService) consumerContext.getBean("demoService");
                 assertEquals("say:world", demoService.sayName("world"));
 
-                GenericService demoService2 = (GenericService) ctx.getBean("demoService2");
+                GenericService demoService2 = (GenericService) consumerContext.getBean("demoService2");
                 assertEquals("say:world", demoService2.$invoke("sayName", new String[]{"java.lang.String"}, new Object[]{"world"}));
 
             } finally {
-                ctx.stop();
-                ctx.close();
+                consumerContext.stop();
+                consumerContext.close();
             }
         } finally {
             providerContext.stop();
@@ -833,7 +825,8 @@ public class ConfigTest {
             // set default value of check
             assertEquals(false, reference.shouldCheck());
 
-            ConsumerConfig defaultConsumer = ApplicationModel.defaultModel().getApplicationConfigManager().getDefaultConsumer().get();
+            ModuleConfigManager moduleConfigManager = ApplicationModel.defaultModel().getDefaultModule().getConfigManager();
+            ConsumerConfig defaultConsumer = moduleConfigManager.getDefaultConsumer().get();
             assertEquals(1234, defaultConsumer.getTimeout());
             assertEquals(false, defaultConsumer.isCheck());
         } finally {
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/JavaConfigBeanTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/JavaConfigBeanTest.java
index 2f216c0..abc20c3 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/JavaConfigBeanTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/JavaConfigBeanTest.java
@@ -25,6 +25,7 @@ import org.apache.dubbo.config.annotation.DubboReference;
 import org.apache.dubbo.config.annotation.DubboService;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.context.ModuleConfigManager;
 import org.apache.dubbo.config.spring.api.DemoService;
 import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
 import org.apache.dubbo.config.spring.impl.DemoServiceImpl;
@@ -32,7 +33,6 @@ import org.apache.dubbo.config.spring.registrycenter.RegistryCenter;
 import org.apache.dubbo.config.spring.registrycenter.ZookeeperSingleRegistryCenter;
 import org.apache.dubbo.rpc.Constants;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
@@ -104,7 +104,9 @@ public class JavaConfigBeanTest {
             Assertions.assertEquals(2346, protocolConfig.getPort());
             Assertions.assertEquals(MY_PROTOCOL_ID, protocolConfig.getId());
 
-            ConsumerConfig consumerConfig = configManager.getDefaultConsumer().get();
+            ApplicationModel applicationModel = consumerContext.getBean(ApplicationModel.class);
+            ModuleConfigManager moduleConfigManager = applicationModel.getDefaultModule().getConfigManager();
+            ConsumerConfig consumerConfig = moduleConfigManager.getDefaultConsumer().get();
             Assertions.assertEquals(1000, consumerConfig.getTimeout());
             Assertions.assertEquals("demo", consumerConfig.getGroup());
             Assertions.assertEquals(false, consumerConfig.isCheck());
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/MethodConfigCallbackTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/MethodConfigCallbackTest.java
index f6895f5..0290f42 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/MethodConfigCallbackTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/MethodConfigCallbackTest.java
@@ -23,11 +23,11 @@ import org.apache.dubbo.config.spring.api.HelloService;
 import org.apache.dubbo.config.spring.api.MethodCallback;
 import org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration;
 import org.apache.dubbo.config.spring.impl.MethodCallbackImpl;
-import org.apache.dubbo.config.spring.registrycenter.ZookeeperSingleRegistryCenter;
 import org.apache.dubbo.config.spring.registrycenter.RegistryCenter;
+import org.apache.dubbo.config.spring.registrycenter.ZookeeperSingleRegistryCenter;
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java
index a97ee3b..945eaa7 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java
@@ -28,9 +28,11 @@ import org.apache.dubbo.config.ProviderConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.context.ModuleConfigManager;
 import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
 import org.apache.dubbo.config.spring.registrycenter.RegistryCenter;
 import org.apache.dubbo.config.spring.registrycenter.ZookeeperMultipleRegistryCenter;
+import org.apache.dubbo.rpc.model.ModuleModel;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -87,6 +89,9 @@ public class SpringBootConfigPropsTest {
     @Autowired
     private ConfigManager configManager;
 
+    @Autowired
+    private ModuleModel moduleModel;
+
     @Test
     public void testConfigProps() {
 
@@ -126,10 +131,11 @@ public class SpringBootConfigPropsTest {
         Assertions.assertEquals("zookeeper://127.0.0.1:2182", reportConfig.getAddress());
         Assertions.assertEquals("User", reportConfig.getUsername());
 
-        ProviderConfig providerConfig = configManager.getDefaultProvider().get();
+        ModuleConfigManager moduleConfigManager = moduleModel.getConfigManager();
+        ProviderConfig providerConfig = moduleConfigManager.getDefaultProvider().get();
         Assertions.assertEquals("127.0.0.1", providerConfig.getHost());
 
-        ConsumerConfig consumerConfig = configManager.getDefaultConsumer().get();
+        ConsumerConfig consumerConfig = moduleConfigManager.getDefaultConsumer().get();
         Assertions.assertEquals("netty", consumerConfig.getClient());
 
     }
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
index 3e96c94..6aa8f65 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
@@ -28,9 +28,11 @@ import org.apache.dubbo.config.ProviderConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.context.ModuleConfigManager;
 import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
 import org.apache.dubbo.config.spring.registrycenter.RegistryCenter;
 import org.apache.dubbo.config.spring.registrycenter.ZookeeperMultipleRegistryCenter;
+import org.apache.dubbo.rpc.model.ModuleModel;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -86,6 +88,9 @@ public class SpringBootMultipleConfigPropsTest {
     @Autowired
     private ConfigManager configManager;
 
+    @Autowired
+    private ModuleModel moduleModel;
+
     @Test
     public void testConfigProps() {
 
@@ -125,10 +130,11 @@ public class SpringBootMultipleConfigPropsTest {
         Assertions.assertEquals("zookeeper://127.0.0.1:2182", reportConfig.getAddress());
         Assertions.assertEquals("User", reportConfig.getUsername());
 
-        ProviderConfig providerConfig = configManager.getDefaultProvider().get();
+        ModuleConfigManager moduleConfigManager = moduleModel.getConfigManager();
+        ProviderConfig providerConfig = moduleConfigManager.getDefaultProvider().get();
         Assertions.assertEquals("127.0.0.1", providerConfig.getHost());
 
-        ConsumerConfig consumerConfig = configManager.getDefaultConsumer().get();
+        ConsumerConfig consumerConfig = moduleConfigManager.getDefaultConsumer().get();
         Assertions.assertEquals("netty", consumerConfig.getClient());
 
     }
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java
index 08cb345..7522ba6 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java
@@ -21,8 +21,6 @@ import org.apache.dubbo.config.spring.api.DemoService;
 import org.apache.dubbo.config.spring.context.annotation.consumer.ConsumerConfiguration;
 import org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl;
 import org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration;
-import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
@@ -72,9 +70,8 @@ public class DubboComponentScanRegistrarTest {
         // Test @Transactional is present or not
         Assertions.assertNotNull(findAnnotation(beanClass, Transactional.class));
 
-        // reset ConfigManager of provider context
-        ApplicationModel.defaultModel().getApplicationConfigManager().destroy();
 
+        // consumer app
         AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
 
         consumerContext.register(ConsumerConfiguration.class);
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionInjectorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionInjectorTest.java
index 71e98d7..2589b1d 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionInjectorTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionInjectorTest.java
@@ -16,15 +16,14 @@
  */
 package org.apache.dubbo.config.spring.extension;
 
-import org.apache.dubbo.common.extension.ExtensionInjector;
-import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.config.bootstrap.DubboBootstrap;
 import org.apache.dubbo.config.spring.api.DemoService;
 import org.apache.dubbo.config.spring.api.HelloService;
+import org.apache.dubbo.config.spring.context.DubboSpringInitializer;
 import org.apache.dubbo.config.spring.impl.DemoServiceImpl;
 import org.apache.dubbo.config.spring.impl.HelloServiceImpl;
+import org.apache.dubbo.config.spring.util.DubboBeanUtils;
 import org.apache.dubbo.rpc.Protocol;
-
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
@@ -36,48 +35,38 @@ import org.springframework.context.annotation.Configuration;
 @Configuration
 public class SpringExtensionInjectorTest {
 
-    private SpringExtensionInjector springExtensionFactory = new SpringExtensionInjector();
-    private AnnotationConfigApplicationContext context1;
-    private AnnotationConfigApplicationContext context2;
 
     @BeforeEach
     public void init() {
         DubboBootstrap.reset();
-
-        // init SpringExtensionInjector
-        ExtensionLoader.getExtensionLoader(ExtensionInjector.class).getExtension("spring");
-
-        context1 = new AnnotationConfigApplicationContext();
-        context1.setDisplayName("Context1");
-        context1.register(getClass());
-        context1.refresh();
-        context2 = new AnnotationConfigApplicationContext();
-        context2.setDisplayName("Context2");
-        context2.register(BeanForContext2.class);
-        context2.refresh();
-        SpringExtensionInjector.addApplicationContext(context1);
-        SpringExtensionInjector.addApplicationContext(context2);
     }
 
     @AfterEach
     public void destroy() {
-        context1.close();
-        context2.close();
-        SpringExtensionInjector.clearContexts();
     }
 
     @Test
-    public void testGetExtensionBySPI() {
-        Protocol protocol = springExtensionFactory.getInstance(Protocol.class, "protocol");
-        Assertions.assertNull(protocol);
-    }
+    public void testSpringInjector() {
+        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+        try {
+            context.setDisplayName("Context1");
+            context.register(getClass());
+            context.refresh();
 
-    @Test
-    public void testGetExtensionByName() {
-        DemoService bean = springExtensionFactory.getInstance(DemoService.class, "bean1");
-        Assertions.assertNotNull(bean);
-        HelloService hello = springExtensionFactory.getInstance(HelloService.class, "hello");
-        Assertions.assertNotNull(hello);
+            // mock dubbo spring initialize
+            DubboSpringInitializer.initialize(context);
+
+            SpringExtensionInjector springExtensionInjector = SpringExtensionInjector.get(DubboBeanUtils.getApplicationModel(context));
+            Protocol protocol = springExtensionInjector.getInstance(Protocol.class, "protocol");
+            Assertions.assertNull(protocol);
+
+            DemoService bean = springExtensionInjector.getInstance(DemoService.class, "bean1");
+            Assertions.assertNotNull(bean);
+            HelloService hello = springExtensionInjector.getInstance(HelloService.class, "hello");
+            Assertions.assertNotNull(hello);
+        } finally {
+            context.close();
+        }
     }
 
     @Bean("bean1")
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/MethodCallbackImpl.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/MethodCallbackImpl.java
index a23923e..7f9a454 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/MethodCallbackImpl.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/impl/MethodCallbackImpl.java
@@ -23,9 +23,8 @@ import org.springframework.core.env.Environment;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.support.TransactionSynchronizationManager;
 
-import java.util.concurrent.atomic.AtomicInteger;
-
 import javax.annotation.PostConstruct;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class MethodCallbackImpl implements MethodCallback {
     private String onInvoke1 = "";
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/issue7003/Issue7003Test.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/issue7003/Issue7003Test.java
index 75d6b7a..0da499e 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/issue7003/Issue7003Test.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/issues/issue7003/Issue7003Test.java
@@ -25,7 +25,6 @@ import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
 import org.apache.dubbo.config.spring.registrycenter.RegistryCenter;
 import org.apache.dubbo.config.spring.registrycenter.ZookeeperSingleRegistryCenter;
 import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -73,7 +72,7 @@ public class Issue7003Test {
             Map<String, ReferenceBean> referenceBeanMap = context.getBeansOfType(ReferenceBean.class);
             Assertions.assertEquals(1, referenceBeanMap.size());
 
-            Collection<ReferenceConfigBase<?>> references = ApplicationModel.defaultModel().getApplicationConfigManager().getReferences();
+            Collection<ReferenceConfigBase<?>> references = ApplicationModel.defaultModel().getDefaultModule().getConfigManager().getReferences();
             Assertions.assertEquals(1, references.size());
 
         } finally {
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/PropertyConfigurerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/PropertyConfigurerTest.java
index c2ba2c4..571c8cd 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/PropertyConfigurerTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/PropertyConfigurerTest.java
@@ -21,8 +21,6 @@ import org.apache.dubbo.config.spring.api.HelloService;
 import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
 import org.apache.dubbo.config.spring.registrycenter.RegistryCenter;
 import org.apache.dubbo.config.spring.registrycenter.ZookeeperSingleRegistryCenter;
... 1898 lines suppressed ...