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

[dubbo] branch 3.3-config-api-refactor updated: Split DefaultConfigValidator to SPI implements (#12948)

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

albumenj pushed a commit to branch 3.3-config-api-refactor
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.3-config-api-refactor by this push:
     new 98e7313e71 Split DefaultConfigValidator to SPI implements (#12948)
98e7313e71 is described below

commit 98e7313e71fab2d24103956ee3befc7b13ebdd92
Author: namelessssssssssss <10...@users.noreply.github.com>
AuthorDate: Sun Sep 10 20:56:10 2023 +0800

    Split DefaultConfigValidator to SPI implements (#12948)
    
    * * Simplify responsibilities of ConfigValidationUtils
    
    * * Update validators
    
    * * Bug fix
    
    * * Bug fix
    * Add ut
    
    * * Add license
    
    * * Rename folder
    
    * * Fix pom & name
    
    * * Code style fix
    
    * * Bug fix
    
    * * Bug fix
    
    * * Update validator init process
    
    * * Refactor ConfigValidateFacade init method
    
    * * Bug fix
    * Add license
    
    * * Fix test
    
    * * Fix ut
    
    * * Update ConfigValidateFacade init process
    
    * * Bug fix
    
    * * Bug fix
    
    * * Bug fix
    
    * * Doc fix
    
    * * Bug fix
    
    * * Bug fix
    
    * * Bug fix
    
    * * Bug fix
    
    * * Bug fix
    
    * * Test fix
    
    * * refactor validator mapping
    
    * * Code style fix
    
    * * Fix conflict
    
    * * Fix conflict
    
    * * Remove default instance of ConfigValidateFacade
    
    * * Remove default instance of ConfigValidateFacade
    
    * * Add license
---
 .../dubbo/common/constants/CommonConstants.java    |   2 +
 .../org/apache/dubbo/config/AbstractConfig.java    |   7 +
 .../apache/dubbo/config/ConfigValidateFacade.java  | 115 ++++
 .../config/context/AbstractConfigManager.java      |  13 +-
 .../dubbo/config/context/ConfigValidator.java      |  20 +-
 .../ConfigValidationException.java}                |  22 +-
 .../dubbo/config/utils/ConfigValidationUtils.java  | 355 ++++++++++
 .../validator/ApplicationConfigValidator.java      |  97 +++
 .../config/validator/ModuleConfigValidator.java    |  49 ++
 .../java/org/apache/dubbo/registry/Constants.java  |   0
 .../org/apache/dubbo/rpc/cluster/Constants.java    |   0
 ...org.apache.dubbo.config.context.ConfigValidator |   2 +
 .../dubbo/config/context/ConfigManagerTest.java    |   2 +
 .../dubbo/config/ConfigScopeModelInitializer.java  |   3 -
 .../org/apache/dubbo/config/ReferenceConfig.java   |   6 +-
 .../org/apache/dubbo/config/ServiceConfig.java     |   5 +-
 .../application/ApplicationLifecycle.java          |   3 +
 .../ConfigCenterApplicationLifecycle.java          |   5 +-
 .../application/MetadataInitializeLifecycle.java   |   4 +-
 .../ValidatorRegistryDeployListener.java           |  41 ++
 .../dubbo/config/utils/ConfigValidationUtils.java  | 741 ---------------------
 .../dubbo/config/utils/DefaultConfigValidator.java |  62 --
 .../validator/ConfigCenterConfigValidator.java     |  44 ++
 .../config/validator/ConsumerConfigValidator.java  |  25 +-
 .../config/validator/InterfaceConfigValidator.java |  68 ++
 .../config/validator/MethodConfigValidator.java    |  63 ++
 .../config/validator/ProviderConfigValidator.java  |  58 ++
 .../config/validator/ReferenceConfigValidator.java |  65 ++
 .../config/validator/ServiceConfigValidator.java   |  78 +++
 ...org.apache.dubbo.config.context.ConfigValidator |   8 +
 ...ploy.lifecycle.application.ApplicationLifecycle |   1 +
 .../apache/dubbo/config/AbstractConfigTest.java    |   2 +-
 .../dubbo/config/ConfigValidatorExistTest.java     |  94 +++
 .../dubbo/config/bootstrap/DubboBootstrapTest.java |  18 +-
 .../config/utils/ConfigValidationUtilsTest.java    |  39 +-
 dubbo-distribution/dubbo-all/pom.xml               |   7 +
 .../config/validator/MetadataConfigValidator.java  |  64 ++
 ...org.apache.dubbo.config.context.ConfigValidator |   1 +
 .../config/validator/MetricsConfigValidator.java   |  25 +-
 ...org.apache.dubbo.config.context.ConfigValidator |   1 +
 .../metrics/collector/DefaultCollectorTest.java    |   5 +-
 .../config/validator/TracingConfigValidator.java   |  25 +-
 ...org.apache.dubbo.config.context.ConfigValidator |   1 +
 .../java/org/apache/dubbo/util/MonitorUrlUtil.java | 102 +++
 .../config/validator/MonitorConfigValidator.java   |  53 ++
 ...org.apache.dubbo.config.context.ConfigValidator |   1 +
 .../security/cert/CertDeployerListenerTest.java    |   3 +-
 .../config/validate/RegistryConfigValidator.java   |  56 ++
 .../dubbo/config/validator/SslConfigValidator.java |  23 +-
 ...org.apache.dubbo.config.context.ConfigValidator |   1 +
 .../config/validator/ProtocolConfigValidator.java  |  82 +++
 ...org.apache.dubbo.config.context.ConfigValidator |   1 +
 52 files changed, 1695 insertions(+), 873 deletions(-)

diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
index 3380621774..4224da82fd 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
@@ -337,6 +337,8 @@ public interface CommonConstants {
 
     String REGISTRY_PROTOCOL_LISTENER_KEY = "registry.protocol.listener";
 
+    String REGISTRY_SERVICE_CLASS_NAME = "org.apache.dubbo.registry.RegistryService";
+
     String DUBBO_VERSION_KEY = "dubbo";
 
     String TAG_KEY = "dubbo.tag";
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
index 75a80c8999..3c23216f09 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java
@@ -172,6 +172,13 @@ public abstract class AbstractConfig implements Serializable {
         appendParameters0(parameters, config, prefix, false);
     }
 
+    public boolean validate() {
+        if(scopeModel == null || scopeModel.getBeanFactory() == null || scopeModel.getBeanFactory().isDestroyed()){
+            return ConfigValidateFacade.getDefaultInstance().validate(this);
+        }
+        return scopeModel.getBeanFactory().getOrRegisterBean(ConfigValidateFacade.class,clz -> new ConfigValidateFacade(scopeModel)).validate(this);
+    }
+
     private static void appendParameters0(Map<String, String> parameters, Object config, String prefix, boolean asParameters) {
         if (config == null) {
             return;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ConfigValidateFacade.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ConfigValidateFacade.java
new file mode 100644
index 0000000000..732ec39f30
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ConfigValidateFacade.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config;
+
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.context.ConfigValidator;
+import org.apache.dubbo.config.exception.ConfigValidationException;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.ScopeModel;
+
+import java.util.Collections;
+import java.util.List;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class ConfigValidateFacade implements ConfigValidator{
+
+    private static final Logger LOGGER = LoggerFactory.getErrorTypeAwareLogger(ConfigValidateFacade.class);
+
+    private final List<ConfigValidator> validators;
+
+    /**
+     * For test
+     */
+    private static boolean enableValidate = true;
+
+    public ConfigValidateFacade(ScopeModel scopeModel) {
+        if(scopeModel != null) {
+            ExtensionLoader<ConfigValidator> extensionLoader = scopeModel.getExtensionLoader(ConfigValidator.class);
+            if (extensionLoader != null) {
+                this.validators = extensionLoader.getActivateExtensions();
+                this.validators.forEach(scopeModel.getBeanFactory()::registerBean);
+            } else {
+                this.validators = Collections.emptyList();
+            }
+        }else {
+            this.validators = Collections.emptyList();
+        }
+    }
+
+    public List<ConfigValidator> getValidators() {
+        return validators;
+    }
+
+    /**
+     * Auto choose a appropriate validator to validate config.
+     *
+     * @param config the config to validate
+     * @return TRUE if pass the validation.
+     * FALSE if no ConfigValidator found for this config,
+     * or one of the supported {@link ConfigValidator#validate(AbstractConfig)} returns FALSE.
+     */
+    @Override
+    public boolean validate(AbstractConfig config) throws ConfigValidationException{
+        if(!enableValidate){
+            return true;
+        }
+        if (config == null) {
+            return false;
+        }
+        boolean validated = false;
+        try {
+            for (ConfigValidator validator : validators) {
+                if (validator.isSupport(config.getClass())) {
+                    validated = true;
+                    if(!validator.validate(config)){
+                           return false;
+                    }
+                }
+            }
+        }catch (Throwable t){
+            throw new ConfigValidationException(config.getClass().getSimpleName()+" validation failed: "+t.getMessage(),t);
+        }
+        if (!validated) {
+            LOGGER.info(config.getClass().getSimpleName()+" is not validated. This may caused by you did not imported the relevant module.");
+        }
+        return validated;
+    }
+
+    @Override
+    public boolean isSupport(Class configClass) {
+        return true;
+    }
+
+    /**
+     * For test
+     */
+    @Deprecated
+    public static ConfigValidateFacade getDefaultInstance() {
+        return ApplicationModel.defaultModel().getBeanFactory().getOrRegisterBean(ConfigValidateFacade.class);
+    }
+
+    /**
+     * For test
+     */
+    @Deprecated
+    public static void setEnableValidate(boolean enable){
+        enableValidate = enable;
+    }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
index 0f8a0e23d4..d61009799d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
@@ -31,6 +31,7 @@ import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.config.AbstractConfig;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.ConfigKeys;
+import org.apache.dubbo.config.ConfigValidateFacade;
 import org.apache.dubbo.config.MetadataReportConfig;
 import org.apache.dubbo.config.MetricsConfig;
 import org.apache.dubbo.config.ModuleConfig;
@@ -585,10 +586,8 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
 
         // validate configs
         Collection<T> configs = this.getConfigs(configType);
-        if (getConfigValidator() != null) {
-            for (T config : configs) {
-                getConfigValidator().validate(config);
-            }
+        for (T config : configs) {
+            getConfigValidator().validate(config);
         }
 
         // check required default
@@ -611,11 +610,11 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
         return true;
     }
 
-    private ConfigValidator getConfigValidator() {
+    private ConfigValidateFacade getConfigValidator() {
         if (configValidator == null) {
-            configValidator = applicationModel.getBeanFactory().getBean(ConfigValidator.class);
+            configValidator = applicationModel.getBeanFactory().getOrRegisterBean(ConfigValidateFacade.class, clz -> new ConfigValidateFacade(scopeModel));
         }
-        return configValidator;
+        return (ConfigValidateFacade) configValidator;
     }
 
     /**
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
index 7d20b1b658..22b630f158 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
@@ -16,10 +16,26 @@
  */
 package org.apache.dubbo.config.context;
 
+import org.apache.dubbo.common.extension.SPI;
 import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.config.exception.ConfigValidationException;
 
-public interface ConfigValidator {
+/**
+ * ConfigValidator. Allow provides an optional validation logic for a {@link AbstractConfig} impl.
+ * @param <T> type of {@link AbstractConfig} implement
+ */
+@SPI
+public interface ConfigValidator<T extends AbstractConfig> {
+
+    /**
+     * Validate a config.
+     * If the config does not pass validation, returns false or throws exception, depends on implementation.
+     *
+     * @param config the config to validate
+     * @return TRUE if pass validation
+     */
+    boolean validate(T config) throws ConfigValidationException;
 
-    void validate(AbstractConfig config);
+    boolean isSupport(Class<?> configClass);
 
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java b/dubbo-common/src/main/java/org/apache/dubbo/config/exception/ConfigValidationException.java
similarity index 56%
copy from dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
copy to dubbo-common/src/main/java/org/apache/dubbo/config/exception/ConfigValidationException.java
index 7d20b1b658..5ee95d0c54 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/exception/ConfigValidationException.java
@@ -14,12 +14,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.context;
+package org.apache.dubbo.config.exception;
 
-import org.apache.dubbo.config.AbstractConfig;
+/**
+ * Config validation exception
+ */
+public class ConfigValidationException extends RuntimeException {
+
+    public ConfigValidationException(String message) {
+        super(message);
+    }
 
-public interface ConfigValidator {
+    public ConfigValidationException(String message, Throwable cause) {
+        super(message, cause);
+    }
 
-    void validate(AbstractConfig config);
+    public ConfigValidationException(Throwable cause) {
+        super(cause);
+    }
 
+    public ConfigValidationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java
new file mode 100644
index 0000000000..f4313a0b2a
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java
@@ -0,0 +1,355 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.utils;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.URLBuilder;
+import org.apache.dubbo.common.config.ConfigurationUtils;
+import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.common.utils.UrlUtils;
+import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.config.AbstractInterfaceConfig;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.registry.Constants;
+import org.apache.dubbo.rpc.model.ScopeModel;
+import org.apache.dubbo.rpc.model.ScopeModelUtil;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
+import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SERVICE_CLASS_NAME;
+import static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX;
+import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_PARAMETER_FORMAT_ERROR;
+
+import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_ALL;
+import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INSTANCE;
+import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INTERFACE;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL;
+import static org.apache.dubbo.common.constants.RegistryConstants.DUBBO_REGISTER_MODE_DEFAULT_KEY;
+import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;
+import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
+import static org.apache.dubbo.config.Constants.IGNORE_CHECK_KEYS;
+import static org.apache.dubbo.config.Constants.REGISTER_KEY;
+
+public class ConfigValidationUtils {
+    public static final String IPV6_START_MARK = "[";
+    public static final String IPV6_END_MARK = "]";
+    /**
+     * The maximum length of a <b>parameter's value</b>
+     */
+    private static final int MAX_LENGTH = 200;
+    /**
+     * The maximum length of a <b>path</b>
+     */
+    private static final int MAX_PATH_LENGTH = 200;
+    /**
+     * The rule qualification for <b>name</b>
+     */
+    private static final Pattern PATTERN_NAME = Pattern.compile("[\\-._0-9a-zA-Z]+");
+    /**
+     * The rule qualification for <b>multiply name</b>
+     */
+    private static final Pattern PATTERN_MULTI_NAME = Pattern.compile("[,\\-._0-9a-zA-Z]+");
+    /**
+     * The rule qualification for <b>method names</b>
+     */
+    private static final Pattern PATTERN_METHOD_NAME = Pattern.compile("[a-zA-Z][0-9a-zA-Z]*");
+    /**
+     * The rule qualification for <b>path</b>
+     */
+    private static final Pattern PATTERN_PATH = Pattern.compile("[/\\-$._0-9a-zA-Z]+");
+    /**
+     * The pattern matches a value who has a symbol
+     */
+    private static final Pattern PATTERN_NAME_HAS_SYMBOL = Pattern.compile("[:*,\\s/\\-._0-9a-zA-Z]+");
+    /**
+     * The pattern matches a property key
+     */
+    private static final Pattern PATTERN_KEY = Pattern.compile("[*,\\-._0-9a-zA-Z]+");
+    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ConfigValidationUtils.class);
+
+    public static List<URL> loadRegistries(AbstractInterfaceConfig interfaceConfig, boolean provider) {
+        // check && override if necessary
+        List<URL> registryList = new ArrayList<>();
+        ApplicationConfig application = interfaceConfig.getApplication();
+        List<RegistryConfig> registries = interfaceConfig.getRegistries();
+        if (CollectionUtils.isNotEmpty(registries)) {
+            for (RegistryConfig config : registries) {
+                // try to refresh registry in case it is set directly by user using config.setRegistries()
+                if (!config.isRefreshed()) {
+                    config.refresh();
+                }
+                String address = config.getAddress();
+                if (StringUtils.isEmpty(address)) {
+                    address = ANYHOST_VALUE;
+                }
+                if (!RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
+                    Map<String, String> map = new HashMap<String, String>();
+                    AbstractConfig.appendParameters(map, application);
+                    AbstractConfig.appendParameters(map, config);
+                    map.put(PATH_KEY,REGISTRY_SERVICE_CLASS_NAME);
+                    AbstractInterfaceConfig.appendRuntimeParameters(map);
+                    if (!map.containsKey(PROTOCOL_KEY)) {
+                        map.put(PROTOCOL_KEY, DUBBO_PROTOCOL);
+                    }
+                    List<URL> urls = UrlUtils.parseURLs(address, map);
+
+                    for (URL url : urls) {
+                        url = URLBuilder.from(url)
+                            .addParameter(REGISTRY_KEY, url.getProtocol())
+                            .setProtocol(extractRegistryType(url))
+                            .setScopeModel(interfaceConfig.getScopeModel())
+                            .build();
+                        // provider delay register state will be checked in RegistryProtocol#export
+                        if (provider && url.getParameter(REGISTER_KEY, true)) {
+                            registryList.add(url);
+                        }
+                        if (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true)) {
+                            registryList.add(url);
+                        }
+                    }
+                }
+            }
+        }
+        return genCompatibleRegistries(interfaceConfig.getScopeModel(), registryList, provider);
+    }
+
+    private static List<URL> genCompatibleRegistries(ScopeModel scopeModel, List<URL> registryList, boolean provider) {
+        List<URL> result = new ArrayList<>(registryList.size());
+        registryList.forEach(registryURL -> {
+            if (provider) {
+                // for registries enabled service discovery, automatically register interface compatible addresses.
+                String registerMode;
+                if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) {
+                    registerMode = registryURL.getParameter(REGISTER_MODE_KEY, ConfigurationUtils.getCachedDynamicProperty(scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_INSTANCE));
+                    if (!isValidRegisterMode(registerMode)) {
+                        registerMode = DEFAULT_REGISTER_MODE_INSTANCE;
+                    }
+                    result.add(registryURL);
+                    if (DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)
+                        && registryNotExists(registryURL, registryList, REGISTRY_PROTOCOL)) {
+                        URL interfaceCompatibleRegistryURL = URLBuilder.from(registryURL)
+                            .setProtocol(REGISTRY_PROTOCOL)
+                            .removeParameter(REGISTRY_TYPE_KEY)
+                            .build();
+                        result.add(interfaceCompatibleRegistryURL);
+                    }
+                } else {
+                    registerMode = registryURL.getParameter(REGISTER_MODE_KEY, ConfigurationUtils.getCachedDynamicProperty(scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_ALL));
+                    if (!isValidRegisterMode(registerMode)) {
+                        registerMode = DEFAULT_REGISTER_MODE_INTERFACE;
+                    }
+                    if ((DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode))
+                        && registryNotExists(registryURL, registryList, SERVICE_REGISTRY_PROTOCOL)) {
+                        URL serviceDiscoveryRegistryURL = URLBuilder.from(registryURL)
+                            .setProtocol(SERVICE_REGISTRY_PROTOCOL)
+                            .removeParameter(REGISTRY_TYPE_KEY)
+                            .build();
+                        result.add(serviceDiscoveryRegistryURL);
+                    }
+
+                    if (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)) {
+                        result.add(registryURL);
+                    }
+                }
+
+                FrameworkStatusReportService reportService = ScopeModelUtil.getApplicationModel(scopeModel).getBeanFactory().getBean(FrameworkStatusReportService.class);
+                reportService.reportRegistrationStatus(reportService.createRegistrationReport(registerMode));
+            } else {
+                result.add(registryURL);
+            }
+        });
+
+        return result;
+    }
+
+    private static boolean isValidRegisterMode(String mode) {
+        return isNotEmpty(mode)
+            && (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(mode)
+            || DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(mode)
+            || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(mode)
+        );
+    }
+
+    private static boolean registryNotExists(URL registryURL, List<URL> registryList, String registryType) {
+        return registryList.stream().noneMatch(
+            url -> registryType.equals(url.getProtocol()) && registryURL.getBackupAddress().equals(url.getBackupAddress())
+        );
+    }
+
+    private static String extractRegistryType(URL url) {
+        return UrlUtils.hasServiceDiscoveryRegistryTypeKey(url) ? SERVICE_REGISTRY_PROTOCOL : getRegistryProtocolType(url);
+    }
+
+    private static String getRegistryProtocolType(URL url) {
+        String registryProtocol = url.getParameter("registry-protocol-type");
+        return isNotEmpty(registryProtocol) ? registryProtocol : REGISTRY_PROTOCOL;
+    }
+
+    public static void checkExtension(ScopeModel scopeModel, Class<?> type, String property, String value) {
+        checkName(property, value);
+        if (isNotEmpty(value)
+            && !scopeModel.getExtensionLoader(type).hasExtension(value)) {
+            throw new IllegalStateException("No such extension " + value + " for " + property + "/" + type.getName());
+        }
+    }
+
+    /**
+     * Check whether there is a <code>Extension</code> who's name (property) is <code>value</code> (special treatment is
+     * required)
+     *
+     * @param type     The Extension type
+     * @param property The extension key
+     * @param value    The Extension name
+     */
+    public static void checkMultiExtension(ScopeModel scopeModel, Class<?> type, String property, String value) {
+        checkMultiExtension(scopeModel, Collections.singletonList(type), property, value);
+    }
+
+    public static void checkMultiExtension(ScopeModel scopeModel, List<Class<?>> types, String property, String value) {
+        checkMultiName(property, value);
+        if (isNotEmpty(value)) {
+            String[] values = value.split("\\s*[,]+\\s*");
+            for (String v : values) {
+                v = StringUtils.trim(v);
+                if (v.startsWith(REMOVE_VALUE_PREFIX)) {
+                    continue;
+                }
+                if (DEFAULT_KEY.equals(v)) {
+                    continue;
+                }
+                boolean match = false;
+                for (Class<?> type : types) {
+                    if (scopeModel.getExtensionLoader(type).hasExtension(v)) {
+                        match = true;
+                    }
+                }
+                if (!match) {
+                    throw new IllegalStateException("No such extension " + v + " for " + property + "/" +
+                        types.stream().map(Class::getName).collect(Collectors.joining(",")));
+                }
+            }
+        }
+    }
+
+    public static void checkLength(String property, String value) {
+        checkProperty(property, value, MAX_LENGTH, null);
+    }
+
+    public static void checkPathLength(String property, String value) {
+        checkProperty(property, value, MAX_PATH_LENGTH, null);
+    }
+
+    public static void checkName(String property, String value) {
+        checkProperty(property, value, MAX_LENGTH, PATTERN_NAME);
+    }
+
+    public static void checkHost(String property, String value) {
+        if (StringUtils.isEmpty(value)) {
+            return;
+        }
+        if (value.startsWith(IPV6_START_MARK) && value.endsWith(IPV6_END_MARK)) {
+            // if the value start with "[" and end with "]", check whether it is IPV6
+            try {
+                InetAddress.getByName(value);
+                return;
+            } catch (UnknownHostException e) {
+                // not a IPv6 string, do nothing, go on to checkName
+            }
+        }
+        checkName(property, value);
+    }
+
+    public static void checkNameHasSymbol(String property, String value) {
+        checkProperty(property, value, MAX_LENGTH, PATTERN_NAME_HAS_SYMBOL);
+    }
+
+    public static void checkKey(String property, String value) {
+        checkProperty(property, value, MAX_LENGTH, PATTERN_KEY);
+    }
+
+    public static void checkMultiName(String property, String value) {
+        checkProperty(property, value, MAX_LENGTH, PATTERN_MULTI_NAME);
+    }
+
+    public static void checkPathName(String property, String value) {
+        checkProperty(property, value, MAX_PATH_LENGTH, PATTERN_PATH);
+    }
+
+    public static void checkMethodName(String property, String value) {
+        checkProperty(property, value, MAX_LENGTH, PATTERN_METHOD_NAME);
+    }
+
+    public static void checkParameterName(Map<String, String> parameters) {
+        if (CollectionUtils.isEmptyMap(parameters)) {
+            return;
+        }
+        List<String> ignoreCheckKeys = new ArrayList<>();
+        ignoreCheckKeys.add(BACKUP_KEY);
+        String ignoreCheckKeysStr = parameters.get(IGNORE_CHECK_KEYS);
+        if (!StringUtils.isBlank(ignoreCheckKeysStr)) {
+            ignoreCheckKeys.addAll(Arrays.asList(ignoreCheckKeysStr.split(",")));
+        }
+        for (Map.Entry<String, String> entry : parameters.entrySet()) {
+            if (!ignoreCheckKeys.contains(entry.getKey())) {
+                checkNameHasSymbol(entry.getKey(), entry.getValue());
+            }
+        }
+    }
+
+    public static void checkProperty(String property, String value, int maxlength, Pattern pattern) {
+        if (StringUtils.isEmpty(value)) {
+            return;
+        }
+        if (value.length() > maxlength) {
+            logger.error(CONFIG_PARAMETER_FORMAT_ERROR, "the value content is too long", "", "Parameter value format error. Invalid " +
+                property + "=\"" + value + "\" is longer than " + maxlength);
+        }
+        if (pattern != null) {
+            Matcher matcher = pattern.matcher(value);
+            if (!matcher.matches()) {
+                logger.error(CONFIG_PARAMETER_FORMAT_ERROR, "the value content is illegal character", "", "Parameter value format error. Invalid " +
+                    property + "=\"" + value + "\" contains illegal " +
+                    "character, only digit, letter, '-', '_' or '.' is legal.");
+            }
+        }
+    }
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ApplicationConfigValidator.java b/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ApplicationConfigValidator.java
new file mode 100644
index 0000000000..c9563aab88
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ApplicationConfigValidator.java
@@ -0,0 +1,97 @@
+/*
+ * 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.validator;
+
+import org.apache.dubbo.common.config.PropertiesConfiguration;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.ClassUtils;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+import org.apache.dubbo.config.exception.ConfigValidationException;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+import org.apache.dubbo.rpc.model.ScopeModel;
+import org.apache.dubbo.rpc.model.ScopeModelUtil;
+
+import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY;
+import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CLASS_NOT_FOUND;
+import static org.apache.dubbo.config.Constants.ARCHITECTURE;
+import static org.apache.dubbo.config.Constants.ENVIRONMENT;
+import static org.apache.dubbo.config.Constants.NAME;
+import static org.apache.dubbo.config.Constants.ORGANIZATION;
+import static org.apache.dubbo.config.Constants.OWNER;
+
+@Activate
+public class ApplicationConfigValidator implements ConfigValidator<ApplicationConfig> {
+
+    private static ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ApplicationConfigValidator.class);
+
+    public static void validateApplicationConfig(ApplicationConfig config) {
+        if (config == null) {
+            return;
+        }
+
+        if (!config.isValid()) {
+            throw new ConfigValidationException("No application config found or it's not a valid config! " +
+                "Please add <dubbo:application name=\"...\" /> to your spring config.");
+        }
+
+        // backward compatibility
+        ScopeModel scopeModel = ScopeModelUtil.getOrDefaultApplicationModel(config.getScopeModel());
+        PropertiesConfiguration configuration = scopeModel.modelEnvironment().getPropertiesConfiguration();
+        String wait = configuration.getProperty(SHUTDOWN_WAIT_KEY);
+        if (wait != null && wait.trim().length() > 0) {
+            System.setProperty(SHUTDOWN_WAIT_KEY, wait.trim());
+        } else {
+            wait = configuration.getProperty(SHUTDOWN_WAIT_SECONDS_KEY);
+            if (wait != null && wait.trim().length() > 0) {
+                System.setProperty(SHUTDOWN_WAIT_SECONDS_KEY, wait.trim());
+            }
+        }
+
+        ConfigValidationUtils.checkName(NAME, config.getName());
+        ConfigValidationUtils.checkMultiName(OWNER, config.getOwner());
+        ConfigValidationUtils.checkName(ORGANIZATION, config.getOrganization());
+        ConfigValidationUtils.checkName(ARCHITECTURE, config.getArchitecture());
+        ConfigValidationUtils.checkName(ENVIRONMENT, config.getEnvironment());
+        ConfigValidationUtils.checkParameterName(config.getParameters());
+        checkQosDependency(config);
+    }
+
+    public static void checkQosDependency(ApplicationConfig config) {
+        if (!Boolean.FALSE.equals(config.getQosEnable())) {
+            try {
+                ClassUtils.forName("org.apache.dubbo.qos.protocol.QosProtocolWrapper");
+            } catch (ClassNotFoundException e) {
+                logger.warn(COMMON_CLASS_NOT_FOUND, "", "", "No QosProtocolWrapper class was found. Please check the dependency of dubbo-qos whether was imported correctly.", e);
+            }
+        }
+    }
+
+    @Override
+    public boolean validate(ApplicationConfig config) {
+        validateApplicationConfig(config);
+        return true;
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return ApplicationConfig.class.isAssignableFrom(configClass);
+    }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ModuleConfigValidator.java b/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ModuleConfigValidator.java
new file mode 100644
index 0000000000..85ddd314aa
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/validator/ModuleConfigValidator.java
@@ -0,0 +1,49 @@
+/*
+ * 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.validator;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.ModuleConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+
+import static org.apache.dubbo.config.Constants.NAME;
+import static org.apache.dubbo.config.Constants.ORGANIZATION;
+import static org.apache.dubbo.config.Constants.OWNER;
+
+@Activate
+public class ModuleConfigValidator implements ConfigValidator<ModuleConfig> {
+
+    @Override
+    public boolean validate(ModuleConfig config) {
+        validateModuleConfig(config);
+        return true;
+    }
+
+    public static void validateModuleConfig(ModuleConfig config) {
+        if (config != null) {
+            ConfigValidationUtils.checkName(NAME, config.getName());
+            ConfigValidationUtils.checkName(OWNER, config.getOwner());
+            ConfigValidationUtils.checkName(ORGANIZATION, config.getOrganization());
+        }
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return ModuleConfig.class.isAssignableFrom(configClass);
+    }
+}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Constants.java b/dubbo-common/src/main/java/org/apache/dubbo/registry/Constants.java
similarity index 100%
rename from dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/Constants.java
rename to dubbo-common/src/main/java/org/apache/dubbo/registry/Constants.java
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java
similarity index 100%
rename from dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java
rename to dubbo-common/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java
diff --git a/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
new file mode 100644
index 0000000000..8fe3a6c328
--- /dev/null
+++ b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
@@ -0,0 +1,2 @@
+application=org.apache.dubbo.config.validator.ApplicationConfigValidator
+module=org.apache.dubbo.config.validator.ModuleConfigValidator
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
index 5ddd74aad4..00d1ec7fcc 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.config.context;
 import org.apache.dubbo.common.utils.CollectionUtils;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.ConfigCenterConfig;
+import org.apache.dubbo.config.ConfigValidateFacade;
 import org.apache.dubbo.config.ConsumerConfig;
 import org.apache.dubbo.config.MetricsConfig;
 import org.apache.dubbo.config.ModuleConfig;
@@ -64,6 +65,7 @@ class ConfigManagerTest {
         ApplicationModel applicationModel = ApplicationModel.defaultModel();
         configManager = applicationModel.getApplicationConfigManager();
         moduleConfigManager = applicationModel.getDefaultModule().getConfigManager();
+        ConfigValidateFacade.setEnableValidate(false);
     }
 
     @Test
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java
index 955da26d23..fa82316dca 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigScopeModelInitializer.java
@@ -22,7 +22,6 @@ import org.apache.dubbo.common.deploy.ModuleDeployer;
 import org.apache.dubbo.config.deploy.DefaultApplicationDeployer;
 import org.apache.dubbo.config.deploy.DefaultModuleDeployer;
 import org.apache.dubbo.config.deploy.FrameworkModelCleaner;
-import org.apache.dubbo.config.utils.DefaultConfigValidator;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 import org.apache.dubbo.rpc.model.ModuleModel;
@@ -38,11 +37,9 @@ public class ConfigScopeModelInitializer implements ScopeModelInitializer {
     @Override
     public void initializeApplicationModel(ApplicationModel applicationModel) {
         ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
-        beanFactory.registerBean(DefaultConfigValidator.class);
         // applicationDeployer
         ApplicationDeployer applicationDeployer = beanFactory.registerBean(DefaultApplicationDeployer.class);
         applicationModel.setDeployer(applicationDeployer);
-
     }
 
     @Override
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index c11f9c3f62..924b1a9cb8 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
@@ -53,6 +53,7 @@ import org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol;
 import org.apache.dubbo.rpc.service.GenericService;
 import org.apache.dubbo.rpc.stub.StubSuppliers;
 import org.apache.dubbo.rpc.support.ProtocolUtils;
+import org.apache.dubbo.util.MonitorUrlUtil;
 
 import java.beans.Transient;
 import java.util.ArrayList;
@@ -179,7 +180,6 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
     @Override
     protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {
         super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);
-
         protocolSPI = this.getExtensionLoader(Protocol.class).getAdaptiveExtension();
         proxyFactory = this.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
     }
@@ -579,7 +579,7 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
         List<URL> us = ConfigValidationUtils.loadRegistries(this, false);
         if (CollectionUtils.isNotEmpty(us)) {
             for (URL u : us) {
-                URL monitorUrl = ConfigValidationUtils.loadMonitor(this, u);
+                URL monitorUrl = MonitorUrlUtil.loadMonitor(this, u);
                 if (monitorUrl != null) {
                     u = u.putAttribute(MONITOR_KEY, monitorUrl);
                 }
@@ -746,7 +746,7 @@ public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
         }
 
         resolveFile();
-        ConfigValidationUtils.validateReferenceConfig(this);
+        validate();
         postProcessConfig();
     }
 
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 d9d6862255..91dde23fda 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
@@ -54,6 +54,7 @@ import org.apache.dubbo.rpc.model.ProviderModel;
 import org.apache.dubbo.rpc.model.ScopeModel;
 import org.apache.dubbo.rpc.model.ServiceDescriptor;
 import org.apache.dubbo.rpc.service.GenericService;
+import org.apache.dubbo.util.MonitorUrlUtil;
 
 import java.beans.Transient;
 import java.lang.reflect.Method;
@@ -468,7 +469,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
             }
         }
         checkStubAndLocal(interfaceClass);
-        ConfigValidationUtils.validateServiceConfig(this);
+        validate();
         postProcessConfig();
     }
 
@@ -805,7 +806,7 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
                 }
 
                 url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
-                URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL);
+                URL monitorUrl = MonitorUrlUtil.loadMonitor(this, registryURL);
                 if (monitorUrl != null) {
                     url = url.putAttribute(MONITOR_KEY, monitorUrl);
                 }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ApplicationLifecycle.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ApplicationLifecycle.java
index 505c228cf4..08aaeb2060 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ApplicationLifecycle.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ApplicationLifecycle.java
@@ -16,6 +16,7 @@
  */
 package org.apache.dubbo.config.deploy.lifecycle.application;
 
+import org.apache.dubbo.common.deploy.ApplicationDeployListener;
 import org.apache.dubbo.common.deploy.DeployState;
 import org.apache.dubbo.common.extension.SPI;
 import org.apache.dubbo.config.deploy.context.ApplicationContext;
@@ -27,6 +28,8 @@ import org.apache.dubbo.rpc.model.ModuleModel;
  * <br>
  * Used in an application Lifecycle managing procedure, and dubbo packages
  * can implement this interface to define what to do when application status changes.
+ * <p>
+ * Note: If you want to auto registry some extensions to BeanFactory, use {@link ApplicationDeployListener} instead.
  * <br>
  */
 @SPI
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ConfigCenterApplicationLifecycle.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ConfigCenterApplicationLifecycle.java
index 82515fe48e..90e4926385 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ConfigCenterApplicationLifecycle.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ConfigCenterApplicationLifecycle.java
@@ -34,7 +34,6 @@ import org.apache.dubbo.config.ConfigCenterConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.context.ConfigManager;
 import org.apache.dubbo.config.deploy.context.ApplicationContext;
-import org.apache.dubbo.config.utils.ConfigValidationUtils;
 import org.apache.dubbo.metrics.config.event.ConfigCenterEvent;
 import org.apache.dubbo.metrics.event.MetricsEventBus;
 import org.apache.dubbo.rpc.model.ApplicationModel;
@@ -85,7 +84,7 @@ public class ConfigCenterApplicationLifecycle implements ApplicationLifecycle {
             ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
             configCenterConfig.setScopeModel(applicationModel);
             configCenterConfig.refresh();
-            ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
+            configCenterConfig.validate();
             if (configCenterConfig.isValid()) {
                 configManager.addConfigCenter(configCenterConfig);
                 configCenters = configManager.getConfigCenters();
@@ -93,7 +92,7 @@ public class ConfigCenterApplicationLifecycle implements ApplicationLifecycle {
         } else {
             for (ConfigCenterConfig configCenterConfig : configCenters) {
                 configCenterConfig.refresh();
-                ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig);
+                configCenterConfig.validate();
             }
         }
 
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/MetadataInitializeLifecycle.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/MetadataInitializeLifecycle.java
index fb35d4a141..a9e9bfdf4f 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/MetadataInitializeLifecycle.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/MetadataInitializeLifecycle.java
@@ -28,7 +28,6 @@ import org.apache.dubbo.config.MetadataReportConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.context.ConfigManager;
 import org.apache.dubbo.config.deploy.context.ApplicationContext;
-import org.apache.dubbo.config.utils.ConfigValidationUtils;
 import org.apache.dubbo.metadata.report.MetadataReportFactory;
 import org.apache.dubbo.metadata.report.MetadataReportInstance;
 import org.apache.dubbo.rpc.model.ApplicationModel;
@@ -91,8 +90,7 @@ public class MetadataInitializeLifecycle implements ApplicationLifecycle {
         List<MetadataReportConfig> validMetadataReportConfigs = new ArrayList<>(metadataReportConfigs.size());
 
         for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) {
-            if (ConfigValidationUtils.isValidMetadataConfig(metadataReportConfig)) {
-                ConfigValidationUtils.validateMetadataConfig(metadataReportConfig);
+            if (metadataReportConfig.validate()) {
                 validMetadataReportConfigs.add(metadataReportConfig);
             }
         }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ValidatorRegistryDeployListener.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ValidatorRegistryDeployListener.java
new file mode 100644
index 0000000000..3f5d75ffcf
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/lifecycle/application/ValidatorRegistryDeployListener.java
@@ -0,0 +1,41 @@
+/*
+ * 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.deploy.lifecycle.application;
+
+import org.apache.dubbo.common.deploy.ApplicationDeployListener;
+import org.apache.dubbo.config.ConfigValidateFacade;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+public class ValidatorRegistryDeployListener implements ApplicationDeployListener {
+
+    @Override
+    public void onStarting(ApplicationModel scopeModel) {
+        ConfigValidateFacade validateFacade = new ConfigValidateFacade(scopeModel);
+        scopeModel.getBeanFactory().registerBean(validateFacade);
+    }
+
+    @Override
+    public void onInitialize(ApplicationModel scopeModel) {}
+    @Override
+    public void onStarted(ApplicationModel scopeModel) {}
+    @Override
+    public void onStopping(ApplicationModel scopeModel) {}
+    @Override
+    public void onStopped(ApplicationModel scopeModel) {}
+    @Override
+    public void onFailure(ApplicationModel scopeModel, Throwable cause) {}
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java
deleted file mode 100644
index 1f92b894ad..0000000000
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java
+++ /dev/null
@@ -1,741 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.config.utils;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.URLBuilder;
-import org.apache.dubbo.common.config.ConfigurationUtils;
-import org.apache.dubbo.common.config.PropertiesConfiguration;
-import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.serialize.Serialization;
-import org.apache.dubbo.common.status.StatusChecker;
-import org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;
-import org.apache.dubbo.common.threadpool.ThreadPool;
-import org.apache.dubbo.common.utils.ClassUtils;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.common.utils.ConfigUtils;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.common.utils.UrlUtils;
-import org.apache.dubbo.config.AbstractConfig;
-import org.apache.dubbo.config.AbstractInterfaceConfig;
-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.MetricsConfig;
-import org.apache.dubbo.config.ModuleConfig;
-import org.apache.dubbo.config.MonitorConfig;
-import org.apache.dubbo.config.ProtocolConfig;
-import org.apache.dubbo.config.ProviderConfig;
-import org.apache.dubbo.config.ReferenceConfig;
-import org.apache.dubbo.config.RegistryConfig;
-import org.apache.dubbo.config.ServiceConfig;
-import org.apache.dubbo.config.SslConfig;
-import org.apache.dubbo.config.TracingConfig;
-import org.apache.dubbo.monitor.MonitorFactory;
-import org.apache.dubbo.monitor.MonitorService;
-import org.apache.dubbo.registry.RegistryService;
-import org.apache.dubbo.remoting.Codec2;
-import org.apache.dubbo.remoting.Dispatcher;
-import org.apache.dubbo.remoting.Transporter;
-import org.apache.dubbo.remoting.exchange.Exchanger;
-import org.apache.dubbo.remoting.telnet.TelnetHandler;
-import org.apache.dubbo.rpc.ExporterListener;
-import org.apache.dubbo.rpc.Filter;
-import org.apache.dubbo.rpc.InvokerListener;
-import org.apache.dubbo.rpc.ProxyFactory;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.LoadBalance;
-import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
-import org.apache.dubbo.rpc.model.ScopeModel;
-import org.apache.dubbo.rpc.model.ScopeModelUtil;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_MONITOR_ADDRESS;
-import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
-import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.FILTER_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX;
-import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
-import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CLASS_NOT_FOUND;
-import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_PARAMETER_FORMAT_ERROR;
-import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_ALL;
-import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INSTANCE;
-import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INTERFACE;
-import static org.apache.dubbo.common.constants.RegistryConstants.DUBBO_REGISTER_MODE_DEFAULT_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL;
-import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY;
-import static org.apache.dubbo.common.utils.StringUtils.isEmpty;
-import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
-import static org.apache.dubbo.config.Constants.ARCHITECTURE;
-import static org.apache.dubbo.config.Constants.CONTEXTPATH_KEY;
-import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
-import static org.apache.dubbo.config.Constants.ENVIRONMENT;
-import static org.apache.dubbo.config.Constants.IGNORE_CHECK_KEYS;
-import static org.apache.dubbo.config.Constants.LAYER_KEY;
-import static org.apache.dubbo.config.Constants.NAME;
-import static org.apache.dubbo.config.Constants.ORGANIZATION;
-import static org.apache.dubbo.config.Constants.OWNER;
-import static org.apache.dubbo.config.Constants.REGISTER_KEY;
-import static org.apache.dubbo.config.Constants.STATUS_KEY;
-import static org.apache.dubbo.monitor.Constants.LOGSTAT_PROTOCOL;
-import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
-import static org.apache.dubbo.registry.Constants.SUBSCRIBE_KEY;
-import static org.apache.dubbo.remoting.Constants.CLIENT_KEY;
-import static org.apache.dubbo.remoting.Constants.CODEC_KEY;
-import static org.apache.dubbo.remoting.Constants.DISPATCHER_KEY;
-import static org.apache.dubbo.remoting.Constants.EXCHANGER_KEY;
-import static org.apache.dubbo.remoting.Constants.SERIALIZATION_KEY;
-import static org.apache.dubbo.remoting.Constants.SERVER_KEY;
-import static org.apache.dubbo.remoting.Constants.TELNET_KEY;
-import static org.apache.dubbo.remoting.Constants.TRANSPORTER_KEY;
-import static org.apache.dubbo.rpc.Constants.FAIL_PREFIX;
-import static org.apache.dubbo.rpc.Constants.FORCE_PREFIX;
-import static org.apache.dubbo.rpc.Constants.LOCAL_KEY;
-import static org.apache.dubbo.rpc.Constants.MOCK_KEY;
-import static org.apache.dubbo.rpc.Constants.PROXY_KEY;
-import static org.apache.dubbo.rpc.Constants.RETURN_PREFIX;
-import static org.apache.dubbo.rpc.Constants.THROW_PREFIX;
-import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
-
-public class ConfigValidationUtils {
-    private static ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ConfigValidationUtils.class);
-    /**
-     * The maximum length of a <b>parameter's value</b>
-     */
-    private static final int MAX_LENGTH = 200;
-
-    /**
-     * The maximum length of a <b>path</b>
-     */
-    private static final int MAX_PATH_LENGTH = 200;
-
-    /**
-     * The rule qualification for <b>name</b>
-     */
-    private static final Pattern PATTERN_NAME = Pattern.compile("[\\-._0-9a-zA-Z]+");
-
-    /**
-     * The rule qualification for <b>multiply name</b>
-     */
-    private static final Pattern PATTERN_MULTI_NAME = Pattern.compile("[,\\-._0-9a-zA-Z]+");
-
-    /**
-     * The rule qualification for <b>method names</b>
-     */
-    private static final Pattern PATTERN_METHOD_NAME = Pattern.compile("[a-zA-Z][0-9a-zA-Z]*");
-
-    /**
-     * The rule qualification for <b>path</b>
-     */
-    private static final Pattern PATTERN_PATH = Pattern.compile("[/\\-$._0-9a-zA-Z]+");
-
-    /**
-     * The pattern matches a value who has a symbol
-     */
-    private static final Pattern PATTERN_NAME_HAS_SYMBOL = Pattern.compile("[:*,\\s/\\-._0-9a-zA-Z]+");
-
-    /**
-     * The pattern matches a property key
-     */
-    private static final Pattern PATTERN_KEY = Pattern.compile("[*,\\-._0-9a-zA-Z]+");
-
-    public static final String IPV6_START_MARK = "[";
-
-    public static final String IPV6_END_MARK = "]";
-
-    public static List<URL> loadRegistries(AbstractInterfaceConfig interfaceConfig, boolean provider) {
-        // check && override if necessary
-        List<URL> registryList = new ArrayList<>();
-        ApplicationConfig application = interfaceConfig.getApplication();
-        List<RegistryConfig> registries = interfaceConfig.getRegistries();
-        if (CollectionUtils.isNotEmpty(registries)) {
-            for (RegistryConfig config : registries) {
-                // try to refresh registry in case it is set directly by user using config.setRegistries()
-                if (!config.isRefreshed()) {
-                    config.refresh();
-                }
-                String address = config.getAddress();
-                if (StringUtils.isEmpty(address)) {
-                    address = ANYHOST_VALUE;
-                }
-                if (!RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
-                    Map<String, String> map = new HashMap<String, String>();
-                    AbstractConfig.appendParameters(map, application);
-                    AbstractConfig.appendParameters(map, config);
-                    map.put(PATH_KEY, RegistryService.class.getName());
-                    AbstractInterfaceConfig.appendRuntimeParameters(map);
-                    if (!map.containsKey(PROTOCOL_KEY)) {
-                        map.put(PROTOCOL_KEY, DUBBO_PROTOCOL);
-                    }
-                    List<URL> urls = UrlUtils.parseURLs(address, map);
-
-                    for (URL url : urls) {
-                        url = URLBuilder.from(url)
-                            .addParameter(REGISTRY_KEY, url.getProtocol())
-                            .setProtocol(extractRegistryType(url))
-                            .setScopeModel(interfaceConfig.getScopeModel())
-                            .build();
-                        // provider delay register state will be checked in RegistryProtocol#export
-                        if (provider && url.getParameter(REGISTER_KEY, true)) {
-                            registryList.add(url);
-                        }
-                        if (!provider && url.getParameter(SUBSCRIBE_KEY, true)) {
-                            registryList.add(url);
-                        }
-                    }
-                }
-            }
-        }
-        return genCompatibleRegistries(interfaceConfig.getScopeModel(), registryList, provider);
-    }
-
-    private static List<URL> genCompatibleRegistries(ScopeModel scopeModel, List<URL> registryList, boolean provider) {
-        List<URL> result = new ArrayList<>(registryList.size());
-        registryList.forEach(registryURL -> {
-            if (provider) {
-                // for registries enabled service discovery, automatically register interface compatible addresses.
-                String registerMode;
-                if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) {
-                    registerMode = registryURL.getParameter(REGISTER_MODE_KEY, ConfigurationUtils.getCachedDynamicProperty(scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_INSTANCE));
-                    if (!isValidRegisterMode(registerMode)) {
-                        registerMode = DEFAULT_REGISTER_MODE_INSTANCE;
-                    }
-                    result.add(registryURL);
-                    if (DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)
-                        && registryNotExists(registryURL, registryList, REGISTRY_PROTOCOL)) {
-                        URL interfaceCompatibleRegistryURL = URLBuilder.from(registryURL)
-                            .setProtocol(REGISTRY_PROTOCOL)
-                            .removeParameter(REGISTRY_TYPE_KEY)
-                            .build();
-                        result.add(interfaceCompatibleRegistryURL);
-                    }
-                } else {
-                    registerMode = registryURL.getParameter(REGISTER_MODE_KEY, ConfigurationUtils.getCachedDynamicProperty(scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_ALL));
-                    if (!isValidRegisterMode(registerMode)) {
-                        registerMode = DEFAULT_REGISTER_MODE_INTERFACE;
-                    }
-                    if ((DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode))
-                        && registryNotExists(registryURL, registryList, SERVICE_REGISTRY_PROTOCOL)) {
-                        URL serviceDiscoveryRegistryURL = URLBuilder.from(registryURL)
-                            .setProtocol(SERVICE_REGISTRY_PROTOCOL)
-                            .removeParameter(REGISTRY_TYPE_KEY)
-                            .build();
-                        result.add(serviceDiscoveryRegistryURL);
-                    }
-
-                    if (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)) {
-                        result.add(registryURL);
-                    }
-                }
-
-                FrameworkStatusReportService reportService = ScopeModelUtil.getApplicationModel(scopeModel).getBeanFactory().getBean(FrameworkStatusReportService.class);
-                reportService.reportRegistrationStatus(reportService.createRegistrationReport(registerMode));
-            } else {
-                result.add(registryURL);
-            }
-        });
-
-        return result;
-    }
-
-    private static boolean isValidRegisterMode(String mode) {
-        return isNotEmpty(mode)
-            && (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(mode)
-            || DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(mode)
-            || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(mode)
-        );
-    }
-
-    private static boolean registryNotExists(URL registryURL, List<URL> registryList, String registryType) {
-        return registryList.stream().noneMatch(
-            url -> registryType.equals(url.getProtocol()) && registryURL.getBackupAddress().equals(url.getBackupAddress())
-        );
-    }
-
-    public static URL loadMonitor(AbstractInterfaceConfig interfaceConfig, URL registryURL) {
-        Map<String, String> map = new HashMap<String, String>();
-        map.put(INTERFACE_KEY, MonitorService.class.getName());
-        AbstractInterfaceConfig.appendRuntimeParameters(map);
-        //set ip
-        String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);
-        if (StringUtils.isEmpty(hostToRegistry)) {
-            hostToRegistry = NetUtils.getLocalHost();
-        } else if (NetUtils.isInvalidLocalHost(hostToRegistry)) {
-            throw new IllegalArgumentException("Specified invalid registry ip from property:" +
-                DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
-        }
-        map.put(REGISTER_IP_KEY, hostToRegistry);
-
-        MonitorConfig monitor = interfaceConfig.getMonitor();
-        ApplicationConfig application = interfaceConfig.getApplication();
-        AbstractConfig.appendParameters(map, monitor);
-        AbstractConfig.appendParameters(map, application);
-        String address = null;
-        String sysAddress = System.getProperty(DUBBO_MONITOR_ADDRESS);
-        if (sysAddress != null && sysAddress.length() > 0) {
-            address = sysAddress;
-        } else if (monitor != null) {
-            address = monitor.getAddress();
-        }
-        String protocol = monitor == null ? null : monitor.getProtocol();
-        if (monitor != null &&
-            (REGISTRY_PROTOCOL.equals(protocol) || SERVICE_REGISTRY_PROTOCOL.equals(protocol))
-            && registryURL != null) {
-            return URLBuilder.from(registryURL)
-                .setProtocol(DUBBO_PROTOCOL)
-                .addParameter(PROTOCOL_KEY, protocol)
-                .putAttribute(REFER_KEY, map)
-                .build();
-        } else if (ConfigUtils.isNotEmpty(address) || ConfigUtils.isNotEmpty(protocol)) {
-            if (!map.containsKey(PROTOCOL_KEY)) {
-                if (interfaceConfig.getScopeModel().getExtensionLoader(MonitorFactory.class).hasExtension(LOGSTAT_PROTOCOL)) {
-                    map.put(PROTOCOL_KEY, LOGSTAT_PROTOCOL);
-                } else if (ConfigUtils.isNotEmpty(protocol)) {
-                    map.put(PROTOCOL_KEY, protocol);
-                } else {
-                    map.put(PROTOCOL_KEY, DUBBO_PROTOCOL);
-                }
-            }
-            if (ConfigUtils.isEmpty(address)) {
-                address = LOCALHOST_VALUE;
-            }
-            return UrlUtils.parseURL(address, map);
-        }
-        return null;
-    }
-
-
-    public static void validateAbstractInterfaceConfig(AbstractInterfaceConfig config) {
-        checkName(LOCAL_KEY, config.getLocal());
-        checkName("stub", config.getStub());
-        checkMultiName("owner", config.getOwner());
-
-        checkExtension(config.getScopeModel(), ProxyFactory.class, PROXY_KEY, config.getProxy());
-        checkExtension(config.getScopeModel(), Cluster.class, CLUSTER_KEY, config.getCluster());
-        checkMultiExtension(config.getScopeModel(), Arrays.asList(Filter.class, ClusterFilter.class), FILTER_KEY, config.getFilter());
-        checkNameHasSymbol(LAYER_KEY, config.getLayer());
-
-        List<MethodConfig> methods = config.getMethods();
-        if (CollectionUtils.isNotEmpty(methods)) {
-            methods.forEach(ConfigValidationUtils::validateMethodConfig);
-        }
-    }
-
-    public static void validateServiceConfig(ServiceConfig config) {
-        checkKey(VERSION_KEY, config.getVersion());
-        checkKey(GROUP_KEY, config.getGroup());
-        checkName(TOKEN_KEY, config.getToken());
-        checkPathName(PATH_KEY, config.getPath());
-
-        checkMultiExtension(config.getScopeModel(), ExporterListener.class, "listener", config.getListener());
-
-        validateAbstractInterfaceConfig(config);
-
-        List<RegistryConfig> registries = config.getRegistries();
-        if (registries != null) {
-            for (RegistryConfig registry : registries) {
-                validateRegistryConfig(registry);
-            }
-        }
-
-        List<ProtocolConfig> protocols = config.getProtocols();
-        if (protocols != null) {
-            for (ProtocolConfig protocol : protocols) {
-                validateProtocolConfig(protocol);
-            }
-        }
-
-        ProviderConfig providerConfig = config.getProvider();
-        if (providerConfig != null) {
-            validateProviderConfig(providerConfig);
-        }
-    }
-
-    public static void validateReferenceConfig(ReferenceConfig config) {
-        checkMultiExtension(config.getScopeModel(), InvokerListener.class, "listener", config.getListener());
-        checkKey(VERSION_KEY, config.getVersion());
-        checkKey(GROUP_KEY, config.getGroup());
-        checkName(CLIENT_KEY, config.getClient());
-
-        validateAbstractInterfaceConfig(config);
-
-        List<RegistryConfig> registries = config.getRegistries();
-        if (registries != null) {
-            for (RegistryConfig registry : registries) {
-                validateRegistryConfig(registry);
-            }
-        }
-
-        ConsumerConfig consumerConfig = config.getConsumer();
-        if (consumerConfig != null) {
-            validateConsumerConfig(consumerConfig);
-        }
-    }
-
-    public static void validateConfigCenterConfig(ConfigCenterConfig config) {
-        if (config != null) {
-            checkParameterName(config.getParameters());
-        }
-    }
-
-    public static void validateApplicationConfig(ApplicationConfig config) {
-        if (config == null) {
-            return;
-        }
-
-        if (!config.isValid()) {
-            throw new IllegalStateException("No application config found or it's not a valid config! " +
-                "Please add <dubbo:application name=\"...\" /> to your spring config.");
-        }
-
-        // backward compatibility
-        ScopeModel scopeModel = ScopeModelUtil.getOrDefaultApplicationModel(config.getScopeModel());
-        PropertiesConfiguration configuration = scopeModel.modelEnvironment().getPropertiesConfiguration();
-        String wait = configuration.getProperty(SHUTDOWN_WAIT_KEY);
-        if (wait != null && wait.trim().length() > 0) {
-            System.setProperty(SHUTDOWN_WAIT_KEY, wait.trim());
-        } else {
-            wait = configuration.getProperty(SHUTDOWN_WAIT_SECONDS_KEY);
-            if (wait != null && wait.trim().length() > 0) {
-                System.setProperty(SHUTDOWN_WAIT_SECONDS_KEY, wait.trim());
-            }
-        }
-
-        checkName(NAME, config.getName());
-        checkMultiName(OWNER, config.getOwner());
-        checkName(ORGANIZATION, config.getOrganization());
-        checkName(ARCHITECTURE, config.getArchitecture());
-        checkName(ENVIRONMENT, config.getEnvironment());
-        checkParameterName(config.getParameters());
-        checkQosDependency(config);
-    }
-
-    private static void checkQosDependency(ApplicationConfig config) {
-        if (!Boolean.FALSE.equals(config.getQosEnable())) {
-            try {
-                ClassUtils.forName("org.apache.dubbo.qos.protocol.QosProtocolWrapper");
-            } catch (ClassNotFoundException e) {
-                logger.warn(COMMON_CLASS_NOT_FOUND, "", "", "No QosProtocolWrapper class was found. Please check the dependency of dubbo-qos whether was imported correctly.", e);
-            }
-        }
-    }
-
-    public static void validateModuleConfig(ModuleConfig config) {
-        if (config != null) {
-            checkName(NAME, config.getName());
-            checkName(OWNER, config.getOwner());
-            checkName(ORGANIZATION, config.getOrganization());
-        }
-    }
-
-    public static boolean isValidMetadataConfig(MetadataReportConfig metadataReportConfig) {
-        if (metadataReportConfig == null) {
-            return false;
-        }
-
-        if (Boolean.FALSE.equals(metadataReportConfig.getReportMetadata()) &&
-            Boolean.FALSE.equals(metadataReportConfig.getReportDefinition())) {
-            return false;
-        }
-
-        return !isEmpty(metadataReportConfig.getAddress());
-    }
-
-    public static void validateMetadataConfig(MetadataReportConfig metadataReportConfig) {
-        if (!isValidMetadataConfig(metadataReportConfig)) {
-            return;
-        }
-
-        String address = metadataReportConfig.getAddress();
-        String protocol = metadataReportConfig.getProtocol();
-
-        if ((isEmpty(address) || !address.contains("://")) && isEmpty(protocol)) {
-            throw new IllegalArgumentException("Please specify valid protocol or address for metadata report " + address);
-        }
-    }
-
-    public static void validateMetricsConfig(MetricsConfig metricsConfig) {
-        if (metricsConfig == null) {
-            return;
-        }
-    }
-
-    public static void validateTracingConfig(TracingConfig tracingConfig) {
-        if (tracingConfig == null) {
-            return;
-        }
-    }
-
-    public static void validateSslConfig(SslConfig sslConfig) {
-        if (sslConfig == null) {
-            return;
-        }
-    }
-
-    public static void validateMonitorConfig(MonitorConfig config) {
-        if (config != null) {
-            if (!config.isValid()) {
-                logger.info("There's no valid monitor config found, if you want to open monitor statistics for Dubbo, " +
-                    "please make sure your monitor is configured properly.");
-            }
-
-            checkParameterName(config.getParameters());
-        }
-    }
-
-    public static void validateProtocolConfig(ProtocolConfig config) {
-        if (config != null) {
-            String name = config.getName();
-            checkName("name", name);
-            checkHost(HOST_KEY, config.getHost());
-            checkPathName("contextpath", config.getContextpath());
-
-
-            if (DUBBO_PROTOCOL.equals(name)) {
-                checkMultiExtension(config.getScopeModel(), Codec2.class, CODEC_KEY, config.getCodec());
-                checkMultiExtension(config.getScopeModel(), Serialization.class, SERIALIZATION_KEY, config.getSerialization());
-                checkMultiExtension(config.getScopeModel(), Transporter.class, SERVER_KEY, config.getServer());
-                checkMultiExtension(config.getScopeModel(), Transporter.class, CLIENT_KEY, config.getClient());
-            }
-
-            checkMultiExtension(config.getScopeModel(), TelnetHandler.class, TELNET_KEY, config.getTelnet());
-            checkMultiExtension(config.getScopeModel(), StatusChecker.class, "status", config.getStatus());
-            checkExtension(config.getScopeModel(), Transporter.class, TRANSPORTER_KEY, config.getTransporter());
-            checkExtension(config.getScopeModel(), Exchanger.class, EXCHANGER_KEY, config.getExchanger());
-            checkExtension(config.getScopeModel(), Dispatcher.class, DISPATCHER_KEY, config.getDispatcher());
-            checkExtension(config.getScopeModel(), Dispatcher.class, "dispather", config.getDispather());
-            checkExtension(config.getScopeModel(), ThreadPool.class, THREADPOOL_KEY, config.getThreadpool());
-        }
-    }
-
-    public static void validateProviderConfig(ProviderConfig config) {
-        checkPathName(CONTEXTPATH_KEY, config.getContextpath());
-        checkExtension(config.getScopeModel(), ThreadPool.class, THREADPOOL_KEY, config.getThreadpool());
-        checkMultiExtension(config.getScopeModel(), TelnetHandler.class, TELNET_KEY, config.getTelnet());
-        checkMultiExtension(config.getScopeModel(), StatusChecker.class, STATUS_KEY, config.getStatus());
-        checkExtension(config.getScopeModel(), Transporter.class, TRANSPORTER_KEY, config.getTransporter());
-        checkExtension(config.getScopeModel(), Exchanger.class, EXCHANGER_KEY, config.getExchanger());
-    }
-
-    public static void validateConsumerConfig(ConsumerConfig config) {
-        if (config == null) {
-            return;
-        }
-    }
-
-    public static void validateRegistryConfig(RegistryConfig config) {
-        checkName(PROTOCOL_KEY, config.getProtocol());
-        checkName(USERNAME_KEY, config.getUsername());
-        checkLength(PASSWORD_KEY, config.getPassword());
-        checkPathLength(FILE_KEY, config.getFile());
-        checkName(TRANSPORTER_KEY, config.getTransporter());
-        checkName(SERVER_KEY, config.getServer());
-        checkName(CLIENT_KEY, config.getClient());
-        checkParameterName(config.getParameters());
-    }
-
-    public static void validateMethodConfig(MethodConfig config) {
-        checkExtension(config.getScopeModel(), LoadBalance.class, LOADBALANCE_KEY, config.getLoadbalance());
-        checkParameterName(config.getParameters());
-        checkMethodName("name", config.getName());
-
-        String mock = config.getMock();
-        if (isNotEmpty(mock)) {
-            if (mock.startsWith(RETURN_PREFIX) || mock.startsWith(THROW_PREFIX + " ")) {
-                checkLength(MOCK_KEY, mock);
-            } else if (mock.startsWith(FAIL_PREFIX) || mock.startsWith(FORCE_PREFIX)) {
-                checkNameHasSymbol(MOCK_KEY, mock);
-            } else {
-                checkName(MOCK_KEY, mock);
-            }
-        }
-    }
-
-    private static String extractRegistryType(URL url) {
-        return UrlUtils.hasServiceDiscoveryRegistryTypeKey(url) ? SERVICE_REGISTRY_PROTOCOL : getRegistryProtocolType(url);
-    }
-
-    private static String getRegistryProtocolType(URL url) {
-        String registryProtocol = url.getParameter("registry-protocol-type");
-        return isNotEmpty(registryProtocol) ? registryProtocol : REGISTRY_PROTOCOL;
-    }
-
-    public static void checkExtension(ScopeModel scopeModel, Class<?> type, String property, String value) {
-        checkName(property, value);
-        if (isNotEmpty(value)
-            && !scopeModel.getExtensionLoader(type).hasExtension(value)) {
-            throw new IllegalStateException("No such extension " + value + " for " + property + "/" + type.getName());
-        }
-    }
-
-    /**
-     * Check whether there is a <code>Extension</code> who's name (property) is <code>value</code> (special treatment is
-     * required)
-     *
-     * @param type     The Extension type
-     * @param property The extension key
-     * @param value    The Extension name
-     */
-    public static void checkMultiExtension(ScopeModel scopeModel, Class<?> type, String property, String value) {
-        checkMultiExtension(scopeModel, Collections.singletonList(type), property, value);
-    }
-
-    public static void checkMultiExtension(ScopeModel scopeModel, List<Class<?>> types, String property, String value) {
-        checkMultiName(property, value);
-        if (isNotEmpty(value)) {
-            String[] values = value.split("\\s*[,]+\\s*");
-            for (String v : values) {
-                v = StringUtils.trim(v);
-                if (v.startsWith(REMOVE_VALUE_PREFIX)) {
-                    continue;
-                }
-                if (DEFAULT_KEY.equals(v)) {
-                    continue;
-                }
-                boolean match = false;
-                for (Class<?> type : types) {
-                    if (scopeModel.getExtensionLoader(type).hasExtension(v)) {
-                        match = true;
-                    }
-                }
-                if (!match) {
-                    throw new IllegalStateException("No such extension " + v + " for " + property + "/" +
-                        types.stream().map(Class::getName).collect(Collectors.joining(",")));
-                }
-            }
-        }
-    }
-
-    public static void checkLength(String property, String value) {
-        checkProperty(property, value, MAX_LENGTH, null);
-    }
-
-    public static void checkPathLength(String property, String value) {
-        checkProperty(property, value, MAX_PATH_LENGTH, null);
-    }
-
-    public static void checkName(String property, String value) {
-        checkProperty(property, value, MAX_LENGTH, PATTERN_NAME);
-    }
-
-    public static void checkHost(String property, String value) {
-        if (StringUtils.isEmpty(value)) {
-            return;
-        }
-        if (value.startsWith(IPV6_START_MARK) && value.endsWith(IPV6_END_MARK)) {
-            // if the value start with "[" and end with "]", check whether it is IPV6
-            try {
-                InetAddress.getByName(value);
-                return;
-            } catch (UnknownHostException e) {
-                // not a IPv6 string, do nothing, go on to checkName
-            }
-        }
-        checkName(property, value);
-    }
-
-    public static void checkNameHasSymbol(String property, String value) {
-        checkProperty(property, value, MAX_LENGTH, PATTERN_NAME_HAS_SYMBOL);
-    }
-
-    public static void checkKey(String property, String value) {
-        checkProperty(property, value, MAX_LENGTH, PATTERN_KEY);
-    }
-
-    public static void checkMultiName(String property, String value) {
-        checkProperty(property, value, MAX_LENGTH, PATTERN_MULTI_NAME);
-    }
-
-    public static void checkPathName(String property, String value) {
-        checkProperty(property, value, MAX_PATH_LENGTH, PATTERN_PATH);
-    }
-
-    public static void checkMethodName(String property, String value) {
-        checkProperty(property, value, MAX_LENGTH, PATTERN_METHOD_NAME);
-    }
-
-    public static void checkParameterName(Map<String, String> parameters) {
-        if (CollectionUtils.isEmptyMap(parameters)) {
-            return;
-        }
-        List<String> ignoreCheckKeys = new ArrayList<>();
-        ignoreCheckKeys.add(BACKUP_KEY);
-        String ignoreCheckKeysStr = parameters.get(IGNORE_CHECK_KEYS);
-        if (!StringUtils.isBlank(ignoreCheckKeysStr)) {
-            ignoreCheckKeys.addAll(Arrays.asList(ignoreCheckKeysStr.split(",")));
-        }
-        for (Map.Entry<String, String> entry : parameters.entrySet()) {
-            if (!ignoreCheckKeys.contains(entry.getKey())) {
-                checkNameHasSymbol(entry.getKey(), entry.getValue());
-            }
-        }
-    }
-
-    public static void checkProperty(String property, String value, int maxlength, Pattern pattern) {
-        if (StringUtils.isEmpty(value)) {
-            return;
-        }
-        if (value.length() > maxlength) {
-            logger.error(CONFIG_PARAMETER_FORMAT_ERROR, "the value content is too long", "", "Parameter value format error. Invalid " +
-                property + "=\"" + value + "\" is longer than " + maxlength);
-        }
-        if (pattern != null) {
-            Matcher matcher = pattern.matcher(value);
-            if (!matcher.matches()) {
-                logger.error(CONFIG_PARAMETER_FORMAT_ERROR, "the value content is illegal character", "", "Parameter value format error. Invalid " +
-                    property + "=\"" + value + "\" contains illegal " +
-                    "character, only digit, letter, '-', '_' or '.' is legal.");
-            }
-        }
-    }
-
-}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/DefaultConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/DefaultConfigValidator.java
deleted file mode 100644
index 396f6afc49..0000000000
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/DefaultConfigValidator.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.config.utils;
-
-import org.apache.dubbo.config.AbstractConfig;
-import org.apache.dubbo.config.ApplicationConfig;
-import org.apache.dubbo.config.ConsumerConfig;
-import org.apache.dubbo.config.MetadataReportConfig;
-import org.apache.dubbo.config.MetricsConfig;
-import org.apache.dubbo.config.ModuleConfig;
-import org.apache.dubbo.config.MonitorConfig;
-import org.apache.dubbo.config.ProtocolConfig;
-import org.apache.dubbo.config.ProviderConfig;
-import org.apache.dubbo.config.RegistryConfig;
-import org.apache.dubbo.config.SslConfig;
-import org.apache.dubbo.config.TracingConfig;
-import org.apache.dubbo.config.context.ConfigValidator;
-
-public class DefaultConfigValidator implements ConfigValidator {
-
-    @Override
-    public void validate(AbstractConfig config) {
-        if (config instanceof ProtocolConfig) {
-            ConfigValidationUtils.validateProtocolConfig((ProtocolConfig) config);
-        } else if (config instanceof RegistryConfig) {
-            ConfigValidationUtils.validateRegistryConfig((RegistryConfig) config);
-        } else if (config instanceof MetadataReportConfig) {
-            ConfigValidationUtils.validateMetadataConfig((MetadataReportConfig) config);
-        } else if (config instanceof ProviderConfig) {
-            ConfigValidationUtils.validateProviderConfig((ProviderConfig) config);
-        } else if (config instanceof ConsumerConfig) {
-            ConfigValidationUtils.validateConsumerConfig((ConsumerConfig) config);
-        } else if (config instanceof ApplicationConfig) {
-            ConfigValidationUtils.validateApplicationConfig((ApplicationConfig) config);
-        } else if (config instanceof MonitorConfig) {
-            ConfigValidationUtils.validateMonitorConfig((MonitorConfig) config);
-        } else if (config instanceof ModuleConfig) {
-            ConfigValidationUtils.validateModuleConfig((ModuleConfig) config);
-        } else if (config instanceof MetricsConfig) {
-            ConfigValidationUtils.validateMetricsConfig((MetricsConfig) config);
-        } else if (config instanceof TracingConfig) {
-            ConfigValidationUtils.validateTracingConfig((TracingConfig) config);
-        } else if (config instanceof SslConfig) {
-            ConfigValidationUtils.validateSslConfig((SslConfig) config);
-        }
-    }
-
-}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConfigCenterConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConfigCenterConfigValidator.java
new file mode 100644
index 0000000000..a67580c05c
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConfigCenterConfigValidator.java
@@ -0,0 +1,44 @@
+/*
+ * 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.validator;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.ConfigCenterConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+
+//TODO: Move to configcenter-api
+@Activate
+public class ConfigCenterConfigValidator implements ConfigValidator<ConfigCenterConfig> {
+
+    public static void validateConfigCenterConfig(ConfigCenterConfig config) {
+        if (config != null) {
+            ConfigValidationUtils.checkParameterName(config.getParameters());
+        }
+    }
+
+    @Override
+    public boolean validate(ConfigCenterConfig config) {
+        validateConfigCenterConfig(config);
+        return true;
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return ConfigCenterConfig.class.equals(configClass);
+    }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConsumerConfigValidator.java
similarity index 53%
copy from dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
copy to dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConsumerConfigValidator.java
index 7d20b1b658..7c145ebfd2 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ConsumerConfigValidator.java
@@ -14,12 +14,29 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.context;
+package org.apache.dubbo.config.validator;
 
-import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.ConsumerConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
 
-public interface ConfigValidator {
+@Activate
+public class ConsumerConfigValidator implements ConfigValidator<ConsumerConfig> {
 
-    void validate(AbstractConfig config);
+    public static void validateConsumerConfig(ConsumerConfig config) {
+        //TODO
+        if (config == null) {
+        }
+    }
 
+    @Override
+    public boolean validate(ConsumerConfig config) {
+        validateConsumerConfig(config);
+        return true;
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return ConsumerConfig.class.isAssignableFrom(configClass);
+    }
 }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/InterfaceConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/InterfaceConfigValidator.java
new file mode 100644
index 0000000000..4a55275338
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/InterfaceConfigValidator.java
@@ -0,0 +1,68 @@
+/*
+ * 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.validator;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.config.AbstractInterfaceConfig;
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+import org.apache.dubbo.rpc.Filter;
+import org.apache.dubbo.rpc.ProxyFactory;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.FILTER_KEY;
+import static org.apache.dubbo.config.Constants.LAYER_KEY;
+import static org.apache.dubbo.rpc.Constants.LOCAL_KEY;
+import static org.apache.dubbo.rpc.Constants.PROXY_KEY;
+
+@Activate
+public class InterfaceConfigValidator implements ConfigValidator<AbstractInterfaceConfig> {
+
+    public static void validateAbstractInterfaceConfig(AbstractInterfaceConfig config) {
+        ConfigValidationUtils.checkName(LOCAL_KEY, config.getLocal());
+        ConfigValidationUtils.checkName("stub", config.getStub());
+        ConfigValidationUtils.checkMultiName("owner", config.getOwner());
+
+        ConfigValidationUtils.checkExtension(config.getScopeModel(), ProxyFactory.class, PROXY_KEY, config.getProxy());
+        ConfigValidationUtils.checkExtension(config.getScopeModel(), Cluster.class, CLUSTER_KEY, config.getCluster());
+        ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), Arrays.asList(Filter.class, ClusterFilter.class), FILTER_KEY, config.getFilter());
+        ConfigValidationUtils.checkNameHasSymbol(LAYER_KEY, config.getLayer());
+
+        List<MethodConfig> methods = config.getMethods();
+        if (CollectionUtils.isNotEmpty(methods)) {
+            methods.forEach(MethodConfig::validate);
+        }
+    }
+
+    @Override
+    public boolean validate(AbstractInterfaceConfig config) {
+        validateAbstractInterfaceConfig(config);
+        return true;
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return AbstractInterfaceConfig.class.isAssignableFrom(configClass);
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/MethodConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/MethodConfigValidator.java
new file mode 100644
index 0000000000..811cd952ae
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/MethodConfigValidator.java
@@ -0,0 +1,63 @@
+/*
+ * 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.validator;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+
+import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
+import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
+import static org.apache.dubbo.rpc.Constants.FAIL_PREFIX;
+import static org.apache.dubbo.rpc.Constants.FORCE_PREFIX;
+import static org.apache.dubbo.rpc.Constants.MOCK_KEY;
+import static org.apache.dubbo.rpc.Constants.RETURN_PREFIX;
+import static org.apache.dubbo.rpc.Constants.THROW_PREFIX;
+
+@Activate
+public class MethodConfigValidator implements ConfigValidator<MethodConfig> {
+
+    public static void validateMethodConfig(MethodConfig config) {
+        ConfigValidationUtils.checkExtension(config.getScopeModel(), LoadBalance.class, LOADBALANCE_KEY, config.getLoadbalance());
+        ConfigValidationUtils.checkParameterName(config.getParameters());
+        ConfigValidationUtils.checkMethodName("name", config.getName());
+
+        String mock = config.getMock();
+        if (isNotEmpty(mock)) {
+            if (mock.startsWith(RETURN_PREFIX) || mock.startsWith(THROW_PREFIX + " ")) {
+                ConfigValidationUtils.checkLength(MOCK_KEY, mock);
+            } else if (mock.startsWith(FAIL_PREFIX) || mock.startsWith(FORCE_PREFIX)) {
+                ConfigValidationUtils.checkNameHasSymbol(MOCK_KEY, mock);
+            } else {
+                ConfigValidationUtils.checkName(MOCK_KEY, mock);
+            }
+        }
+    }
+
+    @Override
+    public boolean validate(MethodConfig config) {
+        validateMethodConfig(config);
+        return true;
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return MethodConfig.class.equals(configClass);
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ProviderConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ProviderConfigValidator.java
new file mode 100644
index 0000000000..1d7b4df139
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ProviderConfigValidator.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.validator;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.status.StatusChecker;
+import org.apache.dubbo.common.threadpool.ThreadPool;
+import org.apache.dubbo.config.ProviderConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+import org.apache.dubbo.remoting.Transporter;
+import org.apache.dubbo.remoting.exchange.Exchanger;
+import org.apache.dubbo.remoting.telnet.TelnetHandler;
+
+import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
+import static org.apache.dubbo.config.Constants.CONTEXTPATH_KEY;
+import static org.apache.dubbo.config.Constants.STATUS_KEY;
+import static org.apache.dubbo.remoting.Constants.EXCHANGER_KEY;
+import static org.apache.dubbo.remoting.Constants.TELNET_KEY;
+import static org.apache.dubbo.remoting.Constants.TRANSPORTER_KEY;
+
+@Activate
+public class ProviderConfigValidator implements ConfigValidator<ProviderConfig> {
+
+    @Override
+    public boolean validate(ProviderConfig config) {
+        validateProviderConfig(config);
+        return true;
+    }
+
+    public static void validateProviderConfig(ProviderConfig config) {
+        ConfigValidationUtils.checkPathName(CONTEXTPATH_KEY, config.getContextpath());
+        ConfigValidationUtils.checkExtension(config.getScopeModel(), ThreadPool.class, THREADPOOL_KEY, config.getThreadpool());
+        ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), TelnetHandler.class, TELNET_KEY, config.getTelnet());
+        ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), StatusChecker.class, STATUS_KEY, config.getStatus());
+        ConfigValidationUtils.checkExtension(config.getScopeModel(), Transporter.class, TRANSPORTER_KEY, config.getTransporter());
+        ConfigValidationUtils.checkExtension(config.getScopeModel(), Exchanger.class, EXCHANGER_KEY, config.getExchanger());
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return ProviderConfig.class.isAssignableFrom(configClass);
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ReferenceConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ReferenceConfigValidator.java
new file mode 100644
index 0000000000..b804d62db2
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ReferenceConfigValidator.java
@@ -0,0 +1,65 @@
+/*
+ * 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.validator;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.ConsumerConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+import org.apache.dubbo.rpc.InvokerListener;
+
+import java.util.List;
+
+import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+import static org.apache.dubbo.remoting.Constants.CLIENT_KEY;
+
+@Activate
+public class ReferenceConfigValidator implements ConfigValidator<ReferenceConfig<?>> {
+
+    @Override
+    public boolean validate(ReferenceConfig<?> config) {
+        validateReferenceConfig(config);
+        return true;
+    }
+
+    public static void validateReferenceConfig(ReferenceConfig<?> config) {
+        ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), InvokerListener.class, "listener", config.getListener());
+        ConfigValidationUtils.checkKey(VERSION_KEY, config.getVersion());
+        ConfigValidationUtils.checkKey(GROUP_KEY, config.getGroup());
+        ConfigValidationUtils.checkName(CLIENT_KEY, config.getClient());
+
+        List<RegistryConfig> registries = config.getRegistries();
+        if (registries != null) {
+            for (RegistryConfig registry : registries) {
+                registry.validate();
+            }
+        }
+
+        ConsumerConfig consumerConfig = config.getConsumer();
+        if (consumerConfig != null) {
+            consumerConfig.validate();
+        }
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return ReferenceConfig.class.equals(configClass);
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ServiceConfigValidator.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ServiceConfigValidator.java
new file mode 100644
index 0000000000..bea8a54ab0
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/validator/ServiceConfigValidator.java
@@ -0,0 +1,78 @@
+/*
+ * 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.validator;
+
+import org.apache.dubbo.common.extension.Activate;
+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.context.ConfigValidator;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+import org.apache.dubbo.rpc.ExporterListener;
+
+import java.util.List;
+
+import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
+
+@Activate
+public class ServiceConfigValidator implements ConfigValidator<ServiceConfig<?>> {
+
+    public static void validateServiceConfig(ServiceConfig<?> config) {
+
+        ConfigValidationUtils.checkKey(VERSION_KEY, config.getVersion());
+        ConfigValidationUtils.checkKey(GROUP_KEY, config.getGroup());
+        ConfigValidationUtils.checkName(TOKEN_KEY, config.getToken());
+        ConfigValidationUtils.checkPathName(PATH_KEY, config.getPath());
+
+        ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), ExporterListener.class, "listener", config.getListener());
+
+        List<RegistryConfig> registries = config.getRegistries();
+        if (registries != null) {
+            for (RegistryConfig registry : registries) {
+                registry.validate();
+            }
+        }
+
+        List<ProtocolConfig> protocols = config.getProtocols();
+        if (protocols != null) {
+            for (ProtocolConfig protocol : protocols) {
+                protocol.validate();
+            }
+        }
+
+        ProviderConfig providerConfig = config.getProvider();
+        if (providerConfig != null) {
+            providerConfig.validate();
+        }
+    }
+
+    @Override
+    public boolean validate(ServiceConfig<?> config) {
+        validateServiceConfig(config);
+        return true;
+    }
+
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return ServiceConfig.class.equals(configClass);
+    }
+}
diff --git a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
new file mode 100644
index 0000000000..6ab0e95080
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
@@ -0,0 +1,8 @@
+config-center=org.apache.dubbo.config.validator.ConfigCenterConfigValidator
+consumer=org.apache.dubbo.config.validator.ConsumerConfigValidator
+interface=org.apache.dubbo.config.validator.InterfaceConfigValidator
+method=org.apache.dubbo.config.validator.MethodConfigValidator
+provider=org.apache.dubbo.config.validator.ProviderConfigValidator
+reference=org.apache.dubbo.config.validator.ReferenceConfigValidator
+service=org.apache.dubbo.config.validator.ServiceConfigValidator
+
diff --git a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.deploy.lifecycle.application.ApplicationLifecycle b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.deploy.lifecycle.application.ApplicationLifecycle
index ca779fe73f..8e806008f2 100644
--- a/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.deploy.lifecycle.application.ApplicationLifecycle
+++ b/dubbo-config/dubbo-config-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.deploy.lifecycle.application.ApplicationLifecycle
@@ -3,3 +3,4 @@ config-post-handle=org.apache.dubbo.config.deploy.lifecycle.application.Applicat
 module-initialize=org.apache.dubbo.config.deploy.lifecycle.application.ModuleInitializeLifecycle
 post-offline=org.apache.dubbo.config.deploy.lifecycle.application.ApplicationPostOfflineLifecycle
 app-prepare=org.apache.dubbo.config.deploy.lifecycle.application.ApplicationPrepareLifecycle
+validator-registry=org.apache.dubbo.config.deploy.lifecycle.application.ValidatorRegistryDeployListener
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
index 1a986a5884..55bcbae629 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
@@ -131,7 +131,7 @@ class AbstractConfigTest {
         protocolConfig.setCodec("exchange");
         protocolConfig.setName("test");
         protocolConfig.setHost("host");
-        ConfigValidationUtils.validateProtocolConfig(protocolConfig);
+        protocolConfig.validate();
     }
 
     @Test
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigValidatorExistTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigValidatorExistTest.java
new file mode 100644
index 0000000000..980ce01583
--- /dev/null
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigValidatorExistTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config;
+
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.config.validator.ConsumerConfigValidator;
+import org.apache.dubbo.config.validator.InterfaceConfigValidator;
+import org.apache.dubbo.config.validator.MethodConfigValidator;
+import org.apache.dubbo.config.validator.ProviderConfigValidator;
+import org.apache.dubbo.config.validator.ReferenceConfigValidator;
+import org.apache.dubbo.config.validator.ServiceConfigValidator;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import java.util.List;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+
+
+public class ConfigValidatorExistTest {
+
+    ConfigValidateFacade validateFacade;
+
+    @Test
+    void testConfigValidatorExist(){
+        FrameworkModel frameworkModel = FrameworkModel.defaultModel();
+        ApplicationModel applicationModel = frameworkModel.newApplication();
+
+        validateFacade = new ConfigValidateFacade(applicationModel);
+        Assertions.assertNotNull(validateFacade);
+        Assertions.assertTrue(validateFacade.getValidators().size() >= 7);
+
+        try(
+            MockedStatic<ConsumerConfigValidator> configValidatorMockedStatic = Mockito.mockStatic(ConsumerConfigValidator.class);
+            MockedStatic<InterfaceConfigValidator> interfaceConfigValidatorMockedStatic = Mockito.mockStatic(InterfaceConfigValidator.class);
+            MockedStatic<MethodConfigValidator> methodConfigValidatorMockedStatic = Mockito.mockStatic(MethodConfigValidator.class);
+            MockedStatic<ProviderConfigValidator> providerConfigValidatorMockedStatic = Mockito.mockStatic(ProviderConfigValidator.class);
+            MockedStatic<ReferenceConfigValidator> referenceConfigValidatorMockedStatic = Mockito.mockStatic(ReferenceConfigValidator.class);
+            MockedStatic<ServiceConfigValidator> serviceConfigValidatorMockedStatic = Mockito.mockStatic(ServiceConfigValidator.class);
+        ){
+            configValidatorMockedStatic.when(()-> ConsumerConfigValidator.validateConsumerConfig(any())).thenCallRealMethod();
+            interfaceConfigValidatorMockedStatic.when(()-> InterfaceConfigValidator.validateAbstractInterfaceConfig(any())).thenCallRealMethod();
+            methodConfigValidatorMockedStatic.when(()-> MethodConfigValidator.validateMethodConfig(any())).thenCallRealMethod();
+            providerConfigValidatorMockedStatic.when(()-> ProviderConfigValidator.validateProviderConfig(any())).thenCallRealMethod();
+            referenceConfigValidatorMockedStatic.when(()-> ReferenceConfigValidator.validateReferenceConfig(any())).thenCallRealMethod();
+            serviceConfigValidatorMockedStatic.when(()->ServiceConfigValidator.validateServiceConfig(any())).thenCallRealMethod();
+            triggerValidate(new ConsumerConfig());
+            triggerValidate(new AbstractInterfaceConfig() {
+                @Override
+                public List<URL> getExportedUrls() {
+                    return super.getExportedUrls();
+                }
+            });
+            triggerValidate(new MethodConfig());
+            triggerValidate(new ProviderConfig());
+            triggerValidate(new ReferenceConfig<>());
+            triggerValidate(new ServiceConfig<>());
+
+            configValidatorMockedStatic.verify(()-> ConsumerConfigValidator.validateConsumerConfig(any()),atLeastOnce());
+            interfaceConfigValidatorMockedStatic.verify(()-> InterfaceConfigValidator.validateAbstractInterfaceConfig(any()),atLeastOnce());
+            methodConfigValidatorMockedStatic.verify(()->MethodConfigValidator.validateMethodConfig(any()),atLeastOnce());
+            providerConfigValidatorMockedStatic.verify(()->ProviderConfigValidator.validateProviderConfig(any()),atLeastOnce());
+            referenceConfigValidatorMockedStatic.verify(()->ReferenceConfigValidator.validateReferenceConfig(any()),atLeastOnce());
+            serviceConfigValidatorMockedStatic.verify(()-> ServiceConfigValidator.validateServiceConfig(any()),atLeastOnce());
+        }
+    }
+
+    void triggerValidate(AbstractConfig config){
+        try {
+            validateFacade.validate(config);
+        }catch (Throwable ignored){};
+    }
+
+}
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
index 92e6e2b595..83793deab2 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
@@ -35,6 +35,7 @@ import org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter;
 import org.apache.dubbo.config.metadata.ExporterDeployListener;
 import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
 import org.apache.dubbo.config.utils.ConfigValidationUtils;
+import org.apache.dubbo.config.validator.ApplicationConfigValidator;
 import org.apache.dubbo.metadata.MetadataService;
 import org.apache.dubbo.monitor.MonitorService;
 import org.apache.dubbo.registry.RegistryService;
@@ -42,6 +43,7 @@ import org.apache.dubbo.rpc.Exporter;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;
 import org.apache.dubbo.test.check.registrycenter.config.ZookeeperRegistryCenterConfig;
+import org.apache.dubbo.util.MonitorUrlUtil;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
@@ -114,13 +116,13 @@ class DubboBootstrapTest {
 
             writeDubboProperties(SHUTDOWN_WAIT_KEY, "100");
             ApplicationModel.defaultModel().modelEnvironment().getPropertiesConfiguration().refresh();
-            ConfigValidationUtils.validateApplicationConfig(new ApplicationConfig("demo"));
+            ApplicationConfigValidator.validateApplicationConfig(new ApplicationConfig("demo"));
             Assertions.assertEquals("100", System.getProperty(SHUTDOWN_WAIT_KEY));
 
             System.clearProperty(SHUTDOWN_WAIT_KEY);
             writeDubboProperties(SHUTDOWN_WAIT_SECONDS_KEY, "1000");
             ApplicationModel.defaultModel().modelEnvironment().getPropertiesConfiguration().refresh();
-            ConfigValidationUtils.validateApplicationConfig(new ApplicationConfig("demo"));
+            ApplicationConfigValidator.validateApplicationConfig(new ApplicationConfig("demo"));
             Assertions.assertEquals("1000", System.getProperty(SHUTDOWN_WAIT_SECONDS_KEY));
         } finally {
             System.clearProperty("dubbo.application.name");
@@ -162,7 +164,7 @@ class DubboBootstrapTest {
     void testLoadUserMonitor_address_only() {
         // -Ddubbo.monitor.address=monitor-addr:12080
         SysProps.setProperty(DUBBO_MONITOR_ADDRESS, "monitor-addr:12080");
-        URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(new MonitorConfig()), new ServiceConfigURL("dubbo", "addr1", 9090));
+        URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(new MonitorConfig()), new ServiceConfigURL("dubbo", "addr1", 9090));
         Assertions.assertEquals("monitor-addr:12080", url.getAddress());
         Assertions.assertEquals(MonitorService.class.getName(), url.getParameter("interface"));
         Assertions.assertNotNull(url.getParameter("dubbo"));
@@ -176,7 +178,7 @@ class DubboBootstrapTest {
         MonitorConfig monitorConfig = new MonitorConfig();
         monitorConfig.setProtocol("registry");
 
-        URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));
+        URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));
         Assertions.assertEquals("dubbo", url.getProtocol());
         Assertions.assertEquals("registry", url.getParameter("protocol"));
     }
@@ -187,14 +189,14 @@ class DubboBootstrapTest {
         MonitorConfig monitorConfig = new MonitorConfig();
         monitorConfig.setProtocol("service-discovery-registry");
 
-        URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));
+        URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));
         Assertions.assertEquals("dubbo", url.getProtocol());
         Assertions.assertEquals("service-discovery-registry", url.getParameter("protocol"));
     }
 
     @Test
     void testLoadUserMonitor_no_monitor() {
-        URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(null), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));
+        URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(null), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));
         Assertions.assertNull(url);
     }
 
@@ -204,7 +206,7 @@ class DubboBootstrapTest {
         MonitorConfig monitorConfig = new MonitorConfig();
         monitorConfig.setProtocol("user");
 
-        URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));
+        URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));
         Assertions.assertEquals("user", url.getProtocol());
     }
 
@@ -213,7 +215,7 @@ class DubboBootstrapTest {
         // dubbo.monitor.address=user://1.2.3.4:5678?k=v
         MonitorConfig monitorConfig = new MonitorConfig();
         monitorConfig.setAddress("user://1.2.3.4:5678?param1=value1");
-        URL url = ConfigValidationUtils.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));
+        URL url = MonitorUrlUtil.loadMonitor(getTestInterfaceConfig(monitorConfig), URL.valueOf(ZookeeperRegistryCenterConfig.getConnectionAddress()));
         Assertions.assertEquals("user", url.getProtocol());
         Assertions.assertEquals("1.2.3.4:5678", url.getAddress());
         Assertions.assertEquals("value1", url.getParameter("param1"));
diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ConfigValidationUtilsTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ConfigValidationUtilsTest.java
index bd059ffb2a..d5bd6eac65 100644
--- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ConfigValidationUtilsTest.java
+++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/utils/ConfigValidationUtilsTest.java
@@ -20,7 +20,9 @@ import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
 import org.apache.dubbo.config.AbstractInterfaceConfig;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.MetadataReportConfig;
-
+import org.apache.dubbo.config.exception.ConfigValidationException;
+import org.apache.dubbo.config.validator.ApplicationConfigValidator;
+import org.apache.dubbo.config.validator.MetadataConfigValidator;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.mockito.MockedStatic;
@@ -29,9 +31,12 @@ import org.mockito.Mockito;
 import java.lang.reflect.Field;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CLASS_NOT_FOUND;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -45,7 +50,7 @@ class ConfigValidationUtilsTest {
         MetadataReportConfig config = new MetadataReportConfig();
         config.setAddress("protocol://ip:host");
         try {
-            ConfigValidationUtils.validateMetadataConfig(config);
+           MetadataConfigValidator.validateMetadataConfig(config);
         } catch (Exception e) {
             Assertions.fail("valid config expected.");
         }
@@ -53,7 +58,7 @@ class ConfigValidationUtilsTest {
         config.setAddress("ip:host");
         config.setProtocol("protocol");
         try {
-            ConfigValidationUtils.validateMetadataConfig(config);
+            MetadataConfigValidator.validateMetadataConfig(config);
         } catch (Exception e) {
             Assertions.fail("valid config expected.");
         }
@@ -61,17 +66,18 @@ class ConfigValidationUtilsTest {
         config.setAddress("ip:host");
         config.setProtocol(null);
         Assertions.assertThrows(IllegalArgumentException.class, () -> {
-            ConfigValidationUtils.validateMetadataConfig(config);
+            MetadataConfigValidator.validateMetadataConfig(config);
         });
     }
 
     @Test
     void testValidateApplicationConfig() throws Exception {
-        try (MockedStatic<ConfigValidationUtils> mockedStatic = Mockito.mockStatic(ConfigValidationUtils.class);) {
-            mockedStatic.when(() -> ConfigValidationUtils.validateApplicationConfig(any())).thenCallRealMethod();
+        try (MockedStatic<ApplicationConfigValidator> mockedStatic = Mockito.mockStatic(ApplicationConfigValidator.class);
+             MockedStatic<ConfigValidationUtils> configValidationUtilsMockedStatic =  Mockito.mockStatic(ConfigValidationUtils.class);) {
+            mockedStatic.when(() -> ApplicationConfigValidator.validateApplicationConfig(any())).thenCallRealMethod();
             ApplicationConfig config = new ApplicationConfig();
-            Assertions.assertThrows(IllegalStateException.class, () -> {
-                ConfigValidationUtils.validateApplicationConfig(config);
+            Assertions.assertThrows(ConfigValidationException.class, () -> {
+                ApplicationConfigValidator.validateApplicationConfig(config);
             });
 
             config.setName("testName");
@@ -83,14 +89,19 @@ class ConfigValidationUtilsTest {
             map.put("k1", "v1");
             map.put("k2", "v2");
             config.setParameters(map);
-            ConfigValidationUtils.validateApplicationConfig(config);
-            mockedStatic.verify(() -> {
+            ApplicationConfigValidator.validateApplicationConfig(config);
+
+            configValidationUtilsMockedStatic.when(()-> ConfigValidationUtils.checkName(anyString(),anyString())).thenCallRealMethod();
+            configValidationUtilsMockedStatic.when(()-> ConfigValidationUtils.checkMultiName(anyString(),anyString())).thenCallRealMethod();
+            configValidationUtilsMockedStatic.when(()-> ConfigValidationUtils.checkParameterName(any())).thenCallRealMethod();
+            configValidationUtilsMockedStatic.when(()-> ConfigValidationUtils.checkProperty(anyString(),anyString(),anyInt(),any(Pattern.class))).thenCallRealMethod();
+            configValidationUtilsMockedStatic.verify(() -> {
                 ConfigValidationUtils.checkName(any(), any());
             }, times(4));
-            mockedStatic.verify(() -> {
+            configValidationUtilsMockedStatic.verify(() -> {
                 ConfigValidationUtils.checkMultiName(any(), any());
             }, times(1));
-            mockedStatic.verify(() -> {
+            configValidationUtilsMockedStatic.verify(() -> {
                 ConfigValidationUtils.checkParameterName(any());
             }, times(1));
         }
@@ -98,13 +109,13 @@ class ConfigValidationUtilsTest {
 
     @Test
     void testCheckQosInApplicationConfig() throws Exception {
-        ConfigValidationUtils mock = Mockito.mock(ConfigValidationUtils.class);
+        ApplicationConfigValidator mock = Mockito.mock(ApplicationConfigValidator.class);
         ErrorTypeAwareLogger loggerMock = Mockito.mock(ErrorTypeAwareLogger.class);
         injectField(mock.getClass().getDeclaredField("logger"), loggerMock);
         ApplicationConfig config = new ApplicationConfig();
         config.setName("testName");
         config.setQosEnable(false);
-        mock.validateApplicationConfig(config);
+        ApplicationConfigValidator.validateApplicationConfig(config);
         verify(loggerMock, never()).warn(any(), any(Throwable.class));
 
         config.setQosEnable(true);
diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml
index 8f8efd3369..60f9d50e5b 100644
--- a/dubbo-distribution/dubbo-all/pom.xml
+++ b/dubbo-distribution/dubbo-all/pom.xml
@@ -1590,6 +1590,13 @@
                                         META-INF/dubbo/internal/org.apache.dubbo.config.CommonConfigPostProcessor
                                     </resource>
                                 </transformer>
+
+                                <transformer
+                                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+                                    <resource>
+                                        META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
+                                    </resource>
+                                </transformer>
                             </transformers>
                             <filters>
                                 <filter>
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/config/validator/MetadataConfigValidator.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/config/validator/MetadataConfigValidator.java
new file mode 100644
index 0000000000..d0beb62714
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/config/validator/MetadataConfigValidator.java
@@ -0,0 +1,64 @@
+/*
+ * 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.validator;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+
+import static org.apache.dubbo.common.utils.StringUtils.isEmpty;
+
+@Activate
+public class MetadataConfigValidator implements ConfigValidator<MetadataReportConfig> {
+
+    @Override
+    public boolean validate(MetadataReportConfig config) {
+       return validateMetadataConfig(config);
+    }
+
+    public static boolean validateMetadataConfig(MetadataReportConfig metadataReportConfig) {
+        if (!isValidMetadataConfig(metadataReportConfig)) {
+            return false;
+        }
+
+        String address = metadataReportConfig.getAddress();
+        String protocol = metadataReportConfig.getProtocol();
+
+        if ((isEmpty(address) || !address.contains("://")) && isEmpty(protocol)) {
+            throw new IllegalArgumentException("Please specify valid protocol or address for metadata report " + address);
+        }
+        return true;
+    }
+
+    public static boolean isValidMetadataConfig(MetadataReportConfig metadataReportConfig) {
+        if (metadataReportConfig == null) {
+            return false;
+        }
+
+        if (Boolean.FALSE.equals(metadataReportConfig.getReportMetadata()) &&
+            Boolean.FALSE.equals(metadataReportConfig.getReportDefinition())) {
+            return false;
+        }
+
+        return !isEmpty(metadataReportConfig.getAddress());
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return MetadataReportConfig.class.isAssignableFrom(configClass);
+    }
+}
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
new file mode 100644
index 0000000000..5301ecbc08
--- /dev/null
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
@@ -0,0 +1 @@
+metadata=org.apache.dubbo.config.validator.MetadataConfigValidator
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/config/validator/MetricsConfigValidator.java
similarity index 53%
copy from dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
copy to dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/config/validator/MetricsConfigValidator.java
index 7d20b1b658..f1fbc062e0 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
+++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/config/validator/MetricsConfigValidator.java
@@ -14,12 +14,29 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.context;
+package org.apache.dubbo.config.validator;
 
-import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.MetricsConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
 
-public interface ConfigValidator {
+@Activate
+public class MetricsConfigValidator implements ConfigValidator<MetricsConfig> {
 
-    void validate(AbstractConfig config);
+    public static void validateMetricsConfig(MetricsConfig metricsConfig) {
+        //TODO
+        if (metricsConfig == null) {
+        }
+    }
 
+    @Override
+    public boolean validate(MetricsConfig config) {
+        validateMetricsConfig(config);
+        return true;
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return MetricsConfig.class.isAssignableFrom(configClass);
+    }
 }
diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-metrics/dubbo-metrics-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
new file mode 100644
index 0000000000..2716b9c85f
--- /dev/null
+++ b/dubbo-metrics/dubbo-metrics-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
@@ -0,0 +1 @@
+metrics=org.apache.dubbo.config.validator.MetricsConfigValidator
diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java
index 9fd5257cc5..1e4ecebbe8 100644
--- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java
+++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java
@@ -33,7 +33,6 @@ import org.apache.dubbo.metrics.model.key.MetricsKey;
 import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
 import org.apache.dubbo.metrics.model.key.MetricsLevel;
 import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
-import org.apache.dubbo.metrics.model.key.TypeWrapper;
 import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
 import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
 import org.apache.dubbo.metrics.model.sample.MetricSample;
@@ -45,7 +44,6 @@ import org.apache.dubbo.rpc.RpcException;
 import org.apache.dubbo.rpc.RpcInvocation;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
-
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
@@ -157,7 +155,8 @@ class DefaultCollectorTest {
         // push finish rt +1
         List<MetricSample> metricSamples = collector.collect();
         //num(total+success+processing) + rt(5) + error code = 9
-        Assertions.assertEquals(metricSamples.size(),9);
+        Assertions.assertEquals(9, metricSamples.size());
+      
         List<String> metricsNames = metricSamples.stream().map(MetricSample::getName).collect(Collectors.toList());
         // No error will contain total+success+processing
         String REQUESTS = new MetricsKeyWrapper(METRIC_REQUESTS, MetricsPlaceValue.of(side, MetricsLevel.SERVICE)).targetKey();
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/config/validator/TracingConfigValidator.java
similarity index 53%
copy from dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
copy to dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/config/validator/TracingConfigValidator.java
index 7d20b1b658..a975dc019a 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
+++ b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/config/validator/TracingConfigValidator.java
@@ -14,12 +14,29 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.context;
+package org.apache.dubbo.config.validator;
 
-import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.TracingConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
 
-public interface ConfigValidator {
+@Activate
+public class TracingConfigValidator implements ConfigValidator<TracingConfig> {
 
-    void validate(AbstractConfig config);
+    public static void validateTracingConfig(TracingConfig tracingConfig) {
+        // TODO
+        if (tracingConfig == null) {
+        }
+    }
 
+    @Override
+    public boolean validate(TracingConfig config) {
+        validateTracingConfig(config);
+        return true;
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return TracingConfig.class.isAssignableFrom(configClass);
+    }
 }
diff --git a/dubbo-metrics/dubbo-tracing/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-metrics/dubbo-tracing/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
new file mode 100644
index 0000000000..32777468ad
--- /dev/null
+++ b/dubbo-metrics/dubbo-tracing/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
@@ -0,0 +1 @@
+tracing=org.apache.dubbo.config.validator.TracingConfigValidator
diff --git a/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/util/MonitorUrlUtil.java b/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/util/MonitorUrlUtil.java
new file mode 100644
index 0000000000..23fd61e9c0
--- /dev/null
+++ b/dubbo-monitor/dubbo-monitor-api/src/main/java/org/apache/dubbo/util/MonitorUrlUtil.java
@@ -0,0 +1,102 @@
+/*
+ * 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.util;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.URLBuilder;
+import org.apache.dubbo.common.utils.ConfigUtils;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.common.utils.UrlUtils;
+import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.config.AbstractInterfaceConfig;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.monitor.Constants;
+import org.apache.dubbo.monitor.MonitorFactory;
+import org.apache.dubbo.monitor.MonitorService;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_MONITOR_ADDRESS;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
+import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
+import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_PROTOCOL;
+import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
+import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
+
+public class MonitorUrlUtil {
+
+    public static URL loadMonitor(AbstractInterfaceConfig interfaceConfig, URL registryURL) {
+        Map<String, String> map = new HashMap<String, String>();
+        map.put(INTERFACE_KEY, MonitorService.class.getName());
+        AbstractInterfaceConfig.appendRuntimeParameters(map);
+        //set ip
+        String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);
+        if (StringUtils.isEmpty(hostToRegistry)) {
+            hostToRegistry = NetUtils.getLocalHost();
+        } else if (NetUtils.isInvalidLocalHost(hostToRegistry)) {
+            throw new IllegalArgumentException("Specified invalid registry ip from property:" +
+                DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
+        }
+        map.put(REGISTER_IP_KEY, hostToRegistry);
+
+        MonitorConfig monitor = interfaceConfig.getMonitor();
+        ApplicationConfig application = interfaceConfig.getApplication();
+        AbstractConfig.appendParameters(map, monitor);
+        AbstractConfig.appendParameters(map, application);
+        String address = null;
+        String sysAddress = System.getProperty(DUBBO_MONITOR_ADDRESS);
+        if (sysAddress != null && sysAddress.length() > 0) {
+            address = sysAddress;
+        } else if (monitor != null) {
+            address = monitor.getAddress();
+        }
+        String protocol = monitor == null ? null : monitor.getProtocol();
+        if (monitor != null &&
+            (REGISTRY_PROTOCOL.equals(protocol) || SERVICE_REGISTRY_PROTOCOL.equals(protocol))
+            && registryURL != null) {
+            return URLBuilder.from(registryURL)
+                .setProtocol(DUBBO_PROTOCOL)
+                .addParameter(PROTOCOL_KEY, protocol)
+                .putAttribute(REFER_KEY, map)
+                .build();
+
+        } else if (ConfigUtils.isNotEmpty(address) || ConfigUtils.isNotEmpty(protocol)) {
+            if (!map.containsKey(PROTOCOL_KEY)) {
+                if (interfaceConfig.getScopeModel().getExtensionLoader(MonitorFactory.class).hasExtension(Constants.LOGSTAT_PROTOCOL)) {
+                    map.put(PROTOCOL_KEY, Constants.LOGSTAT_PROTOCOL);
+                } else if (ConfigUtils.isNotEmpty(protocol)) {
+                    map.put(PROTOCOL_KEY, protocol);
+                } else {
+                    map.put(PROTOCOL_KEY, DUBBO_PROTOCOL);
+                }
+            }
+            if (ConfigUtils.isEmpty(address)) {
+                address = LOCALHOST_VALUE;
+            }
+            return UrlUtils.parseURL(address, map);
+        }
+        return null;
+    }
+}
diff --git a/dubbo-monitor/dubbo-monitor-common/src/main/java/org/apache/dubbo/config/validator/MonitorConfigValidator.java b/dubbo-monitor/dubbo-monitor-common/src/main/java/org/apache/dubbo/config/validator/MonitorConfigValidator.java
new file mode 100644
index 0000000000..efcc3c1bef
--- /dev/null
+++ b/dubbo-monitor/dubbo-monitor-common/src/main/java/org/apache/dubbo/config/validator/MonitorConfigValidator.java
@@ -0,0 +1,53 @@
+/*
+ * 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.validator;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+
+
+@Activate
+public class MonitorConfigValidator implements ConfigValidator<MonitorConfig> {
+
+    private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MonitorConfigValidator.class);
+
+    public static boolean validateMonitorConfig(MonitorConfig config) {
+        if (config != null) {
+            if (!config.isValid()) {
+                logger.info("There's no valid monitor config found, if you want to open monitor statistics for Dubbo, " +
+                    "please make sure your monitor is configured properly.");
+                return false;
+            }
+            ConfigValidationUtils.checkParameterName(config.getParameters());
+        }
+        return true;
+    }
+
+    @Override
+    public boolean validate(MonitorConfig config) {
+        return validateMonitorConfig(config);
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return MonitorConfig.class.isAssignableFrom(configClass);
+    }
+}
diff --git a/dubbo-monitor/dubbo-monitor-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-monitor/dubbo-monitor-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
new file mode 100644
index 0000000000..ca6341e3da
--- /dev/null
+++ b/dubbo-monitor/dubbo-monitor-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
@@ -0,0 +1 @@
+monitor=org.apache.dubbo.config.validator.MonitorConfigValidator
diff --git a/dubbo-plugin/dubbo-security/src/test/java/org/apache/dubbo/security/cert/CertDeployerListenerTest.java b/dubbo-plugin/dubbo-security/src/test/java/org/apache/dubbo/security/cert/CertDeployerListenerTest.java
index ce6a5fa665..11ca883d94 100644
--- a/dubbo-plugin/dubbo-security/src/test/java/org/apache/dubbo/security/cert/CertDeployerListenerTest.java
+++ b/dubbo-plugin/dubbo-security/src/test/java/org/apache/dubbo/security/cert/CertDeployerListenerTest.java
@@ -20,6 +20,7 @@ import org.apache.dubbo.common.deploy.ApplicationDeployer;
 import org.apache.dubbo.config.ApplicationConfig;
 import org.apache.dubbo.config.MetadataReportConfig;
 import org.apache.dubbo.config.SslConfig;
+import org.apache.dubbo.config.exception.ConfigValidationException;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
@@ -111,7 +112,7 @@ class CertDeployerListenerTest {
             applicationModel.getApplicationConfigManager().addMetadataReport(new MetadataReportConfig("absent"));
 
             ApplicationDeployer deployer = applicationModel.getDeployer();
-            Assertions.assertThrows(IllegalArgumentException.class, deployer::start);
+            Assertions.assertThrows(ConfigValidationException.class, deployer::start);
             Mockito.verify(reference.get(), Mockito.times(1))
                 .connect(Mockito.any());
             Mockito.verify(reference.get(), Mockito.atLeast(1))
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/config/validate/RegistryConfigValidator.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/config/validate/RegistryConfigValidator.java
new file mode 100644
index 0000000000..ce40b7a974
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/config/validate/RegistryConfigValidator.java
@@ -0,0 +1,56 @@
+/*
+ * 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.validate;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+
+import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
+import static org.apache.dubbo.remoting.Constants.CLIENT_KEY;
+import static org.apache.dubbo.remoting.Constants.SERVER_KEY;
+import static org.apache.dubbo.remoting.Constants.TRANSPORTER_KEY;
+
+@Activate
+public class RegistryConfigValidator implements ConfigValidator<RegistryConfig> {
+
+    @Override
+    public boolean validate(RegistryConfig config) {
+        validateRegistryConfig(config);
+        return true;
+    }
+
+    public static void validateRegistryConfig(RegistryConfig config) {
+        ConfigValidationUtils.checkName(PROTOCOL_KEY, config.getProtocol());
+        ConfigValidationUtils.checkName(USERNAME_KEY, config.getUsername());
+        ConfigValidationUtils.checkLength(PASSWORD_KEY, config.getPassword());
+        ConfigValidationUtils.checkPathLength(FILE_KEY, config.getFile());
+        ConfigValidationUtils.checkName(TRANSPORTER_KEY, config.getTransporter());
+        ConfigValidationUtils.checkName(SERVER_KEY, config.getServer());
+        ConfigValidationUtils.checkName(CLIENT_KEY, config.getClient());
+        ConfigValidationUtils.checkParameterName(config.getParameters());
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return RegistryConfig.class.isAssignableFrom(configClass);
+    }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/config/validator/SslConfigValidator.java
similarity index 56%
copy from dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
copy to dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/config/validator/SslConfigValidator.java
index 7d20b1b658..d6bf0374fc 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigValidator.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/config/validator/SslConfigValidator.java
@@ -14,12 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.config.context;
+package org.apache.dubbo.config.validator;
 
-import org.apache.dubbo.config.AbstractConfig;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.SslConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
 
-public interface ConfigValidator {
+@Activate
+public class SslConfigValidator implements ConfigValidator<SslConfig> {
 
-    void validate(AbstractConfig config);
+    public static void validateSslConfig(SslConfig sslConfig) {
+        // TODO
+    }
 
+    @Override
+    public boolean validate(SslConfig config) {
+        validateSslConfig(config);
+        return true;
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return SslConfig.class.isAssignableFrom(configClass);
+    }
 }
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
new file mode 100644
index 0000000000..56a39d1693
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
@@ -0,0 +1 @@
+ssl=org.apache.dubbo.config.validator.SslConfigValidator
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/config/validator/ProtocolConfigValidator.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/config/validator/ProtocolConfigValidator.java
new file mode 100644
index 0000000000..2884bf4030
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/config/validator/ProtocolConfigValidator.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.validator;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.serialize.Serialization;
+import org.apache.dubbo.common.status.StatusChecker;
+import org.apache.dubbo.common.threadpool.ThreadPool;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.context.ConfigValidator;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+import org.apache.dubbo.remoting.Codec2;
+import org.apache.dubbo.remoting.Dispatcher;
+import org.apache.dubbo.remoting.Transporter;
+import org.apache.dubbo.remoting.exchange.Exchanger;
+import org.apache.dubbo.remoting.telnet.TelnetHandler;
+
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
+import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
+import static org.apache.dubbo.remoting.Constants.CLIENT_KEY;
+import static org.apache.dubbo.remoting.Constants.CODEC_KEY;
+import static org.apache.dubbo.remoting.Constants.DISPATCHER_KEY;
+import static org.apache.dubbo.remoting.Constants.EXCHANGER_KEY;
+import static org.apache.dubbo.remoting.Constants.SERIALIZATION_KEY;
+import static org.apache.dubbo.remoting.Constants.SERVER_KEY;
+import static org.apache.dubbo.remoting.Constants.TELNET_KEY;
+import static org.apache.dubbo.remoting.Constants.TRANSPORTER_KEY;
+
+@Activate
+public class ProtocolConfigValidator implements ConfigValidator<ProtocolConfig> {
+
+    @Override
+    public boolean validate(ProtocolConfig config) {
+        validateProtocolConfig(config);
+        return true;
+    }
+
+    public static void validateProtocolConfig(ProtocolConfig config) {
+        if (config != null) {
+            String name = config.getName();
+            ConfigValidationUtils.checkName("name", name);
+            ConfigValidationUtils.checkHost(HOST_KEY, config.getHost());
+            ConfigValidationUtils.checkPathName("contextpath", config.getContextpath());
+
+
+            if (DUBBO_PROTOCOL.equals(name)) {
+                ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), Codec2.class, CODEC_KEY, config.getCodec());
+                ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), Serialization.class, SERIALIZATION_KEY, config.getSerialization());
+                ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), Transporter.class, SERVER_KEY, config.getServer());
+                ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), Transporter.class, CLIENT_KEY, config.getClient());
+            }
+
+            ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), TelnetHandler.class, TELNET_KEY, config.getTelnet());
+            ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), StatusChecker.class, "status", config.getStatus());
+            ConfigValidationUtils.checkExtension(config.getScopeModel(), Transporter.class, TRANSPORTER_KEY, config.getTransporter());
+            ConfigValidationUtils.checkExtension(config.getScopeModel(), Exchanger.class, EXCHANGER_KEY, config.getExchanger());
+            ConfigValidationUtils.checkExtension(config.getScopeModel(), Dispatcher.class, DISPATCHER_KEY, config.getDispatcher());
+            ConfigValidationUtils.checkExtension(config.getScopeModel(), Dispatcher.class, "dispather", config.getDispather());
+            ConfigValidationUtils.checkExtension(config.getScopeModel(), ThreadPool.class, THREADPOOL_KEY, config.getThreadpool());
+        }
+    }
+
+    @Override
+    public boolean isSupport(Class<?> configClass) {
+        return ProtocolConfig.class.isAssignableFrom(configClass);
+    }
+}
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator b/dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
new file mode 100644
index 0000000000..e53a309b5c
--- /dev/null
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.config.context.ConfigValidator
@@ -0,0 +1 @@
+protocol=org.apache.dubbo.config.validator.ProtocolConfigValidator