You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by vi...@apache.org on 2019/07/26 02:14:23 UTC

[dubbo] branch cloud-native updated: Dubbo cloud native (#4666)

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

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


The following commit(s) were added to refs/heads/cloud-native by this push:
     new 2691784  Dubbo cloud native (#4666)
2691784 is described below

commit 2691784703031158e712a751662e4bc48c94de71
Author: Mercy Ma <me...@gmail.com>
AuthorDate: Fri Jul 26 10:14:12 2019 +0800

    Dubbo cloud native (#4666)
---
 dubbo-bootstrap/pom.xml                            |   6 +
 .../dubbo/bootstrap/ApplicationSettings.java       | 127 -----
 .../org/apache/dubbo/bootstrap/DubboBootstrap.java | 394 +++++++------
 .../apache/dubbo/bootstrap/ProtocolSettings.java   | 215 -------
 .../apache/dubbo/bootstrap/ReferenceSettings.java  | 334 -----------
 .../apache/dubbo/bootstrap/RegistrySettings.java   | 164 ------
 .../apache/dubbo/bootstrap/ServiceSettings.java    | 384 -------------
 .../apache/dubbo/bootstrap/DubboBootstrapTest.java |  14 -
 .../bootstrap/DubboServiceConsumerBootstrap.java   |  35 +-
 .../bootstrap/DubboServiceProviderBootstrap.java   |  24 +-
 dubbo-common/pom.xml                               |   4 +
 .../config/configcenter/ConfigChangeEvent.java     |   6 +-
 .../config/configcenter/ConfigurationListener.java |   4 +-
 .../config/configcenter/DynamicConfiguration.java  | 105 +++-
 .../configcenter/DynamicConfigurationFactory.java  |  20 +-
 .../file/FileSystemDynamicConfiguration.java       | 628 +++++++++++++++++++++
 .../FileSystemDynamicConfigurationFactory.java     |  21 +-
 .../configcenter/nop/NopDynamicConfiguration.java  |   1 +
 .../nop/NopDynamicConfigurationFactory.java        |   1 +
 .../wrapper/CompositeDynamicConfiguration.java     |   3 -
 .../apache/dubbo/common/utils/ReflectUtils.java    |  30 +-
 ...config.configcenter.DynamicConfigurationFactory |   3 +-
 .../DynamicConfigurationFactoryTest.java           |  25 +-
 .../file/FileSystemDynamicConfigurationTest.java   | 169 ++++++
 dubbo-common/src/test/resources/log4j.xml          |   4 +-
 .../dubbo/config/AbstractInterfaceConfig.java      |  23 +-
 .../org/apache/dubbo/config/RegistryConfig.java    |  12 +-
 .../org/apache/dubbo/config/ServiceConfig.java     |  17 +-
 .../dubbo/config/builders/AbstractBuilder.java     |   2 +-
 .../apache/dubbo/config/context/ConfigManager.java | 433 +++++++-------
 .../metadata/ServiceInstancePortCustomizer.java    |   1 -
 .../dubbo/config/context/ConfigManagerTest.java    |  71 +++
 .../ConfigurableMetadataServiceExporterTest.java   |   4 +-
 .../resources/META-INF/spring/dubbo-provider.xml   |  16 +-
 .../support/nacos/NacosDynamicConfiguration.java   |  13 +-
 dubbo-dependencies-bom/pom.xml                     |  11 +-
 .../client/FileSystemServiceDiscovery.java         | 114 ++++
 37 files changed, 1704 insertions(+), 1734 deletions(-)

diff --git a/dubbo-bootstrap/pom.xml b/dubbo-bootstrap/pom.xml
index 17df134..e38e05d 100644
--- a/dubbo-bootstrap/pom.xml
+++ b/dubbo-bootstrap/pom.xml
@@ -90,6 +90,12 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java
deleted file mode 100644
index 23934f0..0000000
--- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ApplicationSettings.java
+++ /dev/null
@@ -1,127 +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.bootstrap;
-
-import org.apache.dubbo.config.ApplicationConfig;
-import org.apache.dubbo.config.MonitorConfig;
-import org.apache.dubbo.config.builders.ApplicationBuilder;
-
-import java.util.Map;
-
-/**
- * {@link ApplicationConfig Application} settings
- *
- * @since 2.7.4
- */
-public class ApplicationSettings extends AbstractSettings {
-
-    private final ApplicationBuilder builder;
-
-    public ApplicationSettings(ApplicationBuilder builder, DubboBootstrap dubboBootstrap) {
-        super(dubboBootstrap);
-        this.builder = builder;
-    }
-
-    public ApplicationSettings version(String version) {
-        builder.version(version);
-        return this;
-    }
-
-    public ApplicationSettings owner(String owner) {
-        builder.owner(owner);
-        return this;
-    }
-
-    public ApplicationSettings organization(String organization) {
-        builder.organization(organization);
-        return this;
-    }
-
-    public ApplicationSettings architecture(String architecture) {
-        builder.architecture(architecture);
-        return this;
-    }
-
-    public ApplicationSettings environment(String environment) {
-        builder.environment(environment);
-        return this;
-    }
-
-    public ApplicationSettings compiler(String compiler) {
-        builder.compiler(compiler);
-        return this;
-    }
-
-    public ApplicationSettings logger(String logger) {
-        builder.logger(logger);
-        return this;
-    }
-
-    public ApplicationSettings monitor(MonitorConfig monitor) {
-        builder.monitor(monitor);
-        return this;
-    }
-
-    public ApplicationSettings monitor(String monitor) {
-        builder.monitor(monitor);
-        return this;
-    }
-
-    public ApplicationSettings isDefault(Boolean isDefault) {
-        builder.isDefault(isDefault);
-        return this;
-    }
-
-    public ApplicationSettings dumpDirectory(String dumpDirectory) {
-        builder.dumpDirectory(dumpDirectory);
-        return this;
-    }
-
-    public ApplicationSettings qosEnable(Boolean qosEnable) {
-        builder.qosEnable(qosEnable);
-        return this;
-    }
-
-    public ApplicationSettings qosPort(Integer qosPort) {
-        builder.qosPort(qosPort);
-        return this;
-    }
-
-    public ApplicationSettings qosAcceptForeignIp(Boolean qosAcceptForeignIp) {
-        builder.qosAcceptForeignIp(qosAcceptForeignIp);
-        return this;
-    }
-
-    public ApplicationSettings shutwait(String shutwait) {
-        builder.shutwait(shutwait);
-        return this;
-    }
-
-    public ApplicationSettings appendParameter(String key, String value) {
-        builder.appendParameter(key, value);
-        return this;
-    }
-
-    public ApplicationSettings appendParameters(Map<String, String> appendParameters) {
-        builder.appendParameters(appendParameters);
-        return this;
-    }
-
-    ApplicationConfig build() {
-        return builder.build();
-    }
-}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java
index d20e3e0..6a2237f 100644
--- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java
@@ -19,14 +19,11 @@ package org.apache.dubbo.bootstrap;
 import org.apache.dubbo.common.URL;
 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.ExtensionLoader;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.AbstractConfig;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.ConfigCenterConfig;
@@ -59,7 +56,7 @@ import org.apache.dubbo.registry.support.ServiceOrientedRegistry;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -71,9 +68,13 @@ import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
+import static java.util.Arrays.asList;
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties;
+import static org.apache.dubbo.common.config.configcenter.DynamicConfiguration.getDynamicConfiguration;
 import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
+import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
+import static org.apache.dubbo.config.context.ConfigManager.getInstance;
 import static org.apache.dubbo.registry.support.AbstractRegistryFactory.getRegistries;
 
 /**
@@ -91,6 +92,10 @@ public class DubboBootstrap {
 
     public static final String DEFAULT_REFERENCE_ID = "REFERENCE#DEFAULT";
 
+    public static final String DEFAULT_PROVIDER_ID = "PROVIDER#DEFAULT";
+
+    public static final String DEFAULT_CONSUMER_ID = "CONSUMER#DEFAULT";
+
     private static final String NAME = DubboBootstrap.class.getSimpleName();
 
     private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -105,6 +110,8 @@ public class DubboBootstrap {
 
     private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
 
+    private final ConfigManager configManager = getInstance();
+
     /**
      * Is provider or not
      */
@@ -121,20 +128,6 @@ public class DubboBootstrap {
 
     private ServiceInstance serviceInstance;
 
-    private ApplicationBuilder applicationBuilder;
-
-    private ConsumerBuilder consumerBuilder;
-
-    private ProviderBuilder providerBuilder;
-
-    private Map<String, RegistryBuilder> registryBuilders = new HashMap<>();
-
-    private Map<String, ProtocolBuilder> protocolBuilders = new HashMap<>();
-
-    private Map<String, ServiceBuilder<?>> serviceBuilders = new HashMap<>();
-
-    private Map<String, ReferenceBuilder<?>> referenceBuilders = new HashMap<>();
-
     public DubboBootstrap() {
         DubboShutdownHook.getDubboShutdownHook().register();
     }
@@ -150,96 +143,205 @@ public class DubboBootstrap {
         return this;
     }
 
-    /* accept Config instance */
-    public DubboBootstrap application(ApplicationConfig applicationConfig) {
-        ConfigManager.getInstance().setApplication(applicationConfig);
+    public DubboBootstrap metadataReport(MetadataReportConfig metadataReportConfig) {
+        configManager.addMetadataReport(metadataReportConfig);
         return this;
     }
 
-    public DubboBootstrap configCenter(ConfigCenterConfig configCenterConfig) {
-        ConfigManager.getInstance().addConfigCenter(configCenterConfig);
+    public DubboBootstrap metadataReport(List<MetadataReportConfig> metadataReportConfigs) {
+        configManager.addMetadataReports(metadataReportConfigs);
         return this;
     }
 
-    public DubboBootstrap configCenter(List<ConfigCenterConfig> configCenterConfigs) {
-        ConfigManager.getInstance().addConfigCenter(configCenterConfigs);
-        return this;
+    // {@link ApplicationConfig} correlative methods
+
+    /**
+     * Set the name of application
+     *
+     * @param name the name of application
+     * @return current {@link DubboBootstrap} instance
+     */
+    public DubboBootstrap application(String name) {
+        return application(name, builder -> {
+            // DO NOTHING
+        });
     }
 
-    public DubboBootstrap metadataReport(MetadataReportConfig metadataReportConfig) {
-        ConfigManager.getInstance().addMetadataReport(metadataReportConfig);
-        return this;
+    /**
+     * Set the name of application and it's future build
+     *
+     * @param name            the name of application
+     * @param consumerBuilder {@link ApplicationBuilder}
+     * @return current {@link DubboBootstrap} instance
+     */
+    public DubboBootstrap application(String name, Consumer<ApplicationBuilder> consumerBuilder) {
+        ApplicationBuilder builder = createApplicationBuilder(name);
+        consumerBuilder.accept(builder);
+        return application(builder.build());
     }
 
-    public DubboBootstrap metadataReport(List<MetadataReportConfig> metadataReportConfigs) {
-        ConfigManager.getInstance().addMetadataReport(metadataReportConfigs);
+    /**
+     * Set the {@link ApplicationConfig}
+     *
+     * @param applicationConfig the {@link ApplicationConfig}
+     * @return current {@link DubboBootstrap} instance
+     */
+    public DubboBootstrap application(ApplicationConfig applicationConfig) {
+        configManager.setApplication(applicationConfig);
         return this;
     }
 
+    // {@link RegistryConfig} correlative methods
+
+    /**
+     * Add an instance of {@link RegistryConfig} with {@link #DEFAULT_REGISTRY_ID default ID}
+     *
+     * @param consumerBuilder the {@link Consumer} of {@link RegistryBuilder}
+     * @return current {@link DubboBootstrap} instance
+     */
+    public DubboBootstrap registry(Consumer<RegistryBuilder> consumerBuilder) {
+        return registry(DEFAULT_REGISTRY_ID, consumerBuilder);
+    }
+
+    /**
+     * Add an instance of {@link RegistryConfig} with the specified ID
+     *
+     * @param id              the {@link RegistryConfig#getId() id}  of {@link RegistryConfig}
+     * @param consumerBuilder the {@link Consumer} of {@link RegistryBuilder}
+     * @return current {@link DubboBootstrap} instance
+     */
+    public DubboBootstrap registry(String id, Consumer<RegistryBuilder> consumerBuilder) {
+        RegistryBuilder builder = createRegistryBuilder(id);
+        consumerBuilder.accept(builder);
+        return registry(builder.build());
+    }
+
+    /**
+     * Add an instance of {@link RegistryConfig}
+     *
+     * @param registryConfig an instance of {@link RegistryConfig}
+     * @return current {@link DubboBootstrap} instance
+     */
     public DubboBootstrap registry(RegistryConfig registryConfig) {
-        ConfigManager.getInstance().addRegistry(registryConfig, true);
+        configManager.addRegistry(registryConfig);
         return this;
     }
 
-    public DubboBootstrap registry(List<RegistryConfig> registryConfigs) {
-        ConfigManager.getInstance().addRegistries(registryConfigs, true);
+    /**
+     * Add an instance of {@link RegistryConfig}
+     *
+     * @param registryConfigs the multiple instances of {@link RegistryConfig}
+     * @return current {@link DubboBootstrap} instance
+     */
+    public DubboBootstrap registries(Iterable<RegistryConfig> registryConfigs) {
+        registryConfigs.forEach(this::registry);
         return this;
     }
 
+    // {@link ProtocolConfig} correlative methods
+
+    public DubboBootstrap protocol(Consumer<ProtocolBuilder> consumerBuilder) {
+        return protocol(DEFAULT_PROTOCOL_ID, consumerBuilder);
+    }
+
+    public DubboBootstrap protocol(String id, Consumer<ProtocolBuilder> consumerBuilder) {
+        ProtocolBuilder builder = createProtocolBuilder(id);
+        consumerBuilder.accept(builder);
+        return protocol(builder.build());
+    }
+
     public DubboBootstrap protocol(ProtocolConfig protocolConfig) {
-        ConfigManager.getInstance().addProtocol(protocolConfig, true);
-        return this;
+        return protocols(asList(protocolConfig));
     }
 
     public DubboBootstrap protocols(List<ProtocolConfig> protocolConfigs) {
-        ConfigManager.getInstance().addProtocols(protocolConfigs, true);
+        configManager.addProtocols(protocolConfigs, true);
         return this;
     }
 
-    public DubboBootstrap consumer(ConsumerConfig consumerConfig) {
-        ConfigManager.getInstance().addConsumer(consumerConfig);
-        return this;
+    // {@link ServiceConfig} correlative methods
+
+    public <S> DubboBootstrap service(Consumer<ServiceBuilder<S>> consumerBuilder) {
+        return service(DEFAULT_SERVICE_ID, consumerBuilder);
     }
 
-    public DubboBootstrap provider(ProviderConfig providerConfig) {
-        ConfigManager.getInstance().addProvider(providerConfig);
-        return this;
+    public <S> DubboBootstrap service(String id, Consumer<ServiceBuilder<S>> consumerBuilder) {
+        ServiceBuilder builder = createServiceBuilder(id);
+        consumerBuilder.accept(builder);
+        return service(builder.build());
     }
 
     public DubboBootstrap service(ServiceConfig<?> serviceConfig) {
-        ConfigManager.getInstance().addService(serviceConfig);
+        configManager.addService(serviceConfig);
         return this;
     }
 
+    // {@link Reference} correlative methods
+
+    public <S> DubboBootstrap reference(Consumer<ReferenceBuilder<S>> consumerBuilder) {
+        return reference(DEFAULT_REFERENCE_ID, consumerBuilder);
+    }
+
+    public <S> DubboBootstrap reference(String id, Consumer<ReferenceBuilder<S>> consumerBuilder) {
+        ReferenceBuilder builder = createReferenceBuilder(id);
+        consumerBuilder.accept(builder);
+        return reference(builder.build());
+    }
+
     public DubboBootstrap reference(ReferenceConfig<?> referenceConfig) {
-        ConfigManager.getInstance().addReference(referenceConfig);
+        configManager.addReference(referenceConfig);
         return this;
     }
 
-    /* accept builder functional interface */
-    public DubboBootstrap application(String name, Consumer<ApplicationBuilder> builder) {
-        initApplicationBuilder(name);
-        builder.accept(applicationBuilder);
-        return this;
+    // {@link ProviderConfig} correlative methods
+
+    public DubboBootstrap provider(Consumer<ProviderBuilder> builderConsumer) {
+        return provider(DEFAULT_PROVIDER_ID, builderConsumer);
     }
 
-    public DubboBootstrap registry(String id, Consumer<RegistryBuilder> builder) {
-        builder.accept(initRegistryBuilder(id));
-        return this;
+    public DubboBootstrap provider(String id, Consumer<ProviderBuilder> builderConsumer) {
+        ProviderBuilder builder = createProviderBuilder(id);
+        builderConsumer.accept(builder);
+        return provider(builder.build());
+    }
+
+    public DubboBootstrap provider(ProviderConfig providerConfig) {
+        return providers(asList(providerConfig));
     }
 
-    public DubboBootstrap protocol(String id, Consumer<ProtocolBuilder> builder) {
-        builder.accept(initProtocolBuilder(id));
+    public DubboBootstrap providers(List<ProviderConfig> providerConfigs) {
+        providerConfigs.forEach(configManager::addProvider);
         return this;
     }
 
-    public <S> DubboBootstrap service(String id, Consumer<ServiceBuilder<S>> builder) {
-        builder.accept(initServiceBuilder(id));
+    // {@link ConsumerConfig} correlative methods
+
+    public DubboBootstrap consumer(Consumer<ConsumerBuilder> builderConsumer) {
+        return consumer(DEFAULT_CONSUMER_ID, builderConsumer);
+    }
+
+    public DubboBootstrap consumer(String id, Consumer<ConsumerBuilder> builderConsumer) {
+        ConsumerBuilder builder = createConsumerBuilder(id);
+        builderConsumer.accept(builder);
+        return consumer(builder.build());
+    }
+
+    public DubboBootstrap consumer(ConsumerConfig consumerConfig) {
+        return consumers(asList(consumerConfig));
+    }
+
+    public DubboBootstrap consumers(List<ConsumerConfig> consumerConfigs) {
+        consumerConfigs.forEach(configManager::addConsumer);
         return this;
     }
 
-    public <S> DubboBootstrap reference(String id, Consumer<ReferenceBuilder<S>> builder) {
-        builder.accept(initReferenceBuilder(id));
+    // {@link ConfigCenterConfig} correlative methods
+    public DubboBootstrap configCenter(ConfigCenterConfig configCenterConfig) {
+        return configCenter(asList(configCenterConfig));
+    }
+
+    public DubboBootstrap configCenter(List<ConfigCenterConfig> configCenterConfigs) {
+        configManager.addConfigCenters(configCenterConfigs);
         return this;
     }
 
@@ -252,30 +354,13 @@ public class DubboBootstrap {
             return;
         }
 
-        buildApplicationConfig();
-
-        buildRegistryConfigs();
-
-        buildProtocolConfigs();
-
-        buildServiceConfigs();
-
-        buildReferenceConfigs();
-
-        clearBuilders();
-
         startConfigCenter();
+
         startMetadataReport();
 
         loadRemoteConfigs();
-        useRegistryAsConfigCenterIfNecessary();
 
-//        checkApplication();
-//        checkProvider();
-//        chcckConsumer();
-//        checkRegistry();
-//        checkProtocol();
-//        checkMonitor();
+        useRegistryAsConfigCenterIfNecessary();
 
         initialized = true;
 
@@ -285,8 +370,6 @@ public class DubboBootstrap {
     }
 
     private void loadRemoteConfigs() {
-        ConfigManager configManager = ConfigManager.getInstance();
-
         // registry ids to registry configs
         List<RegistryConfig> tmpRegistries = new ArrayList<>();
         Set<String> registryIds = configManager.getRegistryIds();
@@ -301,7 +384,7 @@ public class DubboBootstrap {
             }
         });
 
-        configManager.addRegistries(tmpRegistries, true);
+        configManager.addRegistries(tmpRegistries);
 
         // protocol ids to protocol configs
         List<ProtocolConfig> tmpProtocols = new ArrayList<>();
@@ -325,26 +408,26 @@ public class DubboBootstrap {
      * there's no config center specified explicitly.
      */
     private void useRegistryAsConfigCenterIfNecessary() {
-        ConfigManager configManager = ConfigManager.getInstance();
-        configManager.getDefaultRegistries().ifPresent(registryConfigs -> {
-            for (RegistryConfig registryConfig : registryConfigs) {
-                if (registryConfig != null && registryConfig.isZookeeperProtocol()) {
-                    // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated.
-                    Environment.getInstance().getDynamicConfiguration().orElseGet(() -> {
-                        Set<ConfigCenterConfig> configCenters = configManager.getConfigCenters();
-                        if (CollectionUtils.isEmpty(configCenters)) {
-                            ConfigCenterConfig cc = new ConfigCenterConfig();
-                            cc.setProtocol(registryConfig.getProtocol());
-                            cc.setAddress(registryConfig.getAddress());
-                            cc.setHighestPriority(false);
-                            configManager.addConfigCenter(cc);
-                        }
-                        return null;
-                    });
-                }
-            }
-            startConfigCenter();
+        // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated.
+        if (Environment.getInstance().getDynamicConfiguration().isPresent()) {
+            return;
+        }
+
+        if (CollectionUtils.isNotEmpty(configManager.getConfigCenters())) {
+            return;
+        }
+
+        configManager.getRegistries().forEach(registryConfig -> {
+            String protocol = registryConfig.getProtocol();
+            String id = "config-center-" + protocol + "-" + registryConfig.getPort();
+            ConfigCenterConfig cc = new ConfigCenterConfig();
+            cc.setId(id);
+            cc.setProtocol(protocol);
+            cc.setAddress(registryConfig.getAddress());
+            cc.setHighestPriority(false);
+            configManager.addConfigCenter(cc);
         });
+        startConfigCenter();
     }
 
     private List<ServiceDiscovery> getServiceDiscoveries() {
@@ -369,16 +452,15 @@ public class DubboBootstrap {
             exportServices();
 
             // Not only provider register and some services are exported
-            if (!onlyRegisterProvider && !ConfigManager.getInstance().getServiceConfigs().isEmpty()) {
+            if (!onlyRegisterProvider && !configManager.getServiceConfigs().isEmpty()) {
                 /**
                  * export {@link MetadataService}
                  */
-                ConfigManager configManager = ConfigManager.getInstance();
                 // TODO, only export to default registry?
-                List<URL> exportedURLs = exportMetadataService (
+                List<URL> exportedURLs = exportMetadataService(
                         configManager.getApplication().orElseThrow(() -> new IllegalStateException("ApplicationConfig cannot be null")),
-                        configManager.getDefaultRegistries().orElseThrow(() -> new IllegalStateException("No default RegistryConfig")),
-                        configManager.getDefaultProtocols().orElseThrow(() -> new IllegalStateException("No default ProtocolConfig"))
+                        configManager.getRegistries(),
+                        configManager.getProtocols()
                 );
 
                 /**
@@ -450,10 +532,10 @@ public class DubboBootstrap {
         return started;
     }
 
+
     /* serve for builder apis, begin */
-    private ApplicationBuilder initApplicationBuilder(String name) {
-        applicationBuilder = new ApplicationBuilder().name(name);
-        return applicationBuilder;
+    private ApplicationBuilder createApplicationBuilder(String name) {
+        return new ApplicationBuilder().name(name);
     }
 
     private RegistryBuilder createRegistryBuilder(String id) {
@@ -472,29 +554,21 @@ public class DubboBootstrap {
         return new ReferenceBuilder().id(id);
     }
 
-    private RegistryBuilder initRegistryBuilder(String id) {
-        return registryBuilders.computeIfAbsent(id, this::createRegistryBuilder);
-    }
-
-    private ProtocolBuilder initProtocolBuilder(String id) {
-        return protocolBuilders.computeIfAbsent(id, this::createProtocolBuilder);
-    }
-
-    private ServiceBuilder initServiceBuilder(String id) {
-        return serviceBuilders.computeIfAbsent(id, this::createServiceBuilder);
+    private ProviderBuilder createProviderBuilder(String id) {
+        return new ProviderBuilder().id(id);
     }
 
-    private ReferenceBuilder initReferenceBuilder(String id) {
-        return referenceBuilders.computeIfAbsent(id, this::createReferenceBuilder);
+    private ConsumerBuilder createConsumerBuilder(String id) {
+        return new ConsumerBuilder().id(id);
     }
 
     /* serve for builder apis, end */
 
     private void startMetadataReport() {
-        ApplicationConfig applicationConfig = ConfigManager.getInstance().getApplication().orElseThrow(() -> new IllegalStateException("There's no ApplicationConfig specified."));
+        ApplicationConfig applicationConfig = configManager.getApplication().orElseThrow(() -> new IllegalStateException("There's no ApplicationConfig specified."));
 
         // FIXME, multiple metadata config support.
-        Set<MetadataReportConfig> metadataReportConfigs = ConfigManager.getInstance().getMetadataConfigs();
+        Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();
         if (CollectionUtils.isEmpty(metadataReportConfigs)) {
             if (CommonConstants.METADATA_REMOTE.equals(applicationConfig.getMetadata())) {
                 throw new IllegalStateException("No MetadataConfig found, you must specify the remote Metadata Center address when set 'metadata=remote'.");
@@ -512,7 +586,7 @@ public class DubboBootstrap {
     }
 
     private void startConfigCenter() {
-        Set<ConfigCenterConfig> configCenters = ConfigManager.getInstance().getConfigCenters();
+        Collection<ConfigCenterConfig> configCenters = configManager.getConfigCenters();
 
         if (CollectionUtils.isNotEmpty(configCenters)) {
             CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();
@@ -522,7 +596,7 @@ public class DubboBootstrap {
             }
             Environment.getInstance().setDynamicConfiguration(compositeDynamicConfiguration);
         }
-        ConfigManager.getInstance().refreshAll();
+        configManager.refreshAll();
     }
 
     private DynamicConfiguration prepareEnvironment(ConfigCenterConfig configCenter) {
@@ -533,11 +607,11 @@ public class DubboBootstrap {
             DynamicConfiguration dynamicConfiguration = getDynamicConfiguration(configCenter.toUrl());
             String configContent = dynamicConfiguration.getConfigs(configCenter.getConfigFile(), configCenter.getGroup());
 
-            String appGroup = ConfigManager.getInstance().getApplication().orElse(new ApplicationConfig()).getName();
+            String appGroup = configManager.getApplication().orElse(new ApplicationConfig()).getName();
             String appConfigContent = null;
-            if (StringUtils.isNotEmpty(appGroup)) {
+            if (isNotEmpty(appGroup)) {
                 appConfigContent = dynamicConfiguration.getConfigs
-                        (StringUtils.isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(),
+                        (isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(),
                                 appGroup
                         );
             }
@@ -553,13 +627,6 @@ public class DubboBootstrap {
         return null;
     }
 
-    private DynamicConfiguration getDynamicConfiguration(URL url) {
-        DynamicConfigurationFactory factory = ExtensionLoader
-                .getExtensionLoader(DynamicConfigurationFactory.class)
-                .getExtension(url.getProtocol());
-        return factory.getDynamicConfiguration(url);
-    }
-
     /**
      * Add an instance of {@link EventListener}
      *
@@ -572,8 +639,8 @@ public class DubboBootstrap {
     }
 
     private List<URL> exportMetadataService(ApplicationConfig applicationConfig,
-                                            List<RegistryConfig> globalRegistryConfigs,
-                                            List<ProtocolConfig> globalProtocolConfigs) {
+                                            Collection<RegistryConfig> globalRegistryConfigs,
+                                            Collection<ProtocolConfig> globalProtocolConfigs) {
         ConfigurableMetadataServiceExporter exporter = new ConfigurableMetadataServiceExporter();
         exporter.setApplicationConfig(applicationConfig);
         exporter.setRegistries(globalRegistryConfigs);
@@ -581,36 +648,8 @@ public class DubboBootstrap {
         return exporter.export();
     }
 
-    private void buildApplicationConfig() {
-        ApplicationConfig applicationConfig = null;
-        if (applicationBuilder != null) {
-            applicationConfig = applicationBuilder.build();
-        }
-        ConfigManager.getInstance().setApplication(applicationConfig);
-    }
-
-    private void buildProtocolConfigs() {
-        List<ProtocolConfig> protocolConfigs = buildConfigs(protocolBuilders);
-        ConfigManager.getInstance().addProtocols(protocolConfigs, true);
-    }
-
-    private void buildRegistryConfigs() {
-        List<RegistryConfig> registryConfigs = buildConfigs(registryBuilders);
-        ConfigManager.getInstance().addRegistries(registryConfigs, true);
-    }
-
-    private void buildServiceConfigs() {
-        List<ServiceConfig<?>> serviceConfigs = buildConfigs(serviceBuilders);
-        serviceConfigs.forEach(ConfigManager.getInstance()::addService);
-    }
-
-    private void buildReferenceConfigs() {
-        List<ReferenceConfig<?>> referenceConfigs = buildConfigs(referenceBuilders);
-        referenceConfigs.forEach(ConfigManager.getInstance()::addReference);
-    }
-
     private void exportServices() {
-        ConfigManager.getInstance().getServiceConfigs().forEach(this::exportServiceConfig);
+        configManager.getServiceConfigs().forEach(this::exportServiceConfig);
     }
 
     public void exportServiceConfig(ServiceConfig<?> serviceConfig) {
@@ -658,46 +697,30 @@ public class DubboBootstrap {
     }
 
     private void destroyProtocolConfigs() {
-        ConfigManager.getInstance().getProtocols().values().forEach(ProtocolConfig::destroy);
+        configManager.getProtocols().forEach(ProtocolConfig::destroy);
         if (logger.isDebugEnabled()) {
             logger.debug(NAME + "'s all ProtocolConfigs have been destroyed.");
         }
     }
 
     private void destroyReferenceConfigs() {
-        ConfigManager.getInstance().getReferenceConfigs().forEach(ReferenceConfig::destroy);
+        configManager.getReferenceConfigs().forEach(ReferenceConfig::destroy);
         if (logger.isDebugEnabled()) {
             logger.debug(NAME + "'s all ReferenceConfigs have been destroyed.");
         }
     }
 
     private void clear() {
-
-        clearBuilders();
-
         clearConfigs();
-
-        ConfigManager.getInstance().clear();
     }
 
     private void clearConfigs() {
-        ConfigManager.getInstance().clear();
+        configManager.clear();
         if (logger.isDebugEnabled()) {
             logger.debug(NAME + "'s configs have been clear.");
         }
     }
 
-    private void clearBuilders() {
-        this.applicationBuilder = null;
-        this.registryBuilders.clear();
-        this.protocolBuilders.clear();
-        this.serviceBuilders.clear();
-        this.referenceBuilders.clear();
-        if (logger.isDebugEnabled()) {
-            logger.debug(NAME + "'s builders have been clear.");
-        }
-    }
-
     private void release() {
         executeMutually(() -> {
             while (awaited.compareAndSet(false, true)) {
@@ -725,7 +748,8 @@ public class DubboBootstrap {
         }
     }
 
-    private static <C extends AbstractConfig, B extends AbstractBuilder> List<C> buildConfigs(Map<String, B> map) {
+    private static <C extends AbstractConfig, B extends
+            AbstractBuilder> List<C> buildConfigs(Map<String, B> map) {
         List<C> configs = new ArrayList<>();
         map.entrySet().forEach(entry -> {
             configs.add((C) entry.getValue().build());
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java
deleted file mode 100644
index 5fc49ca..0000000
--- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ProtocolSettings.java
+++ /dev/null
@@ -1,215 +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.bootstrap;
-
-import org.apache.dubbo.config.ProtocolConfig;
-import org.apache.dubbo.config.builders.ProtocolBuilder;
-
-import java.util.Map;
-
-/**
- * The settings of {@link ProtocolConfig protcol}
- *
- * @see ProtocolBuilder
- * @since 2.7.4
- */
-public class ProtocolSettings extends AbstractSettings {
-
-    private final ProtocolBuilder builder;
-
-    public ProtocolSettings(ProtocolBuilder builder, DubboBootstrap dubboBootstrap) {
-        super(dubboBootstrap);
-        this.builder = builder;
-    }
-
-    public ProtocolSettings name(String name) {
-        builder.name(name);
-        return this;
-    }
-
-    public ProtocolSettings host(String host) {
-        builder.host(host);
-        return this;
-    }
-
-    public ProtocolSettings port(Integer port) {
-        builder.port(port);
-        return this;
-    }
-
-    public ProtocolSettings contextpath(String contextpath) {
-        builder.contextpath(contextpath);
-        return this;
-    }
-
-    @Deprecated
-    public ProtocolSettings path(String path) {
-        builder.path(path);
-        return this;
-    }
-
-    public ProtocolSettings threadpool(String threadpool) {
-        builder.threadpool(threadpool);
-        return this;
-    }
-
-    public ProtocolSettings corethreads(Integer corethreads) {
-        builder.corethreads(corethreads);
-        return this;
-    }
-
-    public ProtocolSettings threads(Integer threads) {
-        builder.threads(threads);
-        return this;
-    }
-
-    public ProtocolSettings iothreads(Integer iothreads) {
-        builder.iothreads(iothreads);
-        return this;
-    }
-
-    public ProtocolSettings queues(Integer queues) {
-        builder.queues(queues);
-        return this;
-    }
-
-    public ProtocolSettings accepts(Integer accepts) {
-        builder.accepts(accepts);
-        return this;
-    }
-
-    public ProtocolSettings codec(String codec) {
-        builder.codec(codec);
-        return this;
-    }
-
-    public ProtocolSettings serialization(String serialization) {
-        builder.serialization(serialization);
-        return this;
-    }
-
-    public ProtocolSettings charset(String charset) {
-        builder.charset(charset);
-        return this;
-    }
-
-    public ProtocolSettings payload(Integer payload) {
-        builder.payload(payload);
-        return this;
-    }
-
-    public ProtocolSettings buffer(Integer buffer) {
-        builder.buffer(buffer);
-        return this;
-    }
-
-    public ProtocolSettings heartbeat(Integer heartbeat) {
-        builder.heartbeat(heartbeat);
-        return this;
-    }
-
-    public ProtocolSettings accesslog(String accesslog) {
-        builder.accesslog(accesslog);
-        return this;
-    }
-
-    public ProtocolSettings transporter(String transporter) {
-        builder.transporter(transporter);
-        return this;
-    }
-
-    public ProtocolSettings exchanger(String exchanger) {
-        builder.exchanger(exchanger);
-        return this;
-    }
-
-    public ProtocolSettings dispatcher(String dispatcher) {
-        builder.dispatcher(dispatcher);
-        return this;
-    }
-
-    @Deprecated
-    public ProtocolSettings dispather(String dispather) {
-        builder.dispather(dispather);
-        return this;
-    }
-
-    public ProtocolSettings networker(String networker) {
-        builder.networker(networker);
-        return this;
-    }
-
-    public ProtocolSettings server(String server) {
-        builder.server(server);
-        return this;
-    }
-
-    public ProtocolSettings client(String client) {
-        builder.client(client);
-        return this;
-    }
-
-    public ProtocolSettings telnet(String telnet) {
-        builder.telnet(telnet);
-        return this;
-    }
-
-    public ProtocolSettings prompt(String prompt) {
-        builder.prompt(prompt);
-        return this;
-    }
-
-    public ProtocolSettings status(String status) {
-        builder.status(status);
-        return this;
-    }
-
-    public ProtocolSettings register(Boolean register) {
-        builder.register(register);
-        return this;
-    }
-
-    public ProtocolSettings keepAlive(Boolean keepAlive) {
-        builder.keepAlive(keepAlive);
-        return this;
-    }
-
-    public ProtocolSettings optimizer(String optimizer) {
-        builder.optimizer(optimizer);
-        return this;
-    }
-
-    public ProtocolSettings extension(String extension) {
-        builder.extension(extension);
-        return this;
-    }
-
-    public ProtocolSettings appendParameter(String key, String value) {
-        builder.appendParameter(key, value);
-        return this;
-    }
-
-    public ProtocolSettings appendParameters(Map<String, String> appendParameters) {
-        builder.appendParameters(appendParameters);
-        return this;
-    }
-
-    public ProtocolSettings isDefault(Boolean isDefault) {
-        builder.isDefault(isDefault);
-        return this;
-    }
-}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java
deleted file mode 100644
index bb24e6e..0000000
--- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ReferenceSettings.java
+++ /dev/null
@@ -1,334 +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.bootstrap;
-
-import org.apache.dubbo.config.ApplicationConfig;
-import org.apache.dubbo.config.ConfigCenterConfig;
-import org.apache.dubbo.config.ConsumerConfig;
-import org.apache.dubbo.config.MetadataReportConfig;
-import org.apache.dubbo.config.MethodConfig;
-import org.apache.dubbo.config.ModuleConfig;
-import org.apache.dubbo.config.MonitorConfig;
-import org.apache.dubbo.config.ReferenceConfig;
-import org.apache.dubbo.config.RegistryConfig;
-import org.apache.dubbo.config.builders.ReferenceBuilder;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * The settings of {@link ReferenceConfig}
- *
- * @since 2.7.4
- */
-public class ReferenceSettings<S> extends AbstractSettings {
-
-    private final ReferenceBuilder<S> builder;
-
-    public ReferenceSettings(ReferenceBuilder<S> builder, DubboBootstrap dubboBootstrap) {
-        super(dubboBootstrap);
-        this.builder = builder;
-    }
-
-    public ReferenceSettings<S> interfaceName(String interfaceName) {
-        builder.interfaceName(interfaceName);
-        return this;
-    }
-
-    public ReferenceSettings<S> interfaceClass(Class<?> interfaceClass) {
-        builder.interfaceClass(interfaceClass);
-        return this;
-    }
-
-    public ReferenceSettings<S> client(String client) {
-        builder.client(client);
-        return this;
-    }
-
-    public ReferenceSettings<S> url(String url) {
-        builder.url(url);
-        return this;
-    }
-
-    public ReferenceSettings<S> addMethods(List<MethodConfig> methods) {
-        builder.addMethods(methods);
-        return this;
-    }
-
-    public ReferenceSettings<S> addMethod(MethodConfig method) {
-        builder.addMethod(method);
-        return this;
-    }
-
-    public ReferenceSettings<S> consumer(ConsumerConfig consumer) {
-        builder.consumer(consumer);
-        return this;
-    }
-
-    public ReferenceSettings<S> protocol(String protocol) {
-        builder.protocol(protocol);
-        return this;
-    }
-
-    public ReferenceSettings<S> check(Boolean check) {
-        builder.check(check);
-        return this;
-    }
-
-    public ReferenceSettings<S> init(Boolean init) {
-        builder.init(init);
-        return this;
-    }
-
-    public ReferenceSettings<S> generic(String generic) {
-        builder.generic(generic);
-        return this;
-    }
-
-    public ReferenceSettings<S> generic(Boolean generic) {
-        builder.generic(generic);
-        return this;
-    }
-
-    @Deprecated
-    public ReferenceSettings<S> injvm(Boolean injvm) {
-        builder.injvm(injvm);
-        return this;
-    }
-
-    public ReferenceSettings<S> lazy(Boolean lazy) {
-        builder.lazy(lazy);
-        return this;
-    }
-
-    public ReferenceSettings<S> reconnect(String reconnect) {
-        builder.reconnect(reconnect);
-        return this;
-    }
-
-    public ReferenceSettings<S> sticky(Boolean sticky) {
-        builder.sticky(sticky);
-        return this;
-    }
-
-    public ReferenceSettings<S> version(String version) {
-        builder.version(version);
-        return this;
-    }
-
-    public ReferenceSettings<S> group(String group) {
-        builder.group(group);
-        return this;
-    }
-
-    @Deprecated
-    public ReferenceSettings<S> local(String local) {
-        builder.local(local);
-        return this;
-    }
-
-    @Deprecated
-    public ReferenceSettings<S> local(Boolean local) {
-        builder.local(local);
-        return this;
-    }
-
-    public ReferenceSettings<S> stub(String stub) {
-        builder.stub(stub);
-        return this;
-    }
-
-    public ReferenceSettings<S> stub(Boolean stub) {
-        builder.stub(stub);
-        return this;
-    }
-
-    public ReferenceSettings<S> monitor(MonitorConfig monitor) {
-        builder.monitor(monitor);
-        return this;
-    }
-
-    public ReferenceSettings<S> monitor(String monitor) {
-        builder.monitor(monitor);
-        return this;
-    }
-
-    public ReferenceSettings<S> proxy(String proxy) {
-        builder.proxy(proxy);
-        return this;
-    }
-
-    public ReferenceSettings<S> cluster(String cluster) {
-        builder.cluster(cluster);
-        return this;
-    }
-
-    public ReferenceSettings<S> filter(String filter) {
-        builder.filter(filter);
-        return this;
-    }
-
-    public ReferenceSettings<S> listener(String listener) {
-        builder.listener(listener);
-        return this;
-    }
-
-    public ReferenceSettings<S> owner(String owner) {
-        builder.owner(owner);
-        return this;
-    }
-
-    public ReferenceSettings<S> connections(Integer connections) {
-        builder.connections(connections);
-        return this;
-    }
-
-    public ReferenceSettings<S> layer(String layer) {
-        builder.layer(layer);
-        return this;
-    }
-
-    public ReferenceSettings<S> application(ApplicationConfig application) {
-        builder.application(application);
-        return this;
-    }
-
-    public ReferenceSettings<S> module(ModuleConfig module) {
-        builder.module(module);
-        return this;
-    }
-
-    public ReferenceSettings<S> addRegistries(List<RegistryConfig> registries) {
-        builder.addRegistries(registries);
-        return this;
-    }
-
-    public ReferenceSettings<S> addRegistry(RegistryConfig registry) {
-        builder.addRegistry(registry);
-        return this;
-    }
-
-    public ReferenceSettings<S> registryIds(String registryIds) {
-        builder.registryIds(registryIds);
-        return this;
-    }
-
-    public ReferenceSettings<S> onconnect(String onconnect) {
-        builder.onconnect(onconnect);
-        return this;
-    }
-
-    public ReferenceSettings<S> ondisconnect(String ondisconnect) {
-        builder.ondisconnect(ondisconnect);
-        return this;
-    }
-
-    public ReferenceSettings<S> metadataReportConfig(MetadataReportConfig metadataReportConfig) {
-        builder.metadataReportConfig(metadataReportConfig);
-        return this;
-    }
-
-    public ReferenceSettings<S> configCenter(ConfigCenterConfig configCenter) {
-        builder.configCenter(configCenter);
-        return this;
-    }
-
-    public ReferenceSettings<S> callbacks(Integer callbacks) {
-        builder.callbacks(callbacks);
-        return this;
-    }
-
-    public ReferenceSettings<S> scope(String scope) {
-        builder.scope(scope);
-        return this;
-    }
-
-    public ReferenceSettings<S> tag(String tag) {
-        builder.tag(tag);
-        return this;
-    }
-
-    public ReferenceSettings<S> timeout(Integer timeout) {
-        builder.timeout(timeout);
-        return this;
-    }
-
-    public ReferenceSettings<S> retries(Integer retries) {
-        builder.retries(retries);
-        return this;
-    }
-
-    public ReferenceSettings<S> actives(Integer actives) {
-        builder.actives(actives);
-        return this;
-    }
-
-    public ReferenceSettings<S> loadbalance(String loadbalance) {
-        builder.loadbalance(loadbalance);
-        return this;
-    }
-
-    public ReferenceSettings<S> async(Boolean async) {
-        builder.async(async);
-        return this;
-    }
-
-    public ReferenceSettings<S> sent(Boolean sent) {
-        builder.sent(sent);
-        return this;
-    }
-
-    public ReferenceSettings<S> mock(String mock) {
-        builder.mock(mock);
-        return this;
-    }
-
-    public ReferenceSettings<S> mock(Boolean mock) {
-        builder.mock(mock);
-        return this;
-    }
-
-    public ReferenceSettings<S> merger(String merger) {
-        builder.merger(merger);
-        return this;
-    }
-
-    public ReferenceSettings<S> cache(String cache) {
-        builder.cache(cache);
-        return this;
-    }
-
-    public ReferenceSettings<S> validation(String validation) {
-        builder.validation(validation);
-        return this;
-    }
-
-    public ReferenceSettings<S> appendParameters(Map<String, String> appendParameters) {
-        builder.appendParameters(appendParameters);
-        return this;
-    }
-
-    public ReferenceSettings<S> appendParameter(String key, String value) {
-        builder.appendParameter(key, value);
-        return this;
-    }
-
-    public ReferenceSettings<S> forks(Integer forks) {
-        builder.forks(forks);
-        return this;
-    }
-}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java
deleted file mode 100644
index 89899ac..0000000
--- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/RegistrySettings.java
+++ /dev/null
@@ -1,164 +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.bootstrap;
-
-import org.apache.dubbo.config.RegistryConfig;
-import org.apache.dubbo.config.builders.RegistryBuilder;
-
-import java.util.Map;
-
-/**
- * The settings of {@link RegistryConfig}
- *
- * @since 2.7.4
- */
-public class RegistrySettings extends AbstractSettings {
-
-    private final RegistryBuilder builder;
-
-    public RegistrySettings(RegistryBuilder builder, DubboBootstrap dubboBootstrap) {
-        super(dubboBootstrap);
-        this.builder = builder;
-    }
-
-    public RegistrySettings address(String address) {
-        builder.address(address);
-        return this;
-    }
-
-    public RegistrySettings username(String username) {
-        builder.username(username);
-        return this;
-    }
-
-    public RegistrySettings password(String password) {
-        builder.password(password);
-        return this;
-    }
-
-    public RegistrySettings port(Integer port) {
-        builder.port(port);
-        return this;
-    }
-
-    public RegistrySettings protocol(String protocol) {
-        builder.protocol(protocol);
-        return this;
-    }
-
-    public RegistrySettings transporter(String transporter) {
-        builder.transporter(transporter);
-        return this;
-    }
-
-    @Deprecated
-    public RegistrySettings transport(String transport) {
-        builder.transport(transport);
-        return this;
-    }
-
-    public RegistrySettings server(String server) {
-        builder.server(server);
-        return this;
-    }
-
-    public RegistrySettings client(String client) {
-        builder.client(client);
-        return this;
-    }
-
-    public RegistrySettings cluster(String cluster) {
-        builder.cluster(cluster);
-        return this;
-    }
-
-    public RegistrySettings group(String group) {
-        builder.group(group);
-        return this;
-    }
-
-    public RegistrySettings version(String version) {
-        builder.version(version);
-        return this;
-    }
-
-    public RegistrySettings timeout(Integer timeout) {
-        builder.timeout(timeout);
-        return this;
-    }
-
-    public RegistrySettings session(Integer session) {
-        builder.session(session);
-        return this;
-    }
-
-    public RegistrySettings file(String file) {
-        builder.file(file);
-        return this;
-    }
-
-    @Deprecated
-    public RegistrySettings wait(Integer wait) {
-        builder.wait(wait);
-        return this;
-    }
-
-    public RegistrySettings isCheck(Boolean check) {
-        builder.isCheck(check);
-        return this;
-    }
-
-    public RegistrySettings isDynamic(Boolean dynamic) {
-        builder.isDynamic(dynamic);
-        return this;
-    }
-
-    public RegistrySettings register(Boolean register) {
-        builder.register(register);
-        return this;
-    }
-
-    public RegistrySettings subscribe(Boolean subscribe) {
-        builder.subscribe(subscribe);
-        return this;
-    }
-
-    public RegistrySettings appendParameter(String key, String value) {
-        builder.appendParameter(key, value);
-        return this;
-    }
-
-    public RegistrySettings appendParameters(Map<String, String> appendParameters) {
-        builder.appendParameters(appendParameters);
-        return this;
-    }
-
-    public RegistrySettings isDefault(Boolean isDefault) {
-        builder.isDefault(isDefault);
-        return this;
-    }
-
-    public RegistrySettings simplified(Boolean simplified) {
-        builder.simplified(simplified);
-        return this;
-    }
-
-    public RegistrySettings extraKeys(String extraKeys) {
-        builder.extraKeys(extraKeys);
-        return this;
-    }
-}
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java
deleted file mode 100644
index b17fa83..0000000
--- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/ServiceSettings.java
+++ /dev/null
@@ -1,384 +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.bootstrap;
-
-import org.apache.dubbo.config.ApplicationConfig;
-import org.apache.dubbo.config.ConfigCenterConfig;
-import org.apache.dubbo.config.MetadataReportConfig;
-import org.apache.dubbo.config.MethodConfig;
-import org.apache.dubbo.config.ModuleConfig;
-import org.apache.dubbo.config.MonitorConfig;
-import org.apache.dubbo.config.ProtocolConfig;
-import org.apache.dubbo.config.ProviderConfig;
-import org.apache.dubbo.config.RegistryConfig;
-import org.apache.dubbo.config.ServiceConfig;
-import org.apache.dubbo.config.builders.ServiceBuilder;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * The settings of {@link ServiceConfig Dubbo service}
- *
- * @since 2.7.4
- */
-public class ServiceSettings<S> extends AbstractSettings {
-
-    private final ServiceBuilder<S> builder;
-
-    public ServiceSettings(ServiceBuilder<S> builder, DubboBootstrap dubboBootstrap) {
-        super(dubboBootstrap);
-        this.builder = builder;
-    }
-
-    public ServiceSettings<S> interfaceName(String interfaceName) {
-        builder.interfaceName(interfaceName);
-        return this;
-    }
-
-    public ServiceSettings<S> interfaceClass(Class<?> interfaceClass) {
-        builder.interfaceClass(interfaceClass);
-        return this;
-    }
-
-    public ServiceSettings<S> ref(S ref) {
-        builder.ref(ref);
-        return this;
-    }
-
-    public ServiceSettings<S> path(String path) {
-        builder.path(path);
-        return this;
-    }
-
-    public ServiceSettings<S> addMethod(MethodConfig method) {
-        builder.addMethod(method);
-        return this;
-    }
-
-    public ServiceSettings<S> addMethods(List<? extends MethodConfig> methods) {
-        builder.addMethods(methods);
-        return this;
-    }
-
-    public ServiceSettings<S> provider(ProviderConfig provider) {
-        builder.provider(provider);
-        return this;
-    }
-
-    public ServiceSettings<S> providerIds(String providerIds) {
-        builder.providerIds(providerIds);
-        return this;
-    }
-
-    public ServiceSettings<S> generic(String generic) {
-        builder.generic(generic);
-        return this;
-    }
-
-    public ServiceSettings<S> mock(String mock) {
-        builder.mock(mock);
-        return this;
-    }
-
-    public ServiceSettings<S> mock(Boolean mock) {
-        builder.mock(mock);
-        return this;
-    }
-
-    public ServiceSettings<S> version(String version) {
-        builder.version(version);
-        return this;
-    }
-
-    public ServiceSettings<S> group(String group) {
-        builder.group(group);
-        return this;
-    }
-
-    public ServiceSettings<S> deprecated(Boolean deprecated) {
-        builder.deprecated(deprecated);
-        return this;
-    }
-
-    public ServiceSettings<S> delay(Integer delay) {
-        builder.delay(delay);
-        return this;
-    }
-
-    public ServiceSettings<S> export(Boolean export) {
-        builder.export(export);
-        return this;
-    }
-
-    public ServiceSettings<S> weight(Integer weight) {
-        builder.weight(weight);
-        return this;
-    }
-
-    public ServiceSettings<S> document(String document) {
-        builder.document(document);
-        return this;
-    }
-
-    public ServiceSettings<S> dynamic(Boolean dynamic) {
-        builder.dynamic(dynamic);
-        return this;
-    }
-
-    public ServiceSettings<S> token(String token) {
-        builder.token(token);
-        return this;
-    }
-
-    public ServiceSettings<S> token(Boolean token) {
-        builder.token(token);
-        return this;
-    }
-
-    public ServiceSettings<S> accesslog(String accesslog) {
-        builder.accesslog(accesslog);
-        return this;
-    }
-
-    public ServiceSettings<S> accesslog(Boolean accesslog) {
-        builder.accesslog(accesslog);
-        return this;
-    }
-
-    public ServiceSettings<S> addProtocols(List<ProtocolConfig> protocols) {
-        builder.addProtocols(protocols);
-        return this;
-    }
-
-    public ServiceSettings<S> addProtocol(ProtocolConfig protocol) {
-        builder.addProtocol(protocol);
-        return this;
-    }
-
-    public ServiceSettings<S> protocolIds(String protocolIds) {
-        builder.protocolIds(protocolIds);
-        return this;
-    }
-
-    public ServiceSettings<S> executes(Integer executes) {
-        builder.executes(executes);
-        return this;
-    }
-
-    public ServiceSettings<S> register(Boolean register) {
-        builder.register(register);
-        return this;
-    }
-
-    public ServiceSettings<S> warmup(Integer warmup) {
-        builder.warmup(warmup);
-        return this;
-    }
-
-    public ServiceSettings<S> serialization(String serialization) {
-        builder.serialization(serialization);
-        return this;
-    }
-
-    @Deprecated
-    public ServiceSettings<S> local(String local) {
-        builder.local(local);
-        return this;
-    }
-
-    @Deprecated
-    public ServiceSettings<S> local(Boolean local) {
-        builder.local(local);
-        return this;
-    }
-
-    public ServiceSettings<S> stub(String stub) {
-        builder.stub(stub);
-        return this;
-    }
-
-    public ServiceSettings<S> stub(Boolean stub) {
-        builder.stub(stub);
-        return this;
-    }
-
-    public ServiceSettings<S> monitor(MonitorConfig monitor) {
-        builder.monitor(monitor);
-        return this;
-    }
-
-    public ServiceSettings<S> monitor(String monitor) {
-        builder.monitor(monitor);
-        return this;
-    }
-
-    public ServiceSettings<S> proxy(String proxy) {
-        builder.proxy(proxy);
-        return this;
-    }
-
-    public ServiceSettings<S> cluster(String cluster) {
-        builder.cluster(cluster);
-        return this;
-    }
-
-    public ServiceSettings<S> filter(String filter) {
-        builder.filter(filter);
-        return this;
-    }
-
-    public ServiceSettings<S> listener(String listener) {
-        builder.listener(listener);
-        return this;
-    }
-
-    public ServiceSettings<S> owner(String owner) {
-        builder.owner(owner);
-        return this;
-    }
-
-    public ServiceSettings<S> connections(Integer connections) {
-        builder.connections(connections);
-        return this;
-    }
-
-    public ServiceSettings<S> layer(String layer) {
-        builder.layer(layer);
-        return this;
-    }
-
-    public ServiceSettings<S> application(ApplicationConfig application) {
-        builder.application(application);
-        return this;
-    }
-
-    public ServiceSettings<S> module(ModuleConfig module) {
-        builder.module(module);
-        return this;
-    }
-
-    public ServiceSettings<S> addRegistries(List<RegistryConfig> registries) {
-        builder.addRegistries(registries);
-        return this;
-    }
-
-    public ServiceSettings<S> addRegistry(RegistryConfig registry) {
-        builder.addRegistry(registry);
-        return this;
-    }
-
-    public ServiceSettings<S> registryIds(String registryIds) {
-        builder.registryIds(registryIds);
-        return this;
-    }
-
-    public ServiceSettings<S> onconnect(String onconnect) {
-        builder.onconnect(onconnect);
-        return this;
-    }
-
-    public ServiceSettings<S> ondisconnect(String ondisconnect) {
-        builder.ondisconnect(ondisconnect);
-        return this;
-    }
-
-    public ServiceSettings<S> metadataReportConfig(MetadataReportConfig metadataReportConfig) {
-        builder.metadataReportConfig(metadataReportConfig);
-        return this;
-    }
-
-    public ServiceSettings<S> configCenter(ConfigCenterConfig configCenter) {
-        builder.configCenter(configCenter);
-        return this;
-    }
-
-    public ServiceSettings<S> callbacks(Integer callbacks) {
-        builder.callbacks(callbacks);
-        return this;
-    }
-
-    public ServiceSettings<S> scope(String scope) {
-        builder.scope(scope);
-        return this;
-    }
-
-    public ServiceSettings<S> tag(String tag) {
-        builder.tag(tag);
-        return this;
-    }
-
-    public ServiceSettings<S> timeout(Integer timeout) {
-        builder.timeout(timeout);
-        return this;
-    }
-
-    public ServiceSettings<S> retries(Integer retries) {
-        builder.retries(retries);
-        return this;
-    }
-
-    public ServiceSettings<S> actives(Integer actives) {
-        builder.actives(actives);
-        return this;
-    }
-
-    public ServiceSettings<S> loadbalance(String loadbalance) {
-        builder.loadbalance(loadbalance);
-        return this;
-    }
-
-    public ServiceSettings<S> async(Boolean async) {
-        builder.async(async);
-        return this;
-    }
-
-    public ServiceSettings<S> sent(Boolean sent) {
-        builder.sent(sent);
-        return this;
-    }
-
-    public ServiceSettings<S> merger(String merger) {
-        builder.merger(merger);
-        return this;
-    }
-
-    public ServiceSettings<S> cache(String cache) {
-        builder.cache(cache);
-        return this;
-    }
-
-    public ServiceSettings<S> validation(String validation) {
-        builder.validation(validation);
-        return this;
-    }
-
-    public ServiceSettings<S> appendParameters(Map<String, String> appendParameters) {
-        builder.appendParameters(appendParameters);
-        return this;
-    }
-
-    public ServiceSettings<S> appendParameter(String key, String value) {
-        builder.appendParameter(key, value);
-        return this;
-    }
-
-    public ServiceSettings<S> forks(Integer forks) {
-        builder.forks(forks);
-        return this;
-    }
-}
diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java
index f49c340..96fbcc7 100644
--- a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboBootstrapTest.java
@@ -16,11 +16,6 @@
  */
 package org.apache.dubbo.bootstrap;
 
-import org.apache.dubbo.config.builders.ApplicationBuilder;
-import org.apache.dubbo.config.builders.ProtocolBuilder;
-import org.apache.dubbo.config.builders.RegistryBuilder;
-import org.apache.dubbo.config.builders.ServiceBuilder;
-
 import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
@@ -35,14 +30,5 @@ public class DubboBootstrapTest {
     @Test
     public void test() throws IOException {
 
-        new DubboBootstrap()
-                .application(ApplicationBuilder.newBuilder().name("dubbo-provider-demo").build())
-                .registry(RegistryBuilder.newBuilder().address("zookeeper://127.0.0.1:2181?registry-type=service&metadata=remote").build())
-                .protocol(ProtocolBuilder.newBuilder().port(-1).name("dubbo").build())
-                .service(ServiceBuilder.newBuilder().id("test").interfaceClass(EchoService.class).ref(new EchoServiceImpl()).build())
-                .start()
-                .await();
-
-        System.in.read();
     }
 }
diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java
index 4e03c1b..191b233 100644
--- a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java
@@ -16,9 +16,8 @@
  */
 package org.apache.dubbo.bootstrap;
 
-import org.apache.dubbo.config.builders.ApplicationBuilder;
-import org.apache.dubbo.config.builders.ReferenceBuilder;
-import org.apache.dubbo.config.builders.RegistryBuilder;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.context.ConfigManager;
 
 /**
  * Dubbo Provider Bootstrap
@@ -29,23 +28,27 @@ public class DubboServiceConsumerBootstrap {
 
     public static void main(String[] args) throws Exception {
 
-        DubboBootstrap bootstrap = new DubboBootstrap()
-                .application(ApplicationBuilder.newBuilder().name("dubbo-consumer-demo").build())
-                .registry(RegistryBuilder.newBuilder().address("zookeeper://127.0.0.1:2181?registry-type=service&subscribed-services=dubbo-provider-demo&metadata=remote").build())
-                .reference(ReferenceBuilder.newBuilder().id("ref").interfaceClass(EchoService.class).build())
+        new DubboBootstrap()
+                .application("dubbo-consumer-demo")
+                // Zookeeper
+                .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181?registry-type=service&subscribed-services=dubbo-provider-demo"))
+                // Nacos
+                .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry-type=service&subscribed-services=dubbo-provider-demo"))
+                .reference("ref", builder -> builder.interfaceClass(EchoService.class))
                 .onlyRegisterProvider(true)
                 .start()
                 .await();
 
-        // TODO,
-//        ReferenceConfig<EchoService> referenceConfig = ReferenceConfigCache.getCache().get(EchoService.class.getName(), EchoService.class);
-//
-//        EchoService echoService = referenceConfig.get();
-//
-//        for (int i = 0; i < 500; i++) {
-//            Thread.sleep(2000L);
-//            System.out.println(echoService.echo("Hello,World"));
-//        }
+        ConfigManager configManager = ConfigManager.getInstance();
+
+        ReferenceConfig<EchoService> referenceConfig = configManager.getReferenceConfig("ref");
+
+        EchoService echoService = referenceConfig.get();
+
+        for (int i = 0; i < 500; i++) {
+            Thread.sleep(2000L);
+            System.out.println(echoService.echo("Hello,World"));
+        }
 
     }
 }
diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java
index 7918bff..1ed573f 100644
--- a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceProviderBootstrap.java
@@ -16,14 +16,6 @@
  */
 package org.apache.dubbo.bootstrap;
 
-import org.apache.dubbo.config.builders.ApplicationBuilder;
-import org.apache.dubbo.config.builders.MetadataReportBuilder;
-import org.apache.dubbo.config.builders.ProtocolBuilder;
-import org.apache.dubbo.config.builders.RegistryBuilder;
-import org.apache.dubbo.config.builders.ServiceBuilder;
-
-import java.io.IOException;
-
 /**
  * Dubbo Provider Bootstrap
  *
@@ -31,15 +23,15 @@ import java.io.IOException;
  */
 public class DubboServiceProviderBootstrap {
 
-    public static void main(String[] args) throws IOException {
-
+    public static void main(String[] args) {
         new DubboBootstrap()
-                .application(ApplicationBuilder.newBuilder().name("dubbo-provider-demo").metadata("remote").build())
-                .metadataReport(MetadataReportBuilder.newBuilder().address("zookeeper://127.0.0.1:2181").build())
-//                .application(ApplicationBuilder.newBuilder().name("dubbo-provider-demo").build())
-                .registry(RegistryBuilder.newBuilder().address("zookeeper://127.0.0.1:2181?registry-type=service").build())
-                .protocol(ProtocolBuilder.newBuilder().port(-1).name("dubbo").build())
-                .service(ServiceBuilder.newBuilder().id("test").interfaceClass(EchoService.class).ref(new EchoServiceImpl()).build())
+                .application("dubbo-provider-demo")
+                // Zookeeper in service registry type
+                .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181?registry-type=service"))
+                // Nacos
+                .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry-type=service"))
+                .protocol(builder -> builder.port(-1).name("dubbo"))
+                .service(builder -> builder.id("test").interfaceClass(EchoService.class).ref(new EchoServiceImpl()))
                 .start()
                 .await();
     }
diff --git a/dubbo-common/pom.xml b/dubbo-common/pom.xml
index 98ecc9b..dabf4bb 100644
--- a/dubbo-common/pom.xml
+++ b/dubbo-common/pom.xml
@@ -77,5 +77,9 @@
             <groupId>de.ruedigermoeller</groupId>
             <artifactId>fst</artifactId>
         </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
     </dependencies>
 </project>
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangeEvent.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangeEvent.java
index 751746f..177551b 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangeEvent.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigChangeEvent.java
@@ -16,15 +16,18 @@
  */
 package org.apache.dubbo.common.config.configcenter;
 
+import java.util.EventObject;
+
 /**
  * Config change event, immutable.
  *
  * @see ConfigChangeType
  */
-public class ConfigChangeEvent {
+public class ConfigChangeEvent extends EventObject {
     private final String key;
 
     private final String value;
+
     private final ConfigChangeType changeType;
 
     public ConfigChangeEvent(String key, String value) {
@@ -32,6 +35,7 @@ public class ConfigChangeEvent {
     }
 
     public ConfigChangeEvent(String key, String value, ConfigChangeType changeType) {
+        super(key + "=" + value);
         this.key = key;
         this.value = value;
         this.changeType = changeType;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigurationListener.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigurationListener.java
index 09746c5..2a1779a 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigurationListener.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigurationListener.java
@@ -16,10 +16,12 @@
  */
 package org.apache.dubbo.common.config.configcenter;
 
+import java.util.EventListener;
+
 /**
  * Config listener, will get notified when the config it listens on changes.
  */
-public interface ConfigurationListener {
+public interface ConfigurationListener extends EventListener {
 
     /**
      * Listener call back method. Listener gets notified by this method once there's any change happens on the config
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java
index f5bf9a4..84b6ec3 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java
@@ -16,16 +16,17 @@
  */
 package org.apache.dubbo.common.config.configcenter;
 
+import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.config.Configuration;
 import org.apache.dubbo.common.config.Environment;
 
 import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.SortedMap;
-import java.util.SortedSet;
-import java.util.TreeMap;
 
+import static org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory.getDynamicConfigurationFactory;
 import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
 
 /**
@@ -38,7 +39,7 @@ import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoad
  * <li>3. addListener/removeListener, add or remove listeners for governance rules or config items that need to watch.</li>
  * </ul>
  */
-public interface DynamicConfiguration extends Configuration {
+public interface DynamicConfiguration extends Configuration, AutoCloseable {
 
     String DEFAULT_GROUP = "dubbo";
 
@@ -133,6 +134,20 @@ public interface DynamicConfiguration extends Configuration {
      */
     String getConfigs(String key, String group, long timeout) throws IllegalStateException;
 
+
+    /**
+     * Publish Config mapped to the given key under the {@link #DEFAULT_GROUP default group}
+     *
+     * @param key     the key to represent a configuration
+     * @param content the content of configuration
+     * @return <code>true</code> if success, or <code>false</code>
+     * @throws UnsupportedOperationException If the under layer does not support
+     * @since 2.7.4
+     */
+    default boolean publishConfig(String key, String content) throws UnsupportedOperationException {
+        return publishConfig(key, DEFAULT_GROUP, content);
+    }
+
     /**
      * Publish Config mapped to the given key and the given group.
      *
@@ -148,45 +163,92 @@ public interface DynamicConfiguration extends Configuration {
     }
 
     /**
+     * Remove Config mapped to the given key under the {@link #DEFAULT_GROUP default group}
+     *
+     * @param key the key to represent a configuration
+     * @return the content of configuration was removed
+     * @throws UnsupportedOperationException If the under layer does not support
+     * @since 2.7.4
+     */
+    default String removeConfig(String key) throws UnsupportedOperationException {
+        return removeConfig(key, DEFAULT_GROUP);
+    }
+
+    /**
+     * Remove Config mapped to the given key and the given group.
+     *
+     * @param key   the key to represent a configuration
+     * @param group the group where the key belongs to
+     * @return the content of configuration was removed
+     * @throws UnsupportedOperationException If the under layer does not support
+     * @since 2.7.4
+     */
+    default String removeConfig(String key, String group) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException("No support");
+    }
+
+    /**
+     * Get all groups
+     *
+     * @return the read-only non-null {@link Set set} of config keys
+     * @throws UnsupportedOperationException If the under layer does not support
+     * @since 2.7.4
+     */
+    default Set<String> getConfigGroups() throws UnsupportedOperationException {
+        throw new UnsupportedOperationException("No support");
+    }
+
+    /**
      * Get the config keys by the specified group
      *
      * @param group the specified group
-     * @return the read-only non-null sorted {@link Set set} of config keys
+     * @return the read-only non-null {@link Set set} of config keys
      * @throws UnsupportedOperationException If the under layer does not support
      * @since 2.7.4
      */
-    default SortedSet<String> getConfigKeys(String group) throws UnsupportedOperationException {
+    default Set<String> getConfigKeys(String group) throws UnsupportedOperationException {
         throw new UnsupportedOperationException("No support");
     }
 
     /**
-     * Get the {@link SortedMap} with with config keys and contents value by the specified group
+     * Get the {@link Map} with with config keys and contents value by the specified group
      *
      * @param group the specified group
-     * @return the read-only non-null sorted {@link SortedMap map}
+     * @return the read-only non-null {@link Map map}
      * @throws UnsupportedOperationException If the under layer does not support
      * @since 2.7.4
      */
-    default SortedMap<String, String> getConfigs(String group) throws UnsupportedOperationException {
+    default Map<String, String> getConfigs(String group) throws UnsupportedOperationException {
         return getConfigs(group, -1);
     }
 
     /**
-     * Get the {@link SortedMap} with with config keys and content value by the specified group
+     * Get the {@link Map} with with config keys and content value by the specified group
      *
      * @param group   the specified group
      * @param timeout the millisecond for timeout
-     * @return the read-only non-null sorted {@link SortedMap map}
+     * @return the read-only non-null {@link Map map}
      * @throws UnsupportedOperationException If the under layer does not support
      * @throws IllegalStateException         If timeout exceeds
      * @since 2.7.4
      */
-    default SortedMap<String, String> getConfigs(String group, long timeout) throws UnsupportedOperationException,
+    default Map<String, String> getConfigs(String group, long timeout) throws UnsupportedOperationException,
             IllegalStateException {
-        SortedMap<String, String> configs = new TreeMap<>();
-        SortedSet<String> configKeys = getConfigKeys(group);
+        Map<String, String> configs = new LinkedHashMap<>();
+        Set<String> configKeys = getConfigKeys(group);
         configKeys.forEach(key -> configs.put(key, getConfig(key, group, timeout)));
-        return Collections.unmodifiableSortedMap(configs);
+        return Collections.unmodifiableMap(configs);
+    }
+
+    /**
+     * Close the configuration
+     *
+     * @throws Exception
+     * @since 2.7.4
+     */
+    @Override
+    default void close() throws Exception {
+        throw new UnsupportedOperationException();
     }
 
     /**
@@ -200,4 +262,17 @@ public interface DynamicConfiguration extends Configuration {
                 .getDefaultExtension()
                 .getDynamicConfiguration(null));
     }
+
+    /**
+     * Get the instance of {@link DynamicConfiguration} by the specified connection {@link URL}
+     *
+     * @param connectionURL
+     * @return non-null
+     * @since 2.7.4
+     */
+    static DynamicConfiguration getDynamicConfiguration(URL connectionURL) {
+        String protocol = connectionURL.getProtocol();
+        DynamicConfigurationFactory factory = getDynamicConfigurationFactory(protocol);
+        return factory.getDynamicConfiguration(connectionURL);
+    }
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactory.java
index 59c27ce..649eec6 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactory.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactory.java
@@ -17,14 +17,30 @@
 package org.apache.dubbo.common.config.configcenter;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.extension.SPI;
 
+import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
+
 /**
- *
+ * The factory interface to create the instance of {@link DynamicConfiguration}
  */
-@SPI("nop")
+@SPI("file") // 2.7.4 change the default SPI implementation
 public interface DynamicConfigurationFactory {
 
     DynamicConfiguration getDynamicConfiguration(URL url);
 
+    /**
+     * Get an instance of {@link DynamicConfigurationFactory} by the specified name. If not found, take the default
+     * extension of {@link DynamicConfigurationFactory}
+     *
+     * @param name the name of extension of {@link DynamicConfigurationFactory}
+     * @return non-null
+     * @see 2.7.4
+     */
+    static DynamicConfigurationFactory getDynamicConfigurationFactory(String name) {
+        Class<DynamicConfigurationFactory> factoryClass = DynamicConfigurationFactory.class;
+        ExtensionLoader<DynamicConfigurationFactory> loader = getExtensionLoader(factoryClass);
+        return loader.hasExtension(name) ? loader.getExtension(name) : loader.getDefaultExtension();
+    }
 }
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
new file mode 100644
index 0000000..b75527e
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java
@@ -0,0 +1,628 @@
+/*
+ * 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.config.configcenter.file;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.configcenter.ConfigChangeEvent;
+import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
+import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
+import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
+import org.apache.dubbo.common.function.ThrowableConsumer;
+import org.apache.dubbo.common.function.ThrowableFunction;
+import org.apache.dubbo.common.utils.NamedThreadFactory;
+
+import com.sun.nio.file.SensitivityWatchEventModifier;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.lang.String.format;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+import static java.util.Collections.emptySet;
+import static java.util.Collections.unmodifiableMap;
+import static java.util.concurrent.Executors.newFixedThreadPool;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.commons.io.FileUtils.readFileToString;
+import static org.apache.dubbo.common.utils.StringUtils.isBlank;
+
+/**
+ * File-System based {@link DynamicConfiguration} implementation
+ *
+ * @since 2.7.4
+ */
+public class FileSystemDynamicConfiguration implements DynamicConfiguration {
+
+    public static final String PARAM_NAME_PREFIX = "dubbo.config-center.";
+
+    public static final String CONFIG_CENTER_DIR_PARAM_NAME = PARAM_NAME_PREFIX + "dir";
+
+    public static final String THREAD_POOL_PREFIX_PARAM_NAME = PARAM_NAME_PREFIX + "thread-pool.prefix";
+
+    public static final String THREAD_POOL_SIZE_PARAM_NAME = PARAM_NAME_PREFIX + "thread-pool.size";
+
+    public static final String CONFIG_CENTER_ENCODING_PARAM_NAME = PARAM_NAME_PREFIX + "encoding";
+
+    public static final String DEFAULT_CONFIG_CENTER_DIR_PATH = System.getProperty("user.home") + File.separator
+            + ".dubbo" + File.separator + "config-center";
+
+    public static final String DEFAULT_THREAD_POOL_PREFIX = PARAM_NAME_PREFIX + "workers";
+
+    public static final String DEFAULT_THREAD_POOL_SIZE = "1";
+
+    public static final String DEFAULT_CONFIG_CENTER_ENCODING = "UTF-8";
+
+    private static final WatchEvent.Kind[] INTEREST_PATH_KINDS = of(ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
+
+    /**
+     * The class name of {@linkplain sun.nio.fs.PollingWatchService}
+     */
+    private static final String POLLING_WATCH_SERVICE_CLASS_NAME = "sun.nio.fs.PollingWatchService";
+
+    private static final int THREAD_POOL_SIZE = 1;
+
+    /**
+     * Logger
+     */
+    private static final Log logger = LogFactory.getLog(FileSystemDynamicConfiguration.class);
+
+    /**
+     * The unmodifiable map for {@link ConfigChangeType} whose key is the {@link WatchEvent.Kind#name() name} of
+     * {@link WatchEvent.Kind WatchEvent's Kind}
+     */
+    private static final Map<String, ConfigChangeType> CONFIG_CHANGE_TYPES_MAP =
+            unmodifiableMap(new HashMap<String, ConfigChangeType>() {
+                // Initializes the elements that is mapping ConfigChangeType
+                {
+                    put(ENTRY_CREATE.name(), ConfigChangeType.ADDED);
+                    put(ENTRY_DELETE.name(), ConfigChangeType.DELETED);
+                    put(ENTRY_MODIFY.name(), ConfigChangeType.MODIFIED);
+                }
+            });
+
+    private static final Optional<WatchService> watchService;
+
+    /**
+     * Is Pooling Based Watch Service
+     *
+     * @see #detectPoolingBasedWatchService(Optional)
+     */
+    private static final boolean basedPoolingWatchService;
+
+    private static final WatchEvent.Modifier[] modifiers;
+
+    /**
+     * the delay to action in seconds. If null, execute indirectly
+     */
+    private static final Integer delay;
+
+    /**
+     * The thread pool for {@link WatchEvent WatchEvents} loop
+     * It's optional if there is not any {@link ConfigurationListener} registration
+     *
+     * @see ThreadPoolExecutor
+     */
+    private static final ThreadPoolExecutor watchEventsLoopThreadPool;
+
+    // static initialization
+    static {
+        watchService = newWatchService();
+        basedPoolingWatchService = detectPoolingBasedWatchService(watchService);
+        modifiers = initWatchEventModifiers();
+        delay = initDelay(modifiers);
+        watchEventsLoopThreadPool = newWatchEventsLoopThreadPool();
+    }
+
+    /**
+     * The Root Directory for config center
+     */
+    private final File rootDirectory;
+
+    private final String encoding;
+
+    /**
+     * The thread pool for workers who executes the tasks
+     */
+    private final ThreadPoolExecutor workersThreadPool;
+
+    /**
+     * The {@link Set} of {@link #configDirectory(String) directories} that may be processing,
+     * <p>
+     * if {@link #isBasedPoolingWatchService()} is <code>false</code>, this properties will be
+     * {@link Collections#emptySet() empty}
+     *
+     * @see #initProcessingDirectories()
+     */
+    private final Set<File> processingDirectories;
+
+    private final Map<File, List<ConfigurationListener>> listenersRepository;
+
+    public FileSystemDynamicConfiguration(URL url) {
+        this(initDirectory(url), getEncoding(url), getThreadPoolPrefixName(url), getThreadPoolSize(url));
+    }
+
+    public FileSystemDynamicConfiguration(File rootDirectory, String encoding,
+                                          String threadPoolPrefixName,
+                                          int threadPoolSize
+    ) {
+        this.rootDirectory = rootDirectory;
+        this.encoding = encoding;
+        this.workersThreadPool = initWorkersThreadPool(threadPoolPrefixName, threadPoolSize);
+        this.processingDirectories = initProcessingDirectories();
+        this.listenersRepository = new LinkedHashMap<>();
+    }
+
+    private Set<File> initProcessingDirectories() {
+        return isBasedPoolingWatchService() ? new LinkedHashSet<>() : emptySet();
+    }
+
+    @Override
+    public void addListener(String key, String group, ConfigurationListener listener) {
+        doInListener(key, group, (configFilePath, listeners) -> {
+
+            if (listeners.isEmpty()) { // If no element, it indicates watchService was registered before
+                ThrowableConsumer.execute(configFilePath, configFile -> {
+                    FileUtils.forceMkdirParent(configFile);
+                    // A rootDirectory to be watched
+                    File configDirectory = configFile.getParentFile();
+                    if (configDirectory != null) {
+                        // Register the configDirectory
+                        configDirectory.toPath().register(watchService.get(), INTEREST_PATH_KINDS, modifiers);
+                    }
+                });
+            }
+
+            // Add into cache
+            listeners.add(listener);
+        });
+    }
+
+    @Override
+    public void removeListener(String key, String group, ConfigurationListener listener) {
+        doInListener(key, group, (file, listeners) -> {
+            // Remove into cache
+            listeners.remove(listener);
+        });
+    }
+
+    protected File configDirectory(String group) {
+        String actualGroup = isBlank(group) ? DEFAULT_GROUP : group;
+        return new File(rootDirectory, actualGroup);
+    }
+
+    protected File configFile(String key, String group) {
+        return new File(configDirectory(group), key);
+    }
+
+    private void doInListener(String key, String group, BiConsumer<File, List<ConfigurationListener>> consumer) {
+        watchService.ifPresent(watchService -> {
+            File configFile = configFile(key, group);
+            executeMutually(configFile.getParentFile(), () -> {
+                // process the WatchEvents if not start
+                if (!isProcessingWatchEvents()) {
+                    processWatchEvents(watchService);
+                }
+
+                List<ConfigurationListener> listeners = getListeners(configFile);
+                consumer.accept(configFile, listeners);
+
+                // Nothing to return
+                return null;
+            });
+        });
+    }
+
+    private static boolean isProcessingWatchEvents() {
+        return getWatchEventsLoopThreadPool().getActiveCount() > 0;
+    }
+
+    /**
+     * Process the {@link WatchEvent WatchEvents} loop in async execution
+     *
+     * @param watchService {@link WatchService}
+     */
+    private void processWatchEvents(WatchService watchService) {
+        getWatchEventsLoopThreadPool().execute(() -> { // WatchEvents Loop
+            while (true) {
+                WatchKey watchKey = null;
+                try {
+                    watchKey = watchService.take();
+                    if (watchKey.isValid()) {
+                        for (WatchEvent event : watchKey.pollEvents()) {
+                            WatchEvent.Kind kind = event.kind();
+                            // configChangeType's key to match WatchEvent's Kind
+                            ConfigChangeType configChangeType = CONFIG_CHANGE_TYPES_MAP.get(kind.name());
+                            if (configChangeType != null) {
+                                Path configDirectoryPath = (Path) watchKey.watchable();
+                                Path currentPath = (Path) event.context();
+                                Path configFilePath = configDirectoryPath.resolve(currentPath);
+                                File configDirectory = configDirectoryPath.toFile();
+                                executeMutually(configDirectory, () -> {
+                                    fireConfigChangeEvent(configFilePath.toFile(), configChangeType);
+                                    signalConfigDirectory(configDirectory);
+                                    return null;
+                                });
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                    return;
+                } finally {
+                    if (watchKey != null) {
+                        // reset
+                        watchKey.reset();
+                    }
+                }
+            }
+        });
+    }
+
+    private void signalConfigDirectory(File configDirectory) {
+        if (isBasedPoolingWatchService()) {
+            // remove configDirectory from processing set because it's done
+            removeProcessingDirectory(configDirectory);
+            // notify configDirectory
+            notifyProcessingDirectory(configDirectory);
+            if (logger.isDebugEnabled()) {
+                logger.debug(format("The config rootDirectory[%s] is signalled...", configDirectory.getName()));
+            }
+        }
+    }
+
+    private void removeProcessingDirectory(File configDirectory) {
+        processingDirectories.remove(configDirectory);
+    }
+
+    private void notifyProcessingDirectory(File configDirectory) {
+        configDirectory.notifyAll();
+    }
+
+    private List<ConfigurationListener> getListeners(File configFile) {
+        return listenersRepository.computeIfAbsent(configFile, p -> new LinkedList<>());
+    }
+
+    private void fireConfigChangeEvent(File configFile, ConfigChangeType configChangeType) {
+        String key = configFile.getName();
+        String value = getConfig(configFile, -1L);
+        // fire ConfigChangeEvent one by one
+        getListeners(configFile).forEach(listener -> {
+            try {
+                listener.process(new ConfigChangeEvent(key, value, configChangeType));
+            } catch (Throwable e) {
+                if (logger.isErrorEnabled()) {
+                    logger.error(e.getMessage(), e);
+                }
+            }
+        });
+    }
+
+    @Override
+    public String getConfig(String key, String group, long timeout) throws IllegalStateException {
+        File configFile = configFile(key, group);
+        return getConfig(configFile, timeout);
+    }
+
+    protected String getConfig(File configFile, long timeout) {
+        return canRead(configFile) ? execute(() -> readFileToString(configFile, getEncoding()), timeout) : null;
+    }
+
+    private boolean canRead(File file) {
+        return file.exists() && file.canRead();
+    }
+
+    @Override
+    public String getConfigs(String key, String group, long timeout) throws IllegalStateException {
+        return getConfig(key, group, timeout);
+    }
+
+    @Override
+    public Object getInternalProperty(String key) {
+        return null;
+    }
+
+    @Override
+    public boolean publishConfig(String key, String group, String content) {
+        return delay(key, group, configFile -> {
+            FileUtils.write(configFile, content, getEncoding());
+            return true;
+        });
+    }
+
+    @Override
+    public String removeConfig(String key, String group) {
+        return delay(key, group, configFile -> {
+
+            String content = getConfig(configFile, -1L);
+
+            FileUtils.deleteQuietly(configFile);
+
+            return content;
+        });
+    }
+
+    private ThreadPoolExecutor initWorkersThreadPool(String prefix, int size) {
+        return (ThreadPoolExecutor) newFixedThreadPool(size, new NamedThreadFactory(prefix));
+    }
+
+    /**
+     * Delay action for {@link #configFile(String, String) config file}
+     *
+     * @param key      the key to represent a configuration
+     * @param group    the group where the key belongs to
+     * @param function the customized {@link Function function} with {@link File}
+     * @param <V>      the computed value
+     * @return
+     */
+    protected <V> V delay(String key, String group, ThrowableFunction<File, V> function) {
+        File configFile = configFile(key, group);
+        // Must be based on PoolingWatchService and has listeners under config file
+        if (isBasedPoolingWatchService()) {
+            File configDirectory = configFile.getParentFile();
+            executeMutually(configDirectory, () -> {
+                if (hasListeners(configFile) && isProcessing(configDirectory)) {
+                    Integer delay = getDelay();
+                    if (delay != null) {
+                        // wait for delay in seconds
+                        long timeout = SECONDS.toMillis(delay);
+                        if (logger.isDebugEnabled()) {
+                            logger.debug(format("The config[key : %s, group : %s] is about to delay in %d ms.",
+                                    key, group, timeout));
+                        }
+                        configDirectory.wait(timeout);
+                    }
+                }
+                addProcessing(configDirectory);
+                return null;
+            });
+        }
+
+        V value = null;
+
+        try {
+            value = function.apply(configFile);
+        } catch (Throwable e) {
+            if (logger.isErrorEnabled()) {
+                logger.error(e.getMessage(), e);
+            }
+        }
+
+        return value;
+    }
+
+    private boolean hasListeners(File configFile) {
+        return getListeners(configFile).size() > 0;
+    }
+
+    /**
+     * Is processing on {@link #configDirectory(String) config rootDirectory}
+     *
+     * @param configDirectory {@link #configDirectory(String) config rootDirectory}
+     * @return if processing , return <code>true</code>, or <code>false</code>
+     */
+    private boolean isProcessing(File configDirectory) {
+        return processingDirectories.contains(configDirectory);
+    }
+
+    private void addProcessing(File configDirectory) {
+        processingDirectories.add(configDirectory);
+    }
+
+    @Override
+    public Set<String> getConfigKeys(String group) {
+        return Stream.of(configDirectory(group).listFiles(File::isFile))
+                .map(File::getName)
+                .collect(Collectors.toSet());
+    }
+
+
+    @Override
+    public Set<String> getConfigGroups() {
+        return Stream.of(getRootDirectory().listFiles())
+                .filter(File::isDirectory)
+                .map(File::getName)
+                .collect(Collectors.toSet());
+    }
+
+    @Override
+    public Map<String, String> getConfigs(String group) throws UnsupportedOperationException {
+        return getConfigs(group, -1);
+    }
+
+    @Override
+    public void close() throws Exception {
+        // TODO
+    }
+
+    private <V> V execute(Callable<V> task, long timeout) {
+        V value = null;
+        try {
+
+            if (timeout < 1) { // less or equal 0
+                value = task.call();
+            } else {
+                Future<V> future = workersThreadPool.submit(task);
+                value = future.get(timeout, TimeUnit.MILLISECONDS);
+            }
+        } catch (Exception e) {
+            if (logger.isErrorEnabled()) {
+                logger.error(e.getMessage(), e);
+            }
+        }
+        return value;
+    }
+
+    protected File getRootDirectory() {
+        return rootDirectory;
+    }
+
+    protected ThreadPoolExecutor getWorkersThreadPool() {
+        return workersThreadPool;
+    }
+
+    protected String getEncoding() {
+        return encoding;
+    }
+
+    protected Integer getDelay() {
+        return delay;
+    }
+
+    /**
+     * It's whether the implementation of {@link WatchService} is based on {@linkplain sun.nio.fs.PollingWatchService}
+     * or not.
+     * <p>
+     *
+     * @return if based, return <code>true</code>, or <code>false</code>
+     * @see #detectPoolingBasedWatchService(Optional)
+     */
+    protected static boolean isBasedPoolingWatchService() {
+        return basedPoolingWatchService;
+    }
+
+    private static String getThreadPoolPrefixName(URL url) {
+        return getParameter(url, THREAD_POOL_PREFIX_PARAM_NAME, DEFAULT_THREAD_POOL_PREFIX);
+    }
+
+    protected static ThreadPoolExecutor getWatchEventsLoopThreadPool() {
+        return watchEventsLoopThreadPool;
+    }
+
+    private <V> V executeMutually(Object mutex, Callable<V> callable) {
+        V value = null;
+        synchronized (mutex) {
+            try {
+                value = callable.call();
+            } catch (Exception e) {
+                if (logger.isErrorEnabled()) {
+                    logger.error(e.getMessage(), e);
+                }
+            }
+        }
+        return value;
+    }
+
+    private static <T> T[] of(T... values) {
+        return values;
+    }
+
+    private static Integer initDelay(WatchEvent.Modifier[] modifiers) {
+        return Stream.of(modifiers)
+                .filter(modifier -> modifier instanceof SensitivityWatchEventModifier)
+                .map(SensitivityWatchEventModifier.class::cast)
+                .map(SensitivityWatchEventModifier::sensitivityValueInSeconds)
+                .max(Integer::compareTo)
+                .orElse(null);
+    }
+
+    private static WatchEvent.Modifier[] initWatchEventModifiers() {
+        if (isBasedPoolingWatchService()) { // If based on PollingWatchService, High sensitivity will be used
+            return of(SensitivityWatchEventModifier.HIGH);
+        } else {
+            return of();
+        }
+    }
+
+    /**
+     * Detect the argument of {@link WatchService} is based on {@linkplain sun.nio.fs.PollingWatchService}
+     * or not.
+     * <p>
+     * Some platforms do not provide the native implementation of {@link WatchService}, just use
+     * {@linkplain sun.nio.fs.PollingWatchService} in periodic poll file modifications.
+     *
+     * @param watchService the instance of {@link WatchService}
+     * @return if based, return <code>true</code>, or <code>false</code>
+     */
+    private static boolean detectPoolingBasedWatchService(Optional<WatchService> watchService) {
+        String className = watchService.map(Object::getClass).map(Class::getName).orElse(null);
+        return POLLING_WATCH_SERVICE_CLASS_NAME.equals(className);
+    }
+
+    private static Optional<WatchService> newWatchService() {
+        Optional<WatchService> watchService = null;
+        FileSystem fileSystem = FileSystems.getDefault();
+        try {
+            watchService = Optional.of(fileSystem.newWatchService());
+        } catch (IOException e) {
+            if (logger.isErrorEnabled()) {
+                logger.error(e.getMessage(), e);
+            }
+            watchService = Optional.empty();
+        }
+        return watchService;
+    }
+
+    private static File initDirectory(URL url) {
+        String directoryPath = getParameter(url, CONFIG_CENTER_DIR_PARAM_NAME, DEFAULT_CONFIG_CENTER_DIR_PATH);
+        File rootDirectory = new File(getParameter(url, CONFIG_CENTER_DIR_PARAM_NAME, DEFAULT_CONFIG_CENTER_DIR_PATH));
+        if (!rootDirectory.exists() && !rootDirectory.mkdirs()) {
+            throw new IllegalStateException(format("Dubbo config center rootDirectory[%s] can't be created!",
+                    directoryPath));
+        }
+        return rootDirectory;
+    }
+
+    private static String getParameter(URL url, String name, String defaultValue) {
+        if (url != null) {
+            return url.getParameter(name, defaultValue);
+        }
+        return defaultValue;
+    }
+
+    private static String getEncoding(URL url) {
+        return getParameter(url, CONFIG_CENTER_ENCODING_PARAM_NAME, DEFAULT_CONFIG_CENTER_ENCODING);
+    }
+
+    private static int getThreadPoolSize(URL url) {
+        return Integer.parseInt(getParameter(url, THREAD_POOL_SIZE_PARAM_NAME, DEFAULT_THREAD_POOL_SIZE));
+    }
+
+    private static ThreadPoolExecutor newWatchEventsLoopThreadPool() {
+        return new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE,
+                0L, MILLISECONDS,
+                new SynchronousQueue(),
+                new NamedThreadFactory("dubbo-config-center-watch-events-loop", true));
+    }
+}
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationFactory.java
similarity index 57%
rename from dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java
rename to dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationFactory.java
index 7ed1de5..f2a1332 100644
--- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/AbstractSettings.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationFactory.java
@@ -14,23 +14,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.bootstrap;
+package org.apache.dubbo.common.config.configcenter.file;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory;
+import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
+import org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory;
 
 /**
- * Abstract {@link Settings}
+ * File-System based {@link DynamicConfigurationFactory} implementation
  *
  * @since 2.7.4
  */
-public class AbstractSettings implements Settings {
-
-    private final DubboBootstrap dubboBootstrap;
-
-    public AbstractSettings(DubboBootstrap dubboBootstrap) {
-        this.dubboBootstrap = dubboBootstrap;
-    }
+public class FileSystemDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory {
 
     @Override
-    public DubboBootstrap next() {
-        return dubboBootstrap;
+    protected DynamicConfiguration createDynamicConfiguration(URL url) {
+        return new FileSystemDynamicConfiguration(url);
     }
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java
index 14accb2..a69f115 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfiguration.java
@@ -28,6 +28,7 @@ import static java.util.Collections.emptySortedSet;
  * The default extension of {@link DynamicConfiguration}. If user does not specify a config centre, or specifies one
  * that is not a valid extension, it will default to this one.
  */
+@Deprecated
 public class NopDynamicConfiguration implements DynamicConfiguration {
 
     public NopDynamicConfiguration(URL url) {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfigurationFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfigurationFactory.java
index bd45e7f..487f70d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfigurationFactory.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/nop/NopDynamicConfigurationFactory.java
@@ -23,6 +23,7 @@ import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
 /**
  *
  */
+@Deprecated
 public class NopDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory {
 
     @Override
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java
index 7f98d38..016265d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java
@@ -89,9 +89,6 @@ public class CompositeDynamicConfiguration implements DynamicConfiguration {
         Object value = null;
         for (DynamicConfiguration configuration : configurations) {
             value = func.apply(configuration);
-            if (value != null) {
-                break;
-            }
         }
         return value;
     }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
index 2720229..f8e987c 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
@@ -21,6 +21,9 @@ import javassist.CtConstructor;
 import javassist.CtMethod;
 import javassist.NotFoundException;
 
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
 import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
@@ -48,6 +51,7 @@ import java.util.concurrent.Future;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.unmodifiableSet;
@@ -1127,7 +1131,7 @@ public final class ReflectUtils {
         }
         return new Type[]{returnType, genericReturnType};
     }
-  
+
     /**
      * Find the {@link Set} of {@link ParameterizedType}
      *
@@ -1184,4 +1188,28 @@ public final class ReflectUtils {
 
         return unmodifiableSet(hierarchicalTypes);
     }
+
+    public static <T> T getProperty(Object bean, String propertyName) {
+        Class<?> beanClass = bean.getClass();
+        BeanInfo beanInfo = null;
+        T propertyValue = null;
+        try {
+            beanInfo = Introspector.getBeanInfo(beanClass);
+            propertyValue = (T) Stream.of(beanInfo.getPropertyDescriptors())
+                    .filter(propertyDescriptor -> propertyName.equals(propertyDescriptor.getName()))
+                    .map(PropertyDescriptor::getReadMethod)
+                    .findFirst()
+                    .map(method -> {
+                        try {
+                            return method.invoke(bean);
+                        } catch (Exception e) {
+                        }
+                        return null;
+                    }).get();
+        } catch (Exception e) {
+
+        }
+        return propertyValue;
+    }
+
 }
\ No newline at end of file
diff --git a/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory
index 42d6a25..f6fe6d6 100644
--- a/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory
+++ b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory
@@ -1 +1,2 @@
-nop=org.apache.dubbo.common.config.configcenter.nop.NopDynamicConfigurationFactory
\ No newline at end of file
+nop=org.apache.dubbo.common.config.configcenter.nop.NopDynamicConfigurationFactory
+file=org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfigurationFactory
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java b/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactoryTest.java
similarity index 51%
rename from dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java
rename to dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactoryTest.java
index 290bb7e..eacd3ee 100644
--- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/Settings.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/DynamicConfigurationFactoryTest.java
@@ -14,19 +14,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.bootstrap;
+package org.apache.dubbo.common.config.configcenter;
+
+import org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfigurationFactory;
+
+import org.junit.jupiter.api.Test;
+
+import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 /**
- * The Dubbo settings
+ * {@link DynamicConfigurationFactory} Test
  *
  * @since 2.7.4
  */
-public interface Settings {
+public class DynamicConfigurationFactoryTest {
 
-    /**
-     * Go next settings
-     *
-     * @return {@link DubboBootstrap}
-     */
-    DubboBootstrap next();
+    @Test
+    public void testDefaultExtension() {
+        DynamicConfigurationFactory factory = getExtensionLoader(DynamicConfigurationFactory.class).getDefaultExtension();
+        assertEquals(FileSystemDynamicConfigurationFactory.class, factory.getClass());
+        assertEquals(factory, getExtensionLoader(DynamicConfigurationFactory.class).getExtension("file"));
+    }
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationTest.java
new file mode 100644
index 0000000..c68cd4c
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfigurationTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.config.configcenter.file;
+
+import org.apache.dubbo.common.URL;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static java.util.Collections.singleton;
+import static org.apache.commons.io.FileUtils.deleteQuietly;
+import static org.apache.dubbo.common.URL.valueOf;
+import static org.apache.dubbo.common.config.configcenter.DynamicConfiguration.DEFAULT_GROUP;
+import static org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfiguration.CONFIG_CENTER_DIR_PARAM_NAME;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * {@link FileSystemDynamicConfiguration} Test
+ */
+public class FileSystemDynamicConfigurationTest {
+
+    private FileSystemDynamicConfiguration configuration;
+
+    private static final String KEY = "abc-def-ghi";
+
+    private static final String CONTENT = "Hello,World";
+
+    @BeforeEach
+    public void init() {
+        String classPath = getClassPath();
+        URL url = valueOf("dubbo://127.0.0.1:20880").addParameter(CONFIG_CENTER_DIR_PARAM_NAME, classPath + File.separator + "config-center");
+        configuration = new FileSystemDynamicConfiguration(url);
+        deleteQuietly(configuration.getRootDirectory());
+    }
+
+    private String getClassPath() {
+        return getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
+    }
+
+    @Test
+    public void testInit() {
+
+        assertEquals(new File(getClassPath(), "config-center"), configuration.getRootDirectory());
+        assertEquals("UTF-8", configuration.getEncoding());
+        assertEquals(ThreadPoolExecutor.class, configuration.getWorkersThreadPool().getClass());
+        assertEquals(1, (configuration.getWorkersThreadPool()).getCorePoolSize());
+        assertEquals(1, (configuration.getWorkersThreadPool()).getMaximumPoolSize());
+        assertNotNull(configuration.getWatchEventsLoopThreadPool());
+        assertEquals(1, (configuration.getWatchEventsLoopThreadPool()).getCorePoolSize());
+        assertEquals(1, (configuration.getWatchEventsLoopThreadPool()).getMaximumPoolSize());
+
+        if (configuration.isBasedPoolingWatchService()) {
+            assertEquals(2, configuration.getDelay());
+        } else {
+            assertNull(configuration.getDelay());
+        }
+    }
+
+    @Test
+    public void testPublishAndGetConfig() {
+        assertTrue(configuration.publishConfig(KEY, CONTENT));
+        assertTrue(configuration.publishConfig(KEY, CONTENT));
+        assertTrue(configuration.publishConfig(KEY, CONTENT));
+        assertEquals(CONTENT, configuration.getConfig(KEY));
+        assertTrue(configuration.getConfigs(null).size() > 0);
+    }
+
+    @Test
+    public void testPublishAndRemoveConfig() throws InterruptedException {
+        assertTrue(configuration.publishConfig(KEY, CONTENT));
+        configuration.addListener(KEY, event -> {
+            System.out.printf("[%s] " + event + "\n", Thread.currentThread().getName());
+
+        });
+        assertTrue(configuration.publishConfig(KEY, CONTENT));
+        assertEquals(CONTENT, configuration.removeConfig(KEY));
+        Thread.sleep(configuration.getDelay() * 1000);
+    }
+
+    @Test
+    public void testGetConfigsAndGroups() {
+        assertTrue(configuration.publishConfig(KEY, CONTENT));
+        assertEquals(singleton(KEY), configuration.getConfigKeys(DEFAULT_GROUP));
+        assertEquals(singleton(DEFAULT_GROUP), configuration.getConfigGroups());
+
+        assertTrue(configuration.publishConfig(KEY, "test", CONTENT));
+        assertEquals(singleton(KEY), configuration.getConfigKeys(DEFAULT_GROUP));
+        assertTrue(configuration.getConfigGroups().contains(DEFAULT_GROUP));
+        assertTrue(configuration.getConfigGroups().contains("test"));
+    }
+
+    @Test
+    public void testAddAndRemoveListener() throws InterruptedException {
+
+        configuration.publishConfig(KEY, "A");
+
+        AtomicBoolean processedEvent = new AtomicBoolean();
+
+        configuration.addListener(KEY, event -> {
+
+            processedEvent.set(true);
+            assertEquals(KEY, event.getKey());
+            System.out.printf("[%s] " + event + "\n", Thread.currentThread().getName());
+        });
+
+
+        configuration.publishConfig(KEY, "B");
+        while (!processedEvent.get()) {
+            Thread.sleep(1 * 1000L);
+        }
+
+        processedEvent.set(false);
+        configuration.publishConfig(KEY, "C");
+        while (!processedEvent.get()) {
+            Thread.sleep(1 * 1000L);
+        }
+
+        processedEvent.set(false);
+        configuration.publishConfig(KEY, "D");
+        while (!processedEvent.get()) {
+            Thread.sleep(1 * 1000L);
+        }
+
+        configuration.addListener("test", "test", event -> {
+            processedEvent.set(true);
+            assertEquals("test", event.getKey());
+            System.out.printf("[%s] " + event + "\n", Thread.currentThread().getName());
+        });
+        processedEvent.set(false);
+        configuration.publishConfig("test", "test", "TEST");
+        while (!processedEvent.get()) {
+            Thread.sleep(1 * 1000L);
+        }
+
+        configuration.publishConfig("test", "test", "TEST");
+        configuration.publishConfig("test", "test", "TEST");
+        configuration.publishConfig("test", "test", "TEST");
+
+
+        processedEvent.set(false);
+        File keyFile = configuration.configFile(KEY, DEFAULT_GROUP);
+        FileUtils.deleteQuietly(keyFile);
+        while (!processedEvent.get()) {
+            Thread.sleep(1 * 1000L);
+        }
+    }
+}
diff --git a/dubbo-common/src/test/resources/log4j.xml b/dubbo-common/src/test/resources/log4j.xml
index bfb523c..21ea447 100644
--- a/dubbo-common/src/test/resources/log4j.xml
+++ b/dubbo-common/src/test/resources/log4j.xml
@@ -21,14 +21,14 @@
     <!-- 以下是appender的定义 -->
     <!-- ===================================================================== -->
     <appender name="dubbo" class="org.apache.dubbo.common.utils.DubboAppender">
-        <param name="File" value="../dubbo.log"/>
+        <param name="File" value="${user.dir}/dubbo.log"/>
         <param name="encoding" value="GBK"/>
         <layout class="org.apache.log4j.PatternLayout">
             <param name="ConversionPattern" value="%d %p [%c:%M] - %m%n"/>
         </layout>
     </appender>
     <root>
-        <level value="INFO"/>
+        <level value="DEBUG"/>
         <appender-ref ref="dubbo"/>
     </root>
 </log4j:configuration>
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
index 1ad15ec..874e38b 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java
@@ -255,7 +255,6 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
     }
 
     /**
-     *
      * Load the registry and conversion it to {@link URL}, the priority order is: system property > dubbo registry config
      *
      * @param provider whether it is the provider side
@@ -298,7 +297,6 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
     }
 
     /**
-     *
      * Load the monitor config from the system properties and conversation it to {@link URL}
      *
      * @param registryURL
@@ -358,7 +356,7 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
      * methods configured in the configuration file are included in the interface of remote service
      *
      * @param interfaceClass the interface of remote service
-     * @param methods the methods configured
+     * @param methods        the methods configured
      */
     protected void checkInterfaceAndMethods(Class<?> interfaceClass, List<MethodConfig> methods) {
         // interface cannot be null
@@ -466,15 +464,14 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
     private void convertRegistryIdsToRegistries() {
         if (StringUtils.isEmpty(registryIds)) {
             if (CollectionUtils.isEmpty(registries)) {
-                setRegistries(
-                        ConfigManager.getInstance().getDefaultRegistries()
-                        .filter(CollectionUtils::isNotEmpty)
-                        .orElseGet(() -> {
-                            RegistryConfig registryConfig = new RegistryConfig();
-                            registryConfig.refresh();
-                            return Arrays.asList(registryConfig);
-                        })
-                );
+                List<RegistryConfig> registryConfigs = ConfigManager.getInstance().getDefaultRegistries();
+                if (registryConfigs.isEmpty()) {
+                    registryConfigs = new ArrayList<>();
+                    RegistryConfig registryConfig = new RegistryConfig();
+                    registryConfig.refresh();
+                    registryConfigs.add(registryConfig);
+                }
+                setRegistries(registryConfigs);
             }
         } else {
             String[] ids = COMMA_SPLIT_PATTERN.split(registryIds);
@@ -668,7 +665,7 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
 
     @SuppressWarnings({"unchecked"})
     public void setRegistries(List<? extends RegistryConfig> registries) {
-        ConfigManager.getInstance().addRegistries((List<RegistryConfig>) registries, false);
+        ConfigManager.getInstance().addRegistries((List<RegistryConfig>) registries);
         this.registries = (List<RegistryConfig>) registries;
     }
 
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
index c9a96cb..a5196df 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
@@ -16,6 +16,7 @@
  */
 package org.apache.dubbo.config;
 
+import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.support.Parameter;
 import org.apache.dubbo.remoting.Constants;
@@ -179,9 +180,14 @@ public class RegistryConfig extends AbstractConfig {
     public void setAddress(String address) {
         this.address = address;
         if (address != null) {
-            int i = address.indexOf("://");
-            if (i > 0) {
-                this.updateIdIfAbsent(address.substring(0, i));
+            try {
+                URL url = URL.valueOf(address);
+                setUsername(url.getUsername());
+                setPassword(url.getPassword());
+                setProtocol(url.getProtocol());
+                setPort(url.getPort());
+                setParameters(url.getParameters());
+            } catch (Exception ignored) {
             }
         }
     }
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 fb9d247..c851ca1 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
@@ -882,15 +882,14 @@ public class ServiceConfig<T> extends AbstractServiceConfig {
     private void convertProtocolIdsToProtocols() {
         if (StringUtils.isEmpty(protocolIds)) {
             if (CollectionUtils.isEmpty(protocols)) {
-                setProtocols(
-                        ConfigManager.getInstance().getDefaultProtocols()
-                                .filter(CollectionUtils::isNotEmpty)
-                                .orElseGet(() -> {
-                                    ProtocolConfig protocolConfig = new ProtocolConfig();
-                                    protocolConfig.refresh();
-                                    return new ArrayList<>(Arrays.asList(protocolConfig));
-                                })
-                );
+                List<ProtocolConfig> protocolConfigs = ConfigManager.getInstance().getDefaultProtocols();
+                if (protocolConfigs.isEmpty()) {
+                    protocolConfigs = new ArrayList<>(1);
+                    ProtocolConfig protocolConfig = new ProtocolConfig();
+                    protocolConfig.refresh();
+                    protocolConfigs.add(protocolConfig);
+                }
+                setProtocols(protocolConfigs);
             }
         } else {
             String[] arr = COMMA_SPLIT_PATTERN.split(protocolIds);
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java
index 12d09bf..1f51f1b 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/builders/AbstractBuilder.java
@@ -36,7 +36,7 @@ public abstract class AbstractBuilder<C extends AbstractConfig, B extends Abstra
     protected String id;
     protected String prefix;
 
-    protected B id(String id) {
+    public B id(String id) {
         this.id = id;
         return getThis();
     }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/context/ConfigManager.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
index 718d425..1888819 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
@@ -19,8 +19,6 @@ package org.apache.dubbo.config.context;
 import org.apache.dubbo.common.config.Environment;
 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.StringUtils;
 import org.apache.dubbo.config.AbstractConfig;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.ConfigCenterConfig;
@@ -34,16 +32,24 @@ import org.apache.dubbo.config.ReferenceConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.ServiceConfig;
 
-import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.StampedLock;
 import java.util.stream.Collectors;
 
+import static java.lang.Boolean.TRUE;
+import static java.util.Collections.unmodifiableSet;
+import static java.util.Optional.ofNullable;
 import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;
+import static org.apache.dubbo.common.utils.ReflectUtils.getProperty;
+import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
 import static org.apache.dubbo.config.Constants.PROTOCOLS_SUFFIX;
 import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
 
@@ -82,40 +88,34 @@ import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
  * All workflow internally can rely on ConfigManager.
  */
 public class ConfigManager {
-    private static final Logger logger = LoggerFactory.getLogger(ConfigManager.class);
-    private static final ConfigManager CONFIG_MANAGER = new ConfigManager();
 
-    private ApplicationConfig application;
-    private MonitorConfig monitor;
-    private ModuleConfig module;
+    private static final Logger logger = LoggerFactory.getLogger(ConfigManager.class);
 
-    private Map<String, ProtocolConfig> protocols = new ConcurrentHashMap<>();
-    private Map<String, RegistryConfig> registries = new ConcurrentHashMap<>();
-    private Map<String, ProviderConfig> providers = new ConcurrentHashMap<>();
-    private Map<String, ConsumerConfig> consumers = new ConcurrentHashMap<>();
+    private static final ConfigManager CONFIG_MANAGER = new ConfigManager();
 
-    private List<ProtocolConfig> defaultProtocols = new ArrayList<>();
-    private List<RegistryConfig> defaultRegistries = new ArrayList<>();
+    private volatile ModuleConfig module;
+    private volatile ApplicationConfig application;
+    private volatile MonitorConfig monitor;
 
-    private Set<ConfigCenterConfig> configCenters = new HashSet<>();
-    private Set<MetadataReportConfig> metadataConfigs = new HashSet<>();
-    private Set<String> registryIds = new HashSet<>();
-    private Set<String> protocolIds = new HashSet<>();
+    private final Map<String, ProtocolConfig> protocols = new ConcurrentHashMap<>();
+    private final Map<String, RegistryConfig> registries = new ConcurrentHashMap<>();
+    private final Map<String, ProviderConfig> providers = new ConcurrentHashMap<>();
+    private final Map<String, ConsumerConfig> consumers = new ConcurrentHashMap<>();
+    private final Map<String, ConfigCenterConfig> configCenters = new ConcurrentHashMap<>();
+    private final Map<String, MetadataReportConfig> metadataConfigs = new ConcurrentHashMap<>();
+    private final Map<String, ServiceConfig<?>> serviceConfigs = new ConcurrentHashMap<>();
+    private final Map<String, ReferenceConfig<?>> referenceConfigs = new ConcurrentHashMap<>();
 
-    private List<ServiceConfig<?>> serviceConfigs = new ArrayList<>();
-    private List<ReferenceConfig<?>> referenceConfigs = new ArrayList<>();
+    private final StampedLock lock = new StampedLock();
 
     public static ConfigManager getInstance() {
         return CONFIG_MANAGER;
     }
 
     private ConfigManager() {
-
     }
 
-    public Optional<ApplicationConfig> getApplication() {
-        return Optional.ofNullable(application);
-    }
+    // ApplicationConfig correlative methods
 
     public void setApplication(ApplicationConfig application) {
         if (application != null) {
@@ -124,10 +124,12 @@ public class ConfigManager {
         }
     }
 
-    public Optional<MonitorConfig> getMonitor() {
-        return Optional.ofNullable(monitor);
+    public Optional<ApplicationConfig> getApplication() {
+        return ofNullable(application);
     }
 
+    // MonitorConfig correlative methods
+
     public void setMonitor(MonitorConfig monitor) {
         if (monitor != null) {
             checkDuplicate(this.monitor, monitor);
@@ -135,10 +137,12 @@ public class ConfigManager {
         }
     }
 
-    public Optional<ModuleConfig> getModule() {
-        return Optional.ofNullable(module);
+    public Optional<MonitorConfig> getMonitor() {
+        return ofNullable(monitor);
     }
 
+    // ModuleConfig correlative methods
+
     public void setModule(ModuleConfig module) {
         if (module != null) {
             checkDuplicate(this.module, module);
@@ -146,210 +150,175 @@ public class ConfigManager {
         }
     }
 
-    public Set<ConfigCenterConfig> getConfigCenters() {
-        return configCenters;
+    public Optional<ModuleConfig> getModule() {
+        return ofNullable(module);
     }
 
+    // ConfigCenterConfig correlative methods
+
     public void addConfigCenter(ConfigCenterConfig configCenter) {
-        if (configCenter != null && !configCenters.contains(configCenter)) {
-            this.configCenters.add(configCenter);
-        }
+        addIfAbsent(configCenter, configCenters);
     }
 
-    public void addConfigCenter(List<ConfigCenterConfig> configCenters) {
-        if (CollectionUtils.isNotEmpty(configCenters)) {
-            this.configCenters.addAll(configCenters);
-        }
+    public void addConfigCenters(Iterable<ConfigCenterConfig> configCenters) {
+        configCenters.forEach(this::addConfigCenter);
+    }
+
+    public ConfigCenterConfig getConfigCenter(String id) {
+        return configCenters.get(id);
     }
 
-    public Set<MetadataReportConfig> getMetadataConfigs() {
-        return metadataConfigs;
+    public Collection<ConfigCenterConfig> getConfigCenters() {
+        return configCenters.values();
     }
 
+    // MetadataReportConfig correlative methods
+
     public void addMetadataReport(MetadataReportConfig metadataReportConfig) {
-        if (metadataReportConfig != null && !metadataConfigs.contains(metadataReportConfig)) {
-            this.metadataConfigs.add(metadataReportConfig);
-        }
+        addIfAbsent(metadataReportConfig, metadataConfigs);
     }
 
-    public void addMetadataReport(List<MetadataReportConfig> metadataReportConfigs) {
-        if (CollectionUtils.isNotEmpty(metadataReportConfigs)) {
-            this.metadataConfigs.addAll(metadataReportConfigs);
-        }
+    public void addMetadataReports(Iterable<MetadataReportConfig> metadataReportConfigs) {
+        metadataReportConfigs.forEach(this::addMetadataReport);
+    }
+
+    public Collection<MetadataReportConfig> getMetadataConfigs() {
+        return metadataConfigs.values();
+    }
+
+    // MetadataReportConfig correlative methods
+
+    public void addProvider(ProviderConfig providerConfig) {
+        addIfAbsent(providerConfig, providers);
     }
 
     public Optional<ProviderConfig> getProvider(String id) {
-        return Optional.ofNullable(providers.get(id));
+        return ofNullable(providers.get(id));
     }
 
     public Optional<ProviderConfig> getDefaultProvider() {
-        return Optional.ofNullable(providers.get(DEFAULT_KEY));
+        return getProvider(DEFAULT_KEY);
     }
 
-    public void addProvider(ProviderConfig providerConfig) {
-        if (providerConfig == null) {
-            return;
-        }
+    public Collection<ProviderConfig> getProviders() {
+        return providers.values();
+    }
 
-        String key = StringUtils.isNotEmpty(providerConfig.getId())
-                ? providerConfig.getId()
-                : (providerConfig.isDefault() == null || providerConfig.isDefault()) ? DEFAULT_KEY : null;
+    // ConsumerConfig correlative methods
 
-        if (StringUtils.isEmpty(key)) {
-            throw new IllegalStateException("A ProviderConfig should either has an id or it's the default one, " + providerConfig);
-        }
-
-        if (providers.containsKey(key) && !providerConfig.equals(providers.get(key))) {
-            logger.warn("Duplicate ProviderConfig found, there already has one default ProviderConfig or more than two ProviderConfigs have the same id, " +
-                                                    "you can try to give each ProviderConfig a different id. " + providerConfig);
-        } else {
-            providers.put(key, providerConfig);
-        }
+    public void addConsumer(ConsumerConfig consumerConfig) {
+        addIfAbsent(consumerConfig, consumers);
     }
 
     public Optional<ConsumerConfig> getConsumer(String id) {
-        return Optional.ofNullable(consumers.get(id));
+        return ofNullable(consumers.get(id));
     }
 
     public Optional<ConsumerConfig> getDefaultConsumer() {
-        return Optional.ofNullable(consumers.get(DEFAULT_KEY));
+        return getConsumer(DEFAULT_KEY);
     }
 
-    public void addConsumer(ConsumerConfig consumerConfig) {
-        if (consumerConfig == null) {
-            return;
-        }
+    public Collection<ConsumerConfig> getConsumers() {
+        return consumers.values();
+    }
 
-        String key = StringUtils.isNotEmpty(consumerConfig.getId())
-                ? consumerConfig.getId()
-                : (consumerConfig.isDefault() == null || consumerConfig.isDefault()) ? DEFAULT_KEY : null;
+    // ProtocolConfig correlative methods
 
-        if (StringUtils.isEmpty(key)) {
-            throw new IllegalStateException("A ConsumerConfig should either has an id or it's the default one, " + consumerConfig);
-        }
+    public void addProtocol(ProtocolConfig protocolConfig) {
+        addIfAbsent(protocolConfig, protocols);
+    }
 
-        if (consumers.containsKey(key) && !consumerConfig.equals(consumers.get(key))) {
-            logger.warn("Duplicate ConsumerConfig found, there already has one default ConsumerConfig or more than two ConsumerConfigs have the same id, " +
-                                                    "you can try to give each ConsumerConfig a different id. " + consumerConfig);
-        } else {
-            consumers.put(key, consumerConfig);
+    public void addProtocols(Iterable<ProtocolConfig> protocolConfigs, boolean canBeDefault) {
+        if (protocolConfigs != null) {
+            protocolConfigs.forEach(this::addProtocol);
         }
     }
 
     public Optional<ProtocolConfig> getProtocol(String id) {
-        return Optional.ofNullable(protocols.get(id));
+        return ofNullable(protocols.get(id));
     }
 
-    public Optional<List<ProtocolConfig>> getDefaultProtocols() {
-        return Optional.of(defaultProtocols);
+    public List<ProtocolConfig> getDefaultProtocols() {
+        return getDefaultConfigs(protocols);
     }
 
-    public void addProtocols(List<ProtocolConfig> protocolConfigs, boolean canBeDefault) {
-        if (protocolConfigs != null) {
-            protocolConfigs.forEach(pc -> this.addProtocol(pc, canBeDefault));
-        }
+    public Collection<ProtocolConfig> getProtocols() {
+        return protocols.values();
     }
 
-    public void addProtocol(ProtocolConfig protocolConfig, boolean canBeDefault) {
-        if (protocolConfig == null) {
-            return;
-        }
+    public Set<String> getProtocolIds() {
+        Set<String> protocolIds = new HashSet<>();
+        protocolIds.addAll(getSubProperties(Environment.getInstance()
+                .getExternalConfigurationMap(), PROTOCOLS_SUFFIX));
+        protocolIds.addAll(getSubProperties(Environment.getInstance()
+                .getAppExternalConfigurationMap(), PROTOCOLS_SUFFIX));
 
-        // if isDefault is not false and a ProtocolConfig is not specified being false.
-        if (canBeDefault && (protocolConfig.isDefault() == null || protocolConfig.isDefault())) {
-            this.defaultProtocols.add(protocolConfig);
-        }
+        protocolIds.addAll(protocols.keySet());
+        return unmodifiableSet(protocolIds);
+    }
 
-        String key = StringUtils.isNotEmpty(protocolConfig.getId())
-                ? protocolConfig.getId()
-                : DEFAULT_KEY;
 
-        if (StringUtils.isEmpty(key)) {
-            throw new IllegalStateException("A ProtocolConfig should either has an id or it's the default one, " + protocolConfig);
-        }
+    // RegistryConfig correlative methods
 
-        if (protocols.containsKey(key) && !protocolConfig.equals(protocols.get(key))) {
-            logger.warn("Duplicate ProtocolConfig found, there already has one default ProtocolConfig or more than two ProtocolConfigs have the same id, " +
-                                                    "you can try to give each ProtocolConfig a different id. " + protocolConfig);
-        } else {
-            protocols.put(key, protocolConfig);
+    public void addRegistry(RegistryConfig registryConfig) {
+        addIfAbsent(registryConfig, registries);
+    }
+
+    public void addRegistries(Iterable<RegistryConfig> registryConfigs) {
+        if (registryConfigs != null) {
+            registryConfigs.forEach(this::addRegistry);
         }
     }
 
     public Optional<RegistryConfig> getRegistry(String id) {
-        return Optional.ofNullable(registries.get(id));
+        return ofNullable(registries.get(id));
     }
 
-    public Optional<List<RegistryConfig>> getDefaultRegistries() {
-        return Optional.of(defaultRegistries);
+    public List<RegistryConfig> getDefaultRegistries() {
+        return getDefaultConfigs(registries);
     }
 
-    public void addRegistries(List<RegistryConfig> registryConfigs, boolean canBeDefault) {
-        if (registryConfigs != null) {
-            registryConfigs.forEach(rc -> this.addRegistry(rc, canBeDefault));
-        }
+    public Collection<RegistryConfig> getRegistries() {
+        return registries.values();
     }
 
-    public void addRegistry(RegistryConfig registryConfig, boolean canBeDefault) {
-        if (registryConfig == null) {
-            return;
-        }
+    public Set<String> getRegistryIds() {
+        Set<String> registryIds = new HashSet<>();
+        registryIds.addAll(getSubProperties(Environment.getInstance().getExternalConfigurationMap(),
+                REGISTRIES_SUFFIX));
+        registryIds.addAll(getSubProperties(Environment.getInstance().getAppExternalConfigurationMap(),
+                REGISTRIES_SUFFIX));
 
-        if (canBeDefault && (registryConfig.isDefault() == null || registryConfig.isDefault())) {
-            this.defaultRegistries.add(registryConfig);
-        }
-        String key = StringUtils.isNotEmpty(registryConfig.getId())
-                ? registryConfig.getId()
-                : DEFAULT_KEY;
+        registryIds.addAll(registries.keySet());
+        return unmodifiableSet(registryIds);
+    }
 
-        if (StringUtils.isEmpty(key)) {
-            throw new IllegalStateException("A RegistryConfig should either has an id or it's the default one, " + registryConfig);
-        }
+    // ServiceConfig correlative methods
 
-        if (registries.containsKey(key) && !registryConfig.equals(registries.get(key))) {
-            logger.warn("Duplicate RegistryConfig found, there already has one default RegistryConfig or more than two RegistryConfigs have the same id, " +
-                                                    "you can try to give each RegistryConfig a different id. " + registryConfig);
-        } else {
-            registries.put(key, registryConfig);
-        }
+    public void addService(ServiceConfig<?> serviceConfig) {
+        addIfAbsent(serviceConfig, serviceConfigs);
     }
 
-    public void addProtocolIds(List<String> protocolIds) {
-        this.protocolIds.addAll(protocolIds);
+    public Collection<ServiceConfig<?>> getServiceConfigs() {
+        return serviceConfigs.values();
     }
 
-    public void addRegistryIds(List<String> registryIds) {
-        this.registryIds.addAll(registryIds);
+    public <T> ServiceConfig<T> getServiceConfig(String id) {
+        return (ServiceConfig<T>) serviceConfigs.get(id);
     }
 
-    public void addService(ServiceConfig<?> serviceConfig) {
-        this.serviceConfigs.add(serviceConfig);
-    }
+    // ReferenceConfig correlative methods
 
     public void addReference(ReferenceConfig<?> referenceConfig) {
-        this.referenceConfigs.add(referenceConfig);
+        addIfAbsent(referenceConfig, referenceConfigs);
     }
 
-    public Set<String> getRegistryIds() {
-        Set<String> configedRegistries = new HashSet<>();
-        configedRegistries.addAll(getSubProperties(Environment.getInstance().getExternalConfigurationMap(),
-                REGISTRIES_SUFFIX));
-        configedRegistries.addAll(getSubProperties(Environment.getInstance().getAppExternalConfigurationMap(),
-                REGISTRIES_SUFFIX));
-
-        configedRegistries.addAll(registryIds);
-        return configedRegistries;
+    public Collection<ReferenceConfig<?>> getReferenceConfigs() {
+        return referenceConfigs.values();
     }
 
-    public Set<String> getProtocolIds() {
-        Set<String> configedProtocols = new HashSet<>();
-        configedProtocols.addAll(getSubProperties(Environment.getInstance()
-                .getExternalConfigurationMap(), PROTOCOLS_SUFFIX));
-        configedProtocols.addAll(getSubProperties(Environment.getInstance()
-                .getAppExternalConfigurationMap(), PROTOCOLS_SUFFIX));
-
-        configedProtocols.addAll(protocolIds);
-        return configedProtocols;
+    public <T> ReferenceConfig<T> getReferenceConfig(String id) {
+        return (ReferenceConfig<T>) referenceConfigs.get(id);
     }
 
     protected static Set<String> getSubProperties(Map<String, String> properties, String prefix) {
@@ -359,62 +328,130 @@ public class ConfigManager {
         }).collect(Collectors.toSet());
     }
 
-    public Map<String, ProtocolConfig> getProtocols() {
-        return protocols;
-    }
+    public void refreshAll() {
+        write(() -> {
+            // refresh all configs here,
+            getApplication().ifPresent(ApplicationConfig::refresh);
+            getMonitor().ifPresent(MonitorConfig::refresh);
+            getModule().ifPresent(ModuleConfig::refresh);
 
-    public Map<String, RegistryConfig> getRegistries() {
-        return registries;
-    }
+            getProtocols().forEach(ProtocolConfig::refresh);
+            getRegistries().forEach(RegistryConfig::refresh);
+            getProviders().forEach(ProviderConfig::refresh);
+            getConsumers().forEach(ConsumerConfig::refresh);
+        });
 
-    public Map<String, ProviderConfig> getProviders() {
-        return providers;
     }
 
-    public Map<String, ConsumerConfig> getConsumers() {
-        return consumers;
-    }
 
-    public List<ServiceConfig<?>> getServiceConfigs() {
-        return serviceConfigs;
+    // For test purpose
+    public void clear() {
+        write(() -> {
+            this.application = null;
+            this.monitor = null;
+            this.module = null;
+            this.registries.clear();
+            this.protocols.clear();
+            this.providers.clear();
+            this.consumers.clear();
+            this.configCenters.clear();
+            this.metadataConfigs.clear();
+        });
+    }
+
+    private <V> V write(Callable<V> callable) {
+        V value = null;
+        long stamp = lock.writeLock();
+        try {
+            value = callable.call();
+        } catch (Throwable e) {
+            throw new RuntimeException(e);
+        } finally {
+            lock.unlockWrite(stamp);
+        }
+        return value;
     }
 
-    public List<ReferenceConfig<?>> getReferenceConfigs() {
-        return referenceConfigs;
+    private void write(Runnable runnable) {
+        write(() -> {
+            runnable.run();
+            return null;
+        });
     }
 
-    public void refreshAll() {
-        // refresh all configs here,
-        getApplication().ifPresent(ApplicationConfig::refresh);
-        getMonitor().ifPresent(MonitorConfig::refresh);
-        getModule().ifPresent(ModuleConfig::refresh);
 
-        getProtocols().values().forEach(ProtocolConfig::refresh);
-        getRegistries().values().forEach(RegistryConfig::refresh);
-        getProviders().values().forEach(ProviderConfig::refresh);
-        getConsumers().values().forEach(ConsumerConfig::refresh);
+    private <V> V read(Callable<V> callable) {
+        long stamp = lock.tryOptimisticRead();
+
+        boolean readLock = false;
+
+        V value = null;
+
+        try {
+            readLock = !lock.validate(stamp);
+
+            if (readLock) {
+                stamp = lock.readLock();
+            }
+            value = callable.call();
+        } catch (Throwable e) {
+            throw new RuntimeException(e);
+        } finally {
+            if (readLock) {
+                lock.unlockRead(stamp);
+            }
+        }
+
+        return value;
     }
 
-    private void checkDuplicate(AbstractConfig oldOne, AbstractConfig newOne) {
+    private static void checkDuplicate(AbstractConfig oldOne, AbstractConfig newOne) {
         if (oldOne != null && !oldOne.equals(newOne)) {
             String configName = oldOne.getClass().getSimpleName();
             throw new IllegalStateException("Duplicate Config found for " + configName + ", you should use only one unique " + configName + " for one application.");
         }
     }
 
-    // For test purpose
-    public void clear() {
-        this.application = null;
-        this.monitor = null;
-        this.module = null;
-        this.registries.clear();
-        this.protocols.clear();
-        this.providers.clear();
-        this.consumers.clear();
-        this.configCenters.clear();
-        this.metadataConfigs.clear();
-        this.registryIds.clear();
-        this.protocolIds.clear();
+    private static Map<Class<? extends AbstractConfig>, Map<String, ? extends AbstractConfig>> newMap() {
+        return new HashMap<>();
+    }
+
+    private static <C extends AbstractConfig> void addIfAbsent(C config, Map<String, C> configsMap) {
+
+        if (config == null) {
+            return;
+        }
+
+        String key = getId(config);
+
+        C existedConfig = configsMap.get(key);
+
+        if (existedConfig != null && !config.equals(existedConfig)) {
+            if (logger.isWarnEnabled()) {
+                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 : %s", type, type, type, type, config));
+            }
+        } else {
+            configsMap.put(key, config);
+        }
+    }
+
+    static <C extends AbstractConfig> String getId(C config) {
+        String id = config.getId();
+        return isNotEmpty(id) ? id : isDefaultConfig(config) ?
+                config.getClass().getSimpleName() + "#" + DEFAULT_KEY : null;
     }
 
+    static <C extends AbstractConfig> boolean isDefaultConfig(C config) {
+        Boolean isDefault = getProperty(config, "default");
+        return isDefault == null || TRUE.equals(isDefault);
+    }
+
+    static <C extends AbstractConfig> List<C> getDefaultConfigs(Map<String, C> configsMap) {
+        return configsMap.values()
+                .stream()
+                .filter(ConfigManager::isDefaultConfig)
+                .collect(Collectors.toList());
+    }
 }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ServiceInstancePortCustomizer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ServiceInstancePortCustomizer.java
index 37e9b3c..25c4d20 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ServiceInstancePortCustomizer.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/metadata/ServiceInstancePortCustomizer.java
@@ -38,7 +38,6 @@ public class ServiceInstancePortCustomizer implements ServiceInstanceCustomizer
 
         ConfigManager.getInstance()
                 .getProtocols()
-                .values()
                 .stream()
                 .findFirst()
                 .ifPresent(protocolConfig -> {
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
new file mode 100644
index 0000000..44e896d
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.context;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ModuleConfig;
+import org.apache.dubbo.config.MonitorConfig;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.dubbo.config.context.ConfigManager.getInstance;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * {@link ConfigManager} Test
+ *
+ * @since 2.7.4
+ */
+public class ConfigManagerTest {
+
+    private ConfigManager configManager = getInstance();
+
+    @BeforeEach
+    public void init() {
+        configManager.clear();
+        assertFalse(configManager.getApplication().isPresent());
+        assertFalse(configManager.getMonitor().isPresent());
+        assertFalse(configManager.getMonitor().isPresent());
+    }
+
+    @Test
+    public void testApplicationConfig() {
+        ApplicationConfig applicationConfig = new ApplicationConfig();
+        configManager.setApplication(applicationConfig);
+        assertTrue(configManager.getApplication().isPresent());
+        assertEquals(applicationConfig, configManager.getApplication().get());
+    }
+
+    @Test
+    public void testMonitorConfig() {
+        MonitorConfig monitorConfig = new MonitorConfig();
+        configManager.setMonitor(monitorConfig);
+        assertTrue(configManager.getMonitor().isPresent());
+        assertEquals(monitorConfig, configManager.getMonitor().get());
+    }
+
+    @Test
+    public void tesModuleConfig() {
+        ModuleConfig config = new ModuleConfig();
+        configManager.setModule(config);
+        assertTrue(configManager.getModule().isPresent());
+        assertEquals(config, configManager.getModule().get());
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporterTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporterTest.java
index e7db07d..43331e9 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporterTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/metadata/ConfigurableMetadataServiceExporterTest.java
@@ -49,9 +49,9 @@ public class ConfigurableMetadataServiceExporterTest {
         configManager.setApplication(applicationConfig);
 
         // Add ProtocolConfig
-        configManager.addProtocol(protocolConfig(), true);
+        configManager.addProtocol(protocolConfig());
         // Add RegistryConfig
-        configManager.addRegistry(registryConfig(), true);
+        configManager.addRegistry(registryConfig());
     }
 
     private static ProtocolConfig protocolConfig() {
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml
index f7064cd..3e56228 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml
@@ -21,8 +21,22 @@
     http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
     ">
 
+    <bean id="a" class="java.lang.String" abstract="true">
+        <property name="value" value="1" />
+    </bean>
+
+    <bean id="b" parent="a" >
+        <property name="value2" value="2" />
+    </bean>
+
+    <bean id="c" class="java.lang.Object">
+        <property name="b" ref="b" />
+    </bean>
+
     <!-- 当前应用信息配置 -->
-    <dubbo:application name="dubbo-spring-test"/>
+    <dubbo:application name="dubbo-spring-test" >
+        <dubbo:parameter key="" value="" />
+    </dubbo:application>
 
     <!-- 连接注册中心配置 -->
     <dubbo:registry address="N/A"/>
diff --git a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
index 8c827a3..6bcafcd 100644
--- a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
+++ b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
@@ -94,12 +94,19 @@ public class NacosDynamicConfiguration implements DynamicConfiguration {
     }
 
     public void publishNacosConfig(String key, String value) {
+        String[] keyAndGroup = getKeyAndGroup(key);
+        publishConfig(keyAndGroup[0], keyAndGroup[1], value);
+    }
+
+    @Override
+    public boolean publishConfig(String key, String group, String content) {
+        boolean published = false;
         try {
-            String[] keyAndGroup = getKeyAndGroup(key);
-            configService.publishConfig(keyAndGroup[0], keyAndGroup[1], value);
+            published = configService.publishConfig(key, group, content);
         } catch (NacosException e) {
             logger.error(e.getErrMsg());
         }
+        return published;
     }
 
     private String[] getKeyAndGroup(String key) {
@@ -107,7 +114,7 @@ public class NacosDynamicConfiguration implements DynamicConfiguration {
         if (i < 0) {
             return new String[]{key, null};
         } else {
-            return new String[]{key.substring(0, i), key.substring(i+1)};
+            return new String[]{key.substring(0, i), key.substring(i + 1)};
         }
     }
 
diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml
index d6cf69e..27e284f 100644
--- a/dubbo-dependencies-bom/pom.xml
+++ b/dubbo-dependencies-bom/pom.xml
@@ -15,14 +15,15 @@
   limitations under the License.
   -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
     <parent>
         <groupId>org.apache</groupId>
         <artifactId>apache</artifactId>
         <version>21</version>
-        <relativePath />
+        <relativePath/>
     </parent>
 
     <groupId>org.apache.dubbo</groupId>
@@ -135,6 +136,7 @@
         <log4j_version>1.2.16</log4j_version>
         <logback_version>1.2.2</logback_version>
         <log4j2_version>2.11.1</log4j2_version>
+        <commons_io_version>2.6</commons_io_version>
 
         <embedded_redis_version>0.6</embedded_redis_version>
 
@@ -443,6 +445,11 @@
                 <version>${jcl_version}</version>
             </dependency>
             <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>${commons_io_version}</version>
+            </dependency>
+            <dependency>
                 <groupId>log4j</groupId>
                 <artifactId>log4j</artifactId>
                 <version>${log4j_version}</version>
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/FileSystemServiceDiscovery.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/FileSystemServiceDiscovery.java
new file mode 100644
index 0000000..1dbf90d
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/FileSystemServiceDiscovery.java
@@ -0,0 +1,114 @@
+/*
+ * 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.registry.client;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory;
+import org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfiguration;
+import org.apache.dubbo.event.EventListener;
+import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;
+import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
+
+import java.util.Set;
+
+import static com.alibaba.fastjson.JSON.toJSONString;
+import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
+
+/**
+ * File System {@link ServiceDiscovery} implementation
+ *
+ * @see FileSystemDynamicConfiguration
+ * @since 2.7.4
+ */
+public class FileSystemServiceDiscovery implements ServiceDiscovery, EventListener<ServiceInstancesChangedEvent> {
+
+    private final URL connectionURL;
+
+    private FileSystemDynamicConfiguration dynamicConfiguration;
+
+    public FileSystemServiceDiscovery(URL connectionURL) {
+        this.connectionURL = connectionURL;
+    }
+
+    @Override
+    public void onEvent(ServiceInstancesChangedEvent event) {
+
+    }
+
+    @Override
+    public void start() {
+        if (dynamicConfiguration == null) {
+            dynamicConfiguration = createDynamicConfiguration(connectionURL);
+        }
+    }
+
+    @Override
+    public void stop() {
+        try {
+            if (dynamicConfiguration != null) {
+                dynamicConfiguration.close();
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private String getConfigKey(ServiceInstance serviceInstance) {
+        return serviceInstance.getId();
+    }
+
+    private String getConfigGroup(ServiceInstance serviceInstance) {
+        return serviceInstance.getServiceName();
+    }
+
+    @Override
+    public void register(ServiceInstance serviceInstance) throws RuntimeException {
+        String key = getConfigKey(serviceInstance);
+        String group = getConfigGroup(serviceInstance);
+        String content = toJSONString(serviceInstance);
+        dynamicConfiguration.publishConfig(key, group, content);
+    }
+
+    @Override
+    public void update(ServiceInstance serviceInstance) throws RuntimeException {
+        register(serviceInstance);
+    }
+
+    @Override
+    public void unregister(ServiceInstance serviceInstance) throws RuntimeException {
+        String key = getConfigKey(serviceInstance);
+        String group = getConfigGroup(serviceInstance);
+        dynamicConfiguration.removeConfig(key, group);
+    }
+
+    @Override
+    public Set<String> getServices() {
+        return null;
+    }
+
+    @Override
+    public void addServiceInstancesChangedListener(String serviceName, ServiceInstancesChangedListener listener) throws
+            NullPointerException, IllegalArgumentException {
+
+    }
+
+    private static FileSystemDynamicConfiguration createDynamicConfiguration(URL connectionURL) {
+        String protocol = connectionURL.getProtocol();
+        DynamicConfigurationFactory factory = getExtensionLoader(DynamicConfigurationFactory.class).getExtension(protocol);
+        return (FileSystemDynamicConfiguration) factory.getDynamicConfiguration(connectionURL);
+    }
+}