You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@seata.apache.org by ji...@apache.org on 2024/04/30 06:45:37 UTC

(incubator-seata) branch 2.x updated: optimize: optimize config compatible module (#6403)

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

jimin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git


The following commit(s) were added to refs/heads/2.x by this push:
     new 4f16097d69 optimize: optimize config compatible module (#6403)
4f16097d69 is described below

commit 4f16097d6934aeac324f524558661677bd755f5c
Author: jimin <sl...@163.com>
AuthorDate: Tue Apr 30 14:45:32 2024 +0800

    optimize: optimize config compatible module (#6403)
---
 changes/en-us/2.x.md                               |   6 +-
 changes/zh-cn/2.x.md                               |   4 +-
 .../seata/common/loader/EnhancedServiceLoader.java | 131 +++++---
 .../java/io/seata/common/util/StringUtils.java     |   3 +
 .../java/io/seata/core/context/RootContext.java    |  12 +
 .../io/seata/config/AbstractConfiguration.java     | 164 ++++++++++
 .../main/java/io/seata/config/Configuration.java   | 310 ++++++++++++++++++
 .../io/seata/config/ConfigurationChangeEvent.java  | 138 ++++++++
 .../seata/config/ConfigurationChangeListener.java  |  91 ++++++
 .../io/seata/config/ConfigurationChangeType.java   |  20 +-
 .../io/seata/config/ConfigurationProvider.java     |  10 +-
 .../io/seata/config/ExtConfigurationProvider.java  |  13 +-
 .../java/io/seata/config/FileConfiguration.java    | 112 +++++++
 .../src/main/java/io/seata/config/Processor.java   |   4 +-
 .../config/CachedConfigurationChangeListener.java  |   3 +
 .../apache/seata/config/ConfigurationFactory.java  | 192 ++++++++++--
 .../io/seata/config/nacos/NacosConfiguration.java  | 346 +++++++++++++++++++++
 .../config/nacos/NacosConfigurationProvider.java}  |  14 +-
 .../io/seata/config/nacos/TestConfigCustomSPI.java |  70 +++++
 .../services/io.seata.config.ConfigurationProvider |   1 +
 .../src/test/resources/registry-test.conf          | 125 ++++++++
 .../seata/core/constants/DubboConstants.java       |   4 +-
 22 files changed, 1674 insertions(+), 99 deletions(-)

diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 3951d0eeed..9803bcd060 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -118,13 +118,12 @@ Add changes here for all PR submitted to the 2.x branch.
   retry mechanism
 - [[#6387](https://github.com/apache/incubator-seata/pull/6387)] optimize tcc use compatible
 - [[#6402](https://github.com/apache/incubator-seata/pull/6402)] optimize rm-datasource use compatible
+- [[#6403](https://github.com/apache/incubator-seata/pull/6403)] optimize config compatible module
 - [[#6419](https://github.com/apache/incubator-seata/pull/6419)] optimize integration-tx-api compatible
 - [[#6427](https://github.com/apache/incubator-seata/pull/6427)] support spi、saga、spring module compatible
 - [[#6442](https://github.com/apache/incubator-seata/pull/6442)] clarify if conditions
 - [[#6487](https://github.com/apache/incubator-seata/pull/6487)] fix typo and package name
-
-### refactor:
-- [[#6269](https://github.com/apache/incubator-seata/pull/6269)] standardize Seata Exception
+- [[#6442](https://github.com/apache/incubator-seata/pull/6442)] clarify if conditions
 - [[#6405](https://github.com/apache/incubator-seata/pull/6405)] fix kotlin compile failure
 - [[#6412](https://github.com/apache/incubator-seata/pull/6412)] optimize core compatible module
 - [[#6429](https://github.com/apache/incubator-seata/pull/6429)] remove repetitive words
@@ -153,7 +152,6 @@ Add changes here for all PR submitted to the 2.x branch.
 - [[#6484](https://github.com/apache/incubator-seata/pull/6484)] fix FileConfigurationTest and MockServerTest fail
 
 ### refactor:
-
 - [[#6280](https://github.com/apache/incubator-seata/pull/6280)] refactor Saga designer using diagram-js
 - [[#6269](https://github.com/apache/incubator-seata/pull/6269)] standardize Seata Exception
 - [[#6420](https://github.com/apache/incubator-seata/pull/6420)] refactor Configuration Cache
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index 14fad2b72c..be31a7043d 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -117,6 +117,7 @@
 - [[#6391](https://github.com/apache/incubator-seata/pull/6091)] 禁止重复注册TCC资源
 - [[#6393](https://github.com/apache/incubator-seata/pull/6393)] 元数据同步前判断版本,并增加重试功能
 - [[#6387](https://github.com/apache/incubator-seata/pull/6387)] 优化tcc使用兼容
+- [[#6403](https://github.com/apache/incubator-seata/pull/6403)] 优化 Config 兼容模块
 - [[#6402](https://github.com/apache/incubator-seata/pull/6402)] 优化rm-datasource向下兼容
 - [[#6419](https://github.com/apache/incubator-seata/pull/6419)] 优化integration-tx-api向下兼容
 - [[#6427](https://github.com/apache/incubator-seata/pull/6427)] 支持spi、saga、spring模块的向下兼容
@@ -129,6 +130,7 @@
 - [[#6412](https://github.com/apache/incubator-seata/pull/6412)] 优化 core 兼容模块
 - [[#6429](https://github.com/apache/incubator-seata/pull/6429)] 移除重复注释
 
+
 ### security:
 - [[#6069](https://github.com/apache/incubator-seata/pull/6069)] 升级Guava依赖版本,修复安全漏洞
 - [[#6144](https://github.com/apache/incubator-seata/pull/6144)] 升级Nacos依赖版本至1.4.6
@@ -151,10 +153,10 @@
 - [[#6484](https://github.com/apache/incubator-seata/pull/6484)] 修复FileConfigurationTest和MockServerTest失败
 
 ### refactor:
-
 - [[#6280](https://github.com/apache/incubator-seata/pull/6280)] 使用diagram-js重构Saga设计器
 - [[#6269](https://github.com/apache/incubator-seata/pull/6269)] 统一Seata异常规范
 - [[#6420](https://github.com/apache/incubator-seata/pull/6420)] 优化配置缓存
+- [[#6269](https://github.com/apache/incubator-seata/pull/6269)] 统一Seata异常规范
 
 非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。
 
diff --git a/common/src/main/java/org/apache/seata/common/loader/EnhancedServiceLoader.java b/common/src/main/java/org/apache/seata/common/loader/EnhancedServiceLoader.java
index f2e0405f33..266e6e7c17 100644
--- a/common/src/main/java/org/apache/seata/common/loader/EnhancedServiceLoader.java
+++ b/common/src/main/java/org/apache/seata/common/loader/EnhancedServiceLoader.java
@@ -16,14 +16,6 @@
  */
 package org.apache.seata.common.loader;
 
-import org.apache.commons.lang.exception.ExceptionUtils;
-import org.apache.seata.common.Constants;
-import org.apache.seata.common.executor.Initialize;
-import org.apache.seata.common.util.CollectionUtils;
-import org.apache.seata.common.util.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -38,6 +30,14 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.stream.Collectors;
 
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.seata.common.Constants;
+import org.apache.seata.common.executor.Initialize;
+import org.apache.seata.common.util.CollectionUtils;
+import org.apache.seata.common.util.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * The type Enhanced service loader.
  */
@@ -60,7 +60,7 @@ public class EnhancedServiceLoader {
      * @throws EnhancedServiceNotFoundException the enhanced service not found exception
      */
     public static <S> S load(Class<S> service, ClassLoader loader) throws EnhancedServiceNotFoundException {
-        return InnerEnhancedServiceLoader.getServiceLoader(service).load(loader);
+        return InnerEnhancedServiceLoader.getServiceLoader(service).load(loader, true);
     }
 
     /**
@@ -72,7 +72,20 @@ public class EnhancedServiceLoader {
      * @throws EnhancedServiceNotFoundException the enhanced service not found exception
      */
     public static <S> S load(Class<S> service) throws EnhancedServiceNotFoundException {
-        return InnerEnhancedServiceLoader.getServiceLoader(service).load(findClassLoader());
+        return load(service, true);
+    }
+
+    /**
+     * Load s.
+     *
+     * @param <S>               the type parameter
+     * @param service           the service
+     * @param includeCompatible the include compatible
+     * @return the s
+     * @throws EnhancedServiceNotFoundException the enhanced service not found exception
+     */
+    public static <S> S load(Class<S> service, boolean includeCompatible) throws EnhancedServiceNotFoundException {
+        return InnerEnhancedServiceLoader.getServiceLoader(service).load(findClassLoader(), includeCompatible);
     }
 
     /**
@@ -85,7 +98,22 @@ public class EnhancedServiceLoader {
      * @throws EnhancedServiceNotFoundException the enhanced service not found exception
      */
     public static <S> S load(Class<S> service, String activateName) throws EnhancedServiceNotFoundException {
-        return InnerEnhancedServiceLoader.getServiceLoader(service).load(activateName, findClassLoader());
+        return load(service, activateName, true);
+    }
+
+    /**
+     * Load s.
+     *
+     * @param <S>               the type parameter
+     * @param service           the service
+     * @param activateName      the activate name
+     * @param includeCompatible the include compatible
+     * @return the s
+     * @throws EnhancedServiceNotFoundException the enhanced service not found exception
+     */
+    public static <S> S load(Class<S> service, String activateName, boolean includeCompatible)
+        throws EnhancedServiceNotFoundException {
+        return InnerEnhancedServiceLoader.getServiceLoader(service).load(activateName, findClassLoader(), includeCompatible);
     }
 
     /**
@@ -100,7 +128,7 @@ public class EnhancedServiceLoader {
      */
     public static <S> S load(Class<S> service, String activateName, ClassLoader loader)
             throws EnhancedServiceNotFoundException {
-        return InnerEnhancedServiceLoader.getServiceLoader(service).load(activateName, loader);
+        return InnerEnhancedServiceLoader.getServiceLoader(service).load(activateName, loader, true);
     }
 
     /**
@@ -115,7 +143,7 @@ public class EnhancedServiceLoader {
      */
     public static <S> S load(Class<S> service, String activateName, Object[] args)
             throws EnhancedServiceNotFoundException {
-        return InnerEnhancedServiceLoader.getServiceLoader(service).load(activateName, args, findClassLoader());
+        return InnerEnhancedServiceLoader.getServiceLoader(service).load(activateName, args, findClassLoader(), true);
     }
 
     /**
@@ -131,7 +159,7 @@ public class EnhancedServiceLoader {
      */
     public static <S> S load(Class<S> service, String activateName, Class<?>[] argsType, Object[] args)
             throws EnhancedServiceNotFoundException {
-        return InnerEnhancedServiceLoader.getServiceLoader(service).load(activateName, argsType, args, findClassLoader());
+        return InnerEnhancedServiceLoader.getServiceLoader(service).load(activateName, argsType, args, findClassLoader(), true);
     }
 
     /**
@@ -139,7 +167,7 @@ public class EnhancedServiceLoader {
      *
      * @param <S>     the type parameter
      * @param service the service
-     * @return list list
+     * @return list service
      */
     public static <S> List<S> loadAll(Class<S> service) {
         return InnerEnhancedServiceLoader.getServiceLoader(service).loadAll(findClassLoader());
@@ -155,7 +183,7 @@ public class EnhancedServiceLoader {
      * @return list list
      */
     public static <S> List<S> loadAll(Class<S> service, Class<?>[] argsType, Object[] args) {
-        return InnerEnhancedServiceLoader.getServiceLoader(service).loadAll(argsType, args, findClassLoader());
+        return InnerEnhancedServiceLoader.getServiceLoader(service).loadAll(argsType, args, findClassLoader(), true);
     }
 
     /**
@@ -204,7 +232,7 @@ public class EnhancedServiceLoader {
                 classToDefinitionMap.remove(entry.getKey());
             }
         }
-        serviceLoader.nameToDefinitionsMap.remove(activateName);
+        serviceLoader.nameToDefinitionsMap.remove(activateName.toLowerCase());
         if (CollectionUtils.isNotEmpty(extensionDefinitions)) {
             for (ExtensionDefinition<S> definition : extensionDefinitions) {
                 serviceLoader.definitionToInstanceMap.remove(definition);
@@ -222,7 +250,7 @@ public class EnhancedServiceLoader {
      * @return all extension class
      */
     static <S> List<Class<S>> getAllExtensionClass(Class<S> service) {
-        return InnerEnhancedServiceLoader.getServiceLoader(service).getAllExtensionClass(findClassLoader());
+        return InnerEnhancedServiceLoader.getServiceLoader(service).getAllExtensionClass(findClassLoader(), true);
     }
 
     /**
@@ -234,13 +262,13 @@ public class EnhancedServiceLoader {
      * @return all extension class
      */
     static <S> List<Class<S>> getAllExtensionClass(Class<S> service, ClassLoader loader) {
-        return InnerEnhancedServiceLoader.getServiceLoader(service).getAllExtensionClass(loader);
+        return InnerEnhancedServiceLoader.getServiceLoader(service).getAllExtensionClass(loader, true);
     }
 
     /**
      * Cannot use TCCL, in the pandora container will cause the class in the plugin not to be loaded
      *
-     * @return
+     * @return ClassLoader
      */
     private static ClassLoader findClassLoader() {
         return EnhancedServiceLoader.class.getClassLoader();
@@ -302,8 +330,8 @@ public class EnhancedServiceLoader {
          * @return s s
          * @throws EnhancedServiceNotFoundException the enhanced service not found exception
          */
-        private S load(ClassLoader loader) throws EnhancedServiceNotFoundException {
-            return loadExtension(loader, null, null);
+        private S load(ClassLoader loader, boolean includeCompatible) throws EnhancedServiceNotFoundException {
+            return loadExtension(loader, null, null, includeCompatible);
         }
 
         /**
@@ -314,9 +342,9 @@ public class EnhancedServiceLoader {
          * @return s s
          * @throws EnhancedServiceNotFoundException the enhanced service not found exception
          */
-        private S load(String activateName, ClassLoader loader)
+        private S load(String activateName, ClassLoader loader, boolean includeCompatible)
                 throws EnhancedServiceNotFoundException {
-            return loadExtension(activateName, loader, null, null);
+            return loadExtension(activateName, loader, null, null, includeCompatible);
         }
 
         /**
@@ -328,7 +356,7 @@ public class EnhancedServiceLoader {
          * @return the s
          * @throws EnhancedServiceNotFoundException the enhanced service not found exception
          */
-        private S load(String activateName, Object[] args, ClassLoader loader)
+        private S load(String activateName, Object[] args, ClassLoader loader, boolean includeCompatible)
                 throws EnhancedServiceNotFoundException {
             Class<?>[] argsType = null;
             if (args != null && args.length > 0) {
@@ -337,7 +365,7 @@ public class EnhancedServiceLoader {
                     argsType[i] = args[i].getClass();
                 }
             }
-            return loadExtension(activateName, loader, argsType, args);
+            return loadExtension(activateName, loader, argsType, args, includeCompatible);
         }
 
         /**
@@ -350,9 +378,9 @@ public class EnhancedServiceLoader {
          * @return the s
          * @throws EnhancedServiceNotFoundException the enhanced service not found exception
          */
-        private S load(String activateName, Class<?>[] argsType, Object[] args, ClassLoader loader)
+        private S load(String activateName, Class<?>[] argsType, Object[] args, ClassLoader loader, boolean includeCompatible)
                 throws EnhancedServiceNotFoundException {
-            return loadExtension(activateName, loader, argsType, args);
+            return loadExtension(activateName, loader, argsType, args, includeCompatible);
         }
 
         /**
@@ -362,7 +390,7 @@ public class EnhancedServiceLoader {
          * @return list list
          */
         private List<S> loadAll(ClassLoader loader) {
-            return loadAll(null, null, loader);
+            return loadAll(null, null, loader, true);
         }
 
         /**
@@ -372,9 +400,9 @@ public class EnhancedServiceLoader {
          * @param args     the args
          * @return list list
          */
-        private List<S> loadAll(Class<?>[] argsType, Object[] args, ClassLoader loader) {
+        private List<S> loadAll(Class<?>[] argsType, Object[] args, ClassLoader loader, boolean includeCompatible) {
             List<S> allInstances = new ArrayList<>();
-            List<Class<S>> allClazzs = getAllExtensionClass(loader);
+            List<Class<S>> allClazzs = getAllExtensionClass(loader, includeCompatible);
             if (CollectionUtils.isEmpty(allClazzs)) {
                 return allInstances;
             }
@@ -395,13 +423,13 @@ public class EnhancedServiceLoader {
          * @param loader the loader
          * @return all extension class
          */
-        private List<Class<S>> getAllExtensionClass(ClassLoader loader) {
-            return loadAllExtensionClass(loader);
+        private List<Class<S>> getAllExtensionClass(ClassLoader loader, boolean includeCompatible) {
+            return loadAllExtensionClass(loader, includeCompatible);
         }
 
-        private S loadExtension(ClassLoader loader, Class<?>[] argTypes, Object[] args) {
+        private S loadExtension(ClassLoader loader, Class<?>[] argTypes, Object[] args, boolean includeCompatible) {
             try {
-                loadAllExtensionClass(loader);
+                loadAllExtensionClass(loader, includeCompatible);
                 ExtensionDefinition<S> defaultExtensionDefinition = getDefaultExtensionDefinition();
                 return getExtensionInstance(defaultExtensionDefinition, loader, argTypes, args);
             } catch (EnhancedServiceNotFoundException e) {
@@ -415,12 +443,12 @@ public class EnhancedServiceLoader {
 
         @SuppressWarnings("rawtypes")
         private S loadExtension(String activateName, ClassLoader loader, Class[] argTypes,
-                                Object[] args) {
+                                Object[] args, boolean includeCompatible) {
             if (StringUtils.isEmpty(activateName)) {
                 throw new IllegalArgumentException("the name of service provider for [" + type.getName() + "] name is null");
             }
             try {
-                loadAllExtensionClass(loader);
+                loadAllExtensionClass(loader, includeCompatible);
                 ExtensionDefinition<S> cachedExtensionDefinition = getCachedExtensionDefinition(activateName);
                 return getExtensionInstance(cachedExtensionDefinition, loader, argTypes, args);
             } catch (Throwable e) {
@@ -468,13 +496,13 @@ public class EnhancedServiceLoader {
             }
         }
 
-        private List<Class<S>> loadAllExtensionClass(ClassLoader loader) {
+        private List<Class<S>> loadAllExtensionClass(ClassLoader loader, boolean includeCompatible) {
             List<ExtensionDefinition<S>> definitions = definitionsHolder.get();
             if (definitions == null) {
                 synchronized (definitionsHolder) {
                     definitions = definitionsHolder.get();
                     if (definitions == null) {
-                        definitions = findAllExtensionDefinition(loader);
+                        definitions = findAllExtensionDefinition(loader, includeCompatible);
                         definitionsHolder.set(definitions);
                     }
                 }
@@ -482,20 +510,23 @@ public class EnhancedServiceLoader {
             return definitions.stream().map(ExtensionDefinition::getServiceClass).collect(Collectors.toList());
         }
 
-        private List<ExtensionDefinition<S>> findAllExtensionDefinition(ClassLoader loader) {
+        private List<ExtensionDefinition<S>> findAllExtensionDefinition(ClassLoader loader, boolean includeCompatible) {
             List<ExtensionDefinition<S>> extensionDefinitions = new ArrayList<>();
             try {
                 loadFile(SERVICES_DIRECTORY, type, loader, extensionDefinitions);
                 loadFile(SEATA_DIRECTORY, type, loader, extensionDefinitions);
 
-                @SuppressWarnings("rawtypes") Class compatibleService = getCompatibleService(type);
-                if (compatibleService != null) {
-                    if (type.isAssignableFrom(compatibleService)) {
-                        LOGGER.info("Load compatible class {}", compatibleService.getName());
-                        loadFile(SERVICES_DIRECTORY, compatibleService, loader, extensionDefinitions);
-                        loadFile(SEATA_DIRECTORY, compatibleService, loader, extensionDefinitions);
-                    } else {
-                        LOGGER.info("Ignore load compatible class {}, because is not assignable from origin type {}", compatibleService.getName(), type.getName());
+                if (includeCompatible) {
+                    @SuppressWarnings("rawtypes")
+                    Class compatibleService = getCompatibleService(type);
+                    if (compatibleService != null) {
+                        if (type.isAssignableFrom(compatibleService)) {
+                            LOGGER.info("Load compatible class {}", compatibleService.getName());
+                            loadFile(SERVICES_DIRECTORY, compatibleService, loader, extensionDefinitions);
+                            loadFile(SEATA_DIRECTORY, compatibleService, loader, extensionDefinitions);
+                        } else {
+                            LOGGER.info("Ignore load compatible class {}, because is not assignable from origin type {}", compatibleService.getName(), type.getName());
+                        }
                     }
                 }
 
@@ -619,7 +650,7 @@ public class EnhancedServiceLoader {
                 ExtensionDefinition<S> result = new ExtensionDefinition<>(serviceName, priority, scope, enhancedServiceClass);
                 classToDefinitionMap.put(clazz, result);
                 if (serviceName != null) {
-                    CollectionUtils.computeIfAbsent(nameToDefinitionsMap, serviceName, e -> new ArrayList<>())
+                    CollectionUtils.computeIfAbsent(nameToDefinitionsMap, serviceName.toLowerCase(), e -> new ArrayList<>())
                             .add(result);
                 }
                 return result;
@@ -645,7 +676,7 @@ public class EnhancedServiceLoader {
         }
 
         private ExtensionDefinition<S> getCachedExtensionDefinition(String activateName) {
-            List<ExtensionDefinition<S>> definitions = nameToDefinitionsMap.get(activateName);
+            List<ExtensionDefinition<S>> definitions = nameToDefinitionsMap.get(activateName.toLowerCase());
             return CollectionUtils.getLast(definitions);
         }
 
diff --git a/compatible/src/main/java/io/seata/common/util/StringUtils.java b/compatible/src/main/java/io/seata/common/util/StringUtils.java
index bf942b36ee..7cbba83a7a 100644
--- a/compatible/src/main/java/io/seata/common/util/StringUtils.java
+++ b/compatible/src/main/java/io/seata/common/util/StringUtils.java
@@ -24,6 +24,9 @@ import java.util.Iterator;
  * The type String utils.
  *
  * Compatible for dubbo dubbo-filter-seata
+ * Notes:
+ * https://github.com/apache/dubbo-spi-extensions/blob/master/dubbo-filter-extensions/dubbo-filter-seata/src/main
+ * /java/org/apache/dubbo/seata/SeataTransactionPropagationProviderFilter.java
  */
 public class StringUtils {
     /**
diff --git a/compatible/src/main/java/io/seata/core/context/RootContext.java b/compatible/src/main/java/io/seata/core/context/RootContext.java
index 77dd24572c..72a33daad3 100644
--- a/compatible/src/main/java/io/seata/core/context/RootContext.java
+++ b/compatible/src/main/java/io/seata/core/context/RootContext.java
@@ -28,6 +28,18 @@ import io.seata.core.model.BranchType;
  */
 public class RootContext {
 
+    /**
+     * The constant KEY_XID.
+     * used for apache dubbo
+     */
+    public static final String KEY_XID = "TX_XID";
+
+    /**
+     * The constant KEY_BRANCH_TYPE
+     * * used for apache dubbo
+     */
+    public static final String KEY_BRANCH_TYPE = "TX_BRANCH_TYPE";
+
     private static BranchType convertIoSeata(org.apache.seata.core.model.BranchType branchType) {
         return BranchType.get(branchType.name());
     }
diff --git a/config/seata-config-core/src/main/java/io/seata/config/AbstractConfiguration.java b/config/seata-config-core/src/main/java/io/seata/config/AbstractConfiguration.java
new file mode 100644
index 0000000000..cac6702320
--- /dev/null
+++ b/config/seata-config-core/src/main/java/io/seata/config/AbstractConfiguration.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.seata.config;
+
+import java.time.Duration;
+
+import org.apache.seata.common.util.DurationUtil;
+import org.apache.seata.common.util.StringUtils;
+
+public abstract class AbstractConfiguration implements Configuration {
+    /**
+     * The constant DEFAULT_CONFIG_TIMEOUT.
+     */
+    protected static final long DEFAULT_CONFIG_TIMEOUT = 5 * 1000;
+
+    /**
+     * The constant DEFAULT_XXX.
+     */
+    public static final short DEFAULT_SHORT = (short)0;
+    public static final int DEFAULT_INT = 0;
+    public static final long DEFAULT_LONG = 0L;
+    public static final Duration DEFAULT_DURATION = Duration.ZERO;
+    public static final boolean DEFAULT_BOOLEAN = false;
+
+    @Override
+    public short getShort(String dataId, short defaultValue, long timeoutMills) {
+        String result = getConfig(dataId, timeoutMills);
+        return StringUtils.isBlank(result) ? defaultValue : Short.parseShort(result);
+    }
+
+    @Override
+    public short getShort(String dataId, short defaultValue) {
+        return getShort(dataId, defaultValue, DEFAULT_CONFIG_TIMEOUT);
+    }
+
+    @Override
+    public short getShort(String dataId) {
+        return getShort(dataId, DEFAULT_SHORT);
+    }
+
+    @Override
+    public int getInt(String dataId, int defaultValue, long timeoutMills) {
+        String result = getConfig(dataId, timeoutMills);
+        return StringUtils.isBlank(result) ? defaultValue : Integer.parseInt(result);
+    }
+
+    @Override
+    public int getInt(String dataId, int defaultValue) {
+        return getInt(dataId, defaultValue, DEFAULT_CONFIG_TIMEOUT);
+    }
+
+    @Override
+    public int getInt(String dataId) {
+        return getInt(dataId, DEFAULT_INT);
+    }
+
+    @Override
+    public long getLong(String dataId, long defaultValue, long timeoutMills) {
+        String result = getConfig(dataId, timeoutMills);
+        return StringUtils.isBlank(result) ? defaultValue : Long.parseLong(result);
+    }
+
+    @Override
+    public long getLong(String dataId, long defaultValue) {
+        return getLong(dataId, defaultValue, DEFAULT_CONFIG_TIMEOUT);
+    }
+
+    @Override
+    public long getLong(String dataId) {
+        return getLong(dataId, DEFAULT_LONG);
+    }
+
+    @Override
+    public Duration getDuration(String dataId) {
+        return getDuration(dataId, DEFAULT_DURATION);
+    }
+
+    @Override
+    public Duration getDuration(String dataId, Duration defaultValue) {
+        return getDuration(dataId, defaultValue, DEFAULT_CONFIG_TIMEOUT);
+    }
+
+    @Override
+    public Duration getDuration(String dataId, Duration defaultValue, long timeoutMills) {
+        String result = getConfig(dataId, timeoutMills);
+        return StringUtils.isBlank(result) ? defaultValue : DurationUtil.parse(result);
+    }
+
+    @Override
+    public boolean getBoolean(String dataId, boolean defaultValue, long timeoutMills) {
+        String result = getConfig(dataId, timeoutMills);
+        return StringUtils.isBlank(result) ? defaultValue : Boolean.parseBoolean(result);
+    }
+
+    @Override
+    public boolean getBoolean(String dataId, boolean defaultValue) {
+        return getBoolean(dataId, defaultValue, DEFAULT_CONFIG_TIMEOUT);
+    }
+
+    @Override
+    public boolean getBoolean(String dataId) {
+        return getBoolean(dataId, DEFAULT_BOOLEAN);
+    }
+
+    @Override
+    public String getConfig(String dataId, String defaultValue) {
+        return getConfig(dataId, defaultValue, DEFAULT_CONFIG_TIMEOUT);
+    }
+
+    @Override
+    public String getConfig(String dataId, long timeoutMills) {
+        return getConfig(dataId, null, timeoutMills);
+    }
+
+    @Override
+    public String getConfig(String dataId, String content, long timeoutMills) {
+        String value = getConfigFromSys(dataId);
+        if (value != null) {
+            return value;
+        }
+        return getLatestConfig(dataId, content, timeoutMills);
+    }
+
+    @Override
+    public String getConfig(String dataId) {
+        return getConfig(dataId, DEFAULT_CONFIG_TIMEOUT);
+    }
+
+    @Override
+    public boolean putConfig(String dataId, String content) {
+        return putConfig(dataId, content, DEFAULT_CONFIG_TIMEOUT);
+    }
+
+    @Override
+    public boolean putConfigIfAbsent(String dataId, String content) {
+        return putConfigIfAbsent(dataId, content, DEFAULT_CONFIG_TIMEOUT);
+    }
+
+    @Override
+    public boolean removeConfig(String dataId) {
+        return removeConfig(dataId, DEFAULT_CONFIG_TIMEOUT);
+    }
+
+    /**
+     * Gets type name.
+     *
+     * @return the type name
+     */
+    public abstract String getTypeName();
+}
diff --git a/config/seata-config-core/src/main/java/io/seata/config/Configuration.java b/config/seata-config-core/src/main/java/io/seata/config/Configuration.java
new file mode 100644
index 0000000000..e778350e22
--- /dev/null
+++ b/config/seata-config-core/src/main/java/io/seata/config/Configuration.java
@@ -0,0 +1,310 @@
+/*
+ * 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 io.seata.config;
+
+import java.time.Duration;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.seata.common.util.StringUtils;
+
+public interface Configuration {
+
+    Map<String, String> ENV_MAP = System.getenv();
+
+    /**
+     * Gets short.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @param timeoutMills the timeout mills
+     * @return the short
+     */
+    short getShort(String dataId, short defaultValue, long timeoutMills);
+
+    /**
+     * Gets short.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @return the int
+     */
+    short getShort(String dataId, short defaultValue);
+
+    /**
+     * Gets short.
+     *
+     * @param dataId the data id
+     * @return the int
+     */
+    short getShort(String dataId);
+
+    /**
+     * Gets int.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @param timeoutMills the timeout mills
+     * @return the int
+     */
+    int getInt(String dataId, int defaultValue, long timeoutMills);
+
+    /**
+     * Gets int.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @return the int
+     */
+    int getInt(String dataId, int defaultValue);
+
+    /**
+     * Gets int.
+     *
+     * @param dataId the data id
+     * @return the int
+     */
+    int getInt(String dataId);
+
+    /**
+     * Gets long.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @param timeoutMills the timeout mills
+     * @return the long
+     */
+    long getLong(String dataId, long defaultValue, long timeoutMills);
+
+    /**
+     * Gets long.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @return the long
+     */
+    long getLong(String dataId, long defaultValue);
+
+    /**
+     * Gets long.
+     *
+     * @param dataId the data id
+     * @return the long
+     */
+    long getLong(String dataId);
+
+    /**
+     * Gets duration.
+     *
+     * @param dataId the data id
+     * @return the duration
+     */
+    Duration getDuration(String dataId);
+
+    /**
+     * Gets duration.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @return the duration
+     */
+    Duration getDuration(String dataId, Duration defaultValue);
+
+    /**
+     * Gets duration.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @param timeoutMills the timeout mills
+     * @return the duration
+     */
+    Duration getDuration(String dataId, Duration defaultValue, long timeoutMills);
+
+    /**
+     * Gets boolean.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @param timeoutMills the timeout mills
+     * @return the boolean
+     */
+    boolean getBoolean(String dataId, boolean defaultValue, long timeoutMills);
+
+    /**
+     * Gets boolean.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @return the boolean
+     */
+    boolean getBoolean(String dataId, boolean defaultValue);
+
+    /**
+     * Gets boolean.
+     *
+     * @param dataId the data id
+     * @return the boolean
+     */
+    boolean getBoolean(String dataId);
+
+    /**
+     * Gets config.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @param timeoutMills the timeout mills
+     * @return the config
+     */
+    String getConfig(String dataId, String defaultValue, long timeoutMills);
+
+    /**
+     * Gets config.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @return the config
+     */
+    String getConfig(String dataId, String defaultValue);
+
+    /**
+     * Gets config.
+     *
+     * @param dataId       the data id
+     * @param timeoutMills the timeout mills
+     * @return the config
+     */
+    String getConfig(String dataId, long timeoutMills);
+
+    /**
+     * Gets config.
+     *
+     * @param dataId the data id
+     * @return the config
+     */
+    String getConfig(String dataId);
+
+    /**
+     * Put config boolean.
+     *
+     * @param dataId       the data id
+     * @param content      the content
+     * @param timeoutMills the timeout mills
+     * @return the boolean
+     */
+    boolean putConfig(String dataId, String content, long timeoutMills);
+
+    /**
+     * Get latest config.
+     *
+     * @param dataId       the data id
+     * @param defaultValue the default value
+     * @param timeoutMills the timeout mills
+     * @return the Latest config
+     */
+    String getLatestConfig(String dataId, String defaultValue, long timeoutMills);
+
+    /**
+     * Put config boolean.
+     *
+     * @param dataId  the data id
+     * @param content the content
+     * @return the boolean
+     */
+    boolean putConfig(String dataId, String content);
+
+    /**
+     * Put config if absent boolean.
+     *
+     * @param dataId       the data id
+     * @param content      the content
+     * @param timeoutMills the timeout mills
+     * @return the boolean
+     */
+    boolean putConfigIfAbsent(String dataId, String content, long timeoutMills);
+
+    /**
+     * Put config if absent boolean.
+     *
+     * @param dataId  the data id
+     * @param content the content
+     * @return the boolean
+     */
+    boolean putConfigIfAbsent(String dataId, String content);
+
+    /**
+     * Remove config boolean.
+     *
+     * @param dataId       the data id
+     * @param timeoutMills the timeout mills
+     * @return the boolean
+     */
+    boolean removeConfig(String dataId, long timeoutMills);
+
+    /**
+     * Remove config boolean.
+     *
+     * @param dataId the data id
+     * @return the boolean
+     */
+    boolean removeConfig(String dataId);
+
+    /**
+     * Add config listener.
+     *
+     * @param dataId   the data id
+     * @param listener the listener
+     */
+    void addConfigListener(String dataId, ConfigurationChangeListener listener);
+
+    /**
+     * Remove config listener.
+     *
+     * @param dataId   the data id
+     * @param listener the listener
+     */
+    void removeConfigListener(String dataId, ConfigurationChangeListener listener);
+
+    /**
+     * Gets config listeners.
+     *
+     * @param dataId the data id
+     * @return the config listeners
+     */
+    Set<ConfigurationChangeListener> getConfigListeners(String dataId);
+
+    /**
+     * Gets config from sys pro.
+     *
+     * @param dataId the data id
+     * @return the config from sys pro
+     */
+    default String getConfigFromSys(String dataId) {
+        if (StringUtils.isBlank(dataId)) {
+            return null;
+        }
+        String content = ENV_MAP.get(dataId);
+        if (null != content) {
+            return content;
+        }
+        String envDataId = dataId.toUpperCase().replace(".", "_");
+        content = ENV_MAP.get(envDataId);
+        if (null != content) {
+            return content;
+        }
+        return System.getProperty(dataId);
+    }
+}
diff --git a/config/seata-config-core/src/main/java/io/seata/config/ConfigurationChangeEvent.java b/config/seata-config-core/src/main/java/io/seata/config/ConfigurationChangeEvent.java
new file mode 100644
index 0000000000..9d4f2565e8
--- /dev/null
+++ b/config/seata-config-core/src/main/java/io/seata/config/ConfigurationChangeEvent.java
@@ -0,0 +1,138 @@
+/*
+ * 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 io.seata.config;
+
+public class ConfigurationChangeEvent {
+    private String dataId;
+    private String oldValue;
+    private String newValue;
+    private String namespace;
+    private ConfigurationChangeType changeType;
+    private static final String DEFAULT_NAMESPACE = "DEFAULT";
+
+    public ConfigurationChangeEvent() {
+
+    }
+
+    public ConfigurationChangeEvent(String dataId, String newValue) {
+        this(dataId, DEFAULT_NAMESPACE, null, newValue, ConfigurationChangeType.MODIFY);
+    }
+
+    public ConfigurationChangeEvent(String dataId, String namespace, String oldValue, String newValue,
+                                    ConfigurationChangeType type) {
+        this.dataId = dataId;
+        this.namespace = namespace;
+        this.oldValue = oldValue;
+        this.newValue = newValue;
+        this.changeType = type;
+    }
+
+    /**
+     * Gets data id.
+     *
+     * @return the data id
+     */
+    public String getDataId() {
+        return dataId;
+    }
+
+    /**
+     * Sets data id.
+     *
+     * @param dataId the data id
+     */
+    public ConfigurationChangeEvent setDataId(String dataId) {
+        this.dataId = dataId;
+        return this;
+    }
+
+    /**
+     * Gets old value.
+     *
+     * @return the old value
+     */
+    public String getOldValue() {
+        return oldValue;
+    }
+
+    /**
+     * Sets old value.
+     *
+     * @param oldValue the old value
+     */
+    public ConfigurationChangeEvent setOldValue(String oldValue) {
+        this.oldValue = oldValue;
+        return this;
+    }
+
+    /**
+     * Gets new value.
+     *
+     * @return the new value
+     */
+    public String getNewValue() {
+        return newValue;
+    }
+
+    /**
+     * Sets new value.
+     *
+     * @param newValue the new value
+     */
+    public ConfigurationChangeEvent setNewValue(String newValue) {
+        this.newValue = newValue;
+        return this;
+    }
+
+    /**
+     * Gets change type.
+     *
+     * @return the change type
+     */
+    public ConfigurationChangeType getChangeType() {
+        return changeType;
+    }
+
+    /**
+     * Sets change type.
+     *
+     * @param changeType the change type
+     */
+    public ConfigurationChangeEvent setChangeType(ConfigurationChangeType changeType) {
+        this.changeType = changeType;
+        return this;
+    }
+
+    /**
+     * Gets namespace.
+     *
+     * @return the namespace
+     */
+    public String getNamespace() {
+        return namespace;
+    }
+
+    /**
+     * Sets namespace.
+     *
+     * @param namespace the namespace
+     */
+    public ConfigurationChangeEvent setNamespace(String namespace) {
+        this.namespace = namespace;
+        return this;
+    }
+}
diff --git a/config/seata-config-core/src/main/java/io/seata/config/ConfigurationChangeListener.java b/config/seata-config-core/src/main/java/io/seata/config/ConfigurationChangeListener.java
new file mode 100644
index 0000000000..fda6086a2b
--- /dev/null
+++ b/config/seata-config-core/src/main/java/io/seata/config/ConfigurationChangeListener.java
@@ -0,0 +1,91 @@
+/*
+ * 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 io.seata.config;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.seata.common.thread.NamedThreadFactory;
+
+public interface ConfigurationChangeListener {
+    /**
+     * The constant CORE_LISTENER_THREAD.
+     */
+    int CORE_LISTENER_THREAD = 1;
+    /**
+     * The constant MAX_LISTENER_THREAD.
+     */
+    int MAX_LISTENER_THREAD = 1;
+    /**
+     * The constant EXECUTOR_SERVICE.
+     */
+    ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(CORE_LISTENER_THREAD, MAX_LISTENER_THREAD,
+        Integer.MAX_VALUE, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(),
+        new NamedThreadFactory("configListenerOperate", MAX_LISTENER_THREAD));
+
+    /**
+     * Process.
+     *
+     * @param event the event
+     */
+    void onChangeEvent(ConfigurationChangeEvent event);
+
+    /**
+     * On process event.
+     *
+     * @param event the event
+     */
+    default void onProcessEvent(ConfigurationChangeEvent event) {
+        getExecutorService().submit(() -> {
+            beforeEvent();
+            onChangeEvent(event);
+            afterEvent();
+        });
+    }
+
+    /**
+     * On shut down.
+     */
+    default void onShutDown() {
+        getExecutorService().shutdownNow();
+    }
+
+    /**
+     * Gets executor service.
+     *
+     * @return the executor service
+     */
+    default ExecutorService getExecutorService() {
+        return EXECUTOR_SERVICE;
+    }
+
+    /**
+     * Before event.
+     */
+    default void beforeEvent() {
+
+    }
+
+    /**
+     * After event.
+     */
+    default void afterEvent() {
+
+    }
+}
diff --git a/compatible/src/main/java/io/seata/config/ExtConfigurationProvider.java b/config/seata-config-core/src/main/java/io/seata/config/ConfigurationChangeType.java
similarity index 77%
copy from compatible/src/main/java/io/seata/config/ExtConfigurationProvider.java
copy to config/seata-config-core/src/main/java/io/seata/config/ConfigurationChangeType.java
index 800d444cd7..22b172e44a 100644
--- a/compatible/src/main/java/io/seata/config/ExtConfigurationProvider.java
+++ b/config/seata-config-core/src/main/java/io/seata/config/ConfigurationChangeType.java
@@ -16,11 +16,17 @@
  */
 package io.seata.config;
 
-
-/**
- * the interface ext configuration provider
- *
- * 
- */
-public interface ExtConfigurationProvider extends org.apache.seata.config.ExtConfigurationProvider {
+public enum ConfigurationChangeType {
+    /**
+     * Add configuration change type.
+     */
+    ADD,
+    /**
+     * Modify configuration change type.
+     */
+    MODIFY,
+    /**
+     * Delete configuration change type.
+     */
+    DELETE
 }
diff --git a/compatible/src/main/java/io/seata/config/ConfigurationProvider.java b/config/seata-config-core/src/main/java/io/seata/config/ConfigurationProvider.java
similarity index 79%
rename from compatible/src/main/java/io/seata/config/ConfigurationProvider.java
rename to config/seata-config-core/src/main/java/io/seata/config/ConfigurationProvider.java
index 4767721b02..c9e8ecf921 100644
--- a/compatible/src/main/java/io/seata/config/ConfigurationProvider.java
+++ b/config/seata-config-core/src/main/java/io/seata/config/ConfigurationProvider.java
@@ -18,7 +18,13 @@ package io.seata.config;
 
 /**
  * the interface configuration provider
- * 
+ * Notes: used for io.seata SPI interface
  */
-public interface ConfigurationProvider extends org.apache.seata.config.ConfigurationProvider {
+public interface ConfigurationProvider {
+    /**
+     * provide a AbstractConfiguration implementation instance
+     *
+     * @return Configuration
+     */
+    Configuration provide();
 }
diff --git a/compatible/src/main/java/io/seata/config/ExtConfigurationProvider.java b/config/seata-config-core/src/main/java/io/seata/config/ExtConfigurationProvider.java
similarity index 74%
rename from compatible/src/main/java/io/seata/config/ExtConfigurationProvider.java
rename to config/seata-config-core/src/main/java/io/seata/config/ExtConfigurationProvider.java
index 800d444cd7..051c2335f7 100644
--- a/compatible/src/main/java/io/seata/config/ExtConfigurationProvider.java
+++ b/config/seata-config-core/src/main/java/io/seata/config/ExtConfigurationProvider.java
@@ -16,11 +16,16 @@
  */
 package io.seata.config;
 
-
 /**
  * the interface ext configuration provider
- *
- * 
+ * Notes: used for io.seata SPI interface
  */
-public interface ExtConfigurationProvider extends org.apache.seata.config.ExtConfigurationProvider {
+public interface ExtConfigurationProvider {
+    /**
+     * provide a AbstractConfiguration implementation instance
+     *
+     * @param originalConfiguration
+     * @return configuration
+     */
+    Configuration provide(Configuration originalConfiguration);
 }
diff --git a/config/seata-config-core/src/main/java/io/seata/config/FileConfiguration.java b/config/seata-config-core/src/main/java/io/seata/config/FileConfiguration.java
new file mode 100644
index 0000000000..af2fb24512
--- /dev/null
+++ b/config/seata-config-core/src/main/java/io/seata/config/FileConfiguration.java
@@ -0,0 +1,112 @@
+/*
+ * 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 io.seata.config;
+
+import java.util.Set;
+
+import org.apache.seata.common.exception.NotSupportYetException;
+
+/**
+ * The type File configuration.
+ *
+ * Notes: used for Apache ShardingSphere and ConfigurationFactory
+ * 1.
+ * https://github.com/apache/shardingsphere/blob/master/kernel/transaction/type/base/seata-at/src/main/java/org
+ * /apache/shardingsphere/transaction/base/seata/at/SeataATShardingSphereTransactionManager.java
+ * 2.EnhancedServiceLoader.load(ExtConfigurationProvider.class).provide(configuration)
+ */
+public class FileConfiguration extends AbstractConfiguration {
+
+    private final org.apache.seata.config.FileConfiguration target;
+
+    /**
+     * Instantiates a new File configuration.
+     */
+    public FileConfiguration() {
+        target = new org.apache.seata.config.FileConfiguration();
+    }
+
+    /**
+     * Instantiates a new File configuration.
+     *
+     * @param target the target
+     */
+    public FileConfiguration(org.apache.seata.config.Configuration target) {
+        this.target = (org.apache.seata.config.FileConfiguration)target;
+    }
+
+    /**
+     * Instantiates a new File configuration.
+     *
+     * @param name the name
+     */
+    public FileConfiguration(String name) {
+        this(name, true);
+    }
+
+    /**
+     * Instantiates a new File configuration.
+     * For seata-server side the conf file should always exists.
+     * For application(or client) side,conf file may not exists when using seata-spring-boot-starter
+     *
+     * @param name                the name
+     * @param allowDynamicRefresh the allow dynamic refresh
+     */
+    public FileConfiguration(String name, boolean allowDynamicRefresh) {
+        target = new org.apache.seata.config.FileConfiguration(name, allowDynamicRefresh);
+    }
+
+    @Override
+    public String getTypeName() {
+        return target.getTypeName();
+    }
+
+    @Override
+    public boolean putConfig(String dataId, String content, long timeoutMills) {
+        return target.putConfig(dataId, content, timeoutMills);
+    }
+
+    @Override
+    public String getLatestConfig(String dataId, String defaultValue, long timeoutMills) {
+        return target.getLatestConfig(dataId, defaultValue, timeoutMills);
+    }
+
+    @Override
+    public boolean putConfigIfAbsent(String dataId, String content, long timeoutMills) {
+        return target.putConfigIfAbsent(dataId, content, timeoutMills);
+    }
+
+    @Override
+    public boolean removeConfig(String dataId, long timeoutMills) {
+        return target.removeConfig(dataId, timeoutMills);
+    }
+
+    @Override
+    public void addConfigListener(String dataId, ConfigurationChangeListener listener) {
+        throw new NotSupportYetException();
+    }
+
+    @Override
+    public void removeConfigListener(String dataId, ConfigurationChangeListener listener) {
+        throw new NotSupportYetException();
+    }
+
+    @Override
+    public Set<ConfigurationChangeListener> getConfigListeners(String dataId) {
+        return null;
+    }
+}
diff --git a/compatible/src/main/java/io/seata/config/Processor.java b/config/seata-config-core/src/main/java/io/seata/config/Processor.java
similarity index 95%
rename from compatible/src/main/java/io/seata/config/Processor.java
rename to config/seata-config-core/src/main/java/io/seata/config/Processor.java
index 1734d5dd11..ab8e5e3b30 100644
--- a/compatible/src/main/java/io/seata/config/Processor.java
+++ b/config/seata-config-core/src/main/java/io/seata/config/Processor.java
@@ -18,9 +18,7 @@ package io.seata.config;
 
 /**
  * The processing configuration.
- * 
- *
- *
+ * Notes: used for io.seata SPI interface
  */
 public interface Processor extends org.apache.seata.config.processor.Processor {
 }
diff --git a/config/seata-config-core/src/main/java/org/apache/seata/config/CachedConfigurationChangeListener.java b/config/seata-config-core/src/main/java/org/apache/seata/config/CachedConfigurationChangeListener.java
index 526bc4b53f..114cfe6ce8 100644
--- a/config/seata-config-core/src/main/java/org/apache/seata/config/CachedConfigurationChangeListener.java
+++ b/config/seata-config-core/src/main/java/org/apache/seata/config/CachedConfigurationChangeListener.java
@@ -22,6 +22,9 @@ public interface CachedConfigurationChangeListener extends ConfigurationChangeLi
 
     @Override
     default void beforeEvent(ConfigurationChangeEvent event) {
+        if (null == event) {
+            return;
+        }
         CONFIGURATION_CACHE.onProcessEvent(event);
     }
 
diff --git a/config/seata-config-core/src/main/java/org/apache/seata/config/ConfigurationFactory.java b/config/seata-config-core/src/main/java/org/apache/seata/config/ConfigurationFactory.java
index c86454e7a4..22d94903f6 100644
--- a/config/seata-config-core/src/main/java/org/apache/seata/config/ConfigurationFactory.java
+++ b/config/seata-config-core/src/main/java/org/apache/seata/config/ConfigurationFactory.java
@@ -16,12 +16,22 @@
  */
 package org.apache.seata.config;
 
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
 
 import org.apache.seata.common.exception.NotSupportYetException;
 import org.apache.seata.common.loader.EnhancedServiceLoader;
 import org.apache.seata.common.loader.EnhancedServiceNotFoundException;
+import org.apache.seata.common.util.CollectionUtils;
 import org.apache.seata.common.util.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -65,7 +75,7 @@ public final class ConfigurationFactory {
             }
         } catch (EnhancedServiceNotFoundException e) {
             if (LOGGER.isDebugEnabled()) {
-                LOGGER.warn("failed to load extConfiguration: {}", e.getMessage(), e);
+                LOGGER.debug("failed to load extConfiguration: {}", e.getMessage(), e);
             }
         } catch (Exception e) {
             LOGGER.error("failed to load extConfiguration: {}", e.getMessage(), e);
@@ -116,7 +126,7 @@ public final class ConfigurationFactory {
     }
 
     private static void maybeNeedOriginFileInstance() {
-        if (ConfigType.File == getConfigType()) {
+        if (ConfigType.File.name().equalsIgnoreCase(getConfigType())) {
             String pathDataId = String.join(ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR,
                     ConfigurationKeys.FILE_ROOT_CONFIG, FILE_TYPE, NAME_KEY);
             String name = CURRENT_FILE_INSTANCE.getConfig(pathDataId);
@@ -125,13 +135,18 @@ public final class ConfigurationFactory {
         }
     }
 
-    private static ConfigType getConfigType() {
+    /**
+     * Notes: should not rely on the ConfigType type, as it will prevent the extension of configuration types
+     * implemented externally.
+     * @return
+     */
+    private static String getConfigType() {
         String configTypeName = CURRENT_FILE_INSTANCE.getConfig(ConfigurationKeys.FILE_ROOT_CONFIG
             + ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR + ConfigurationKeys.FILE_ROOT_TYPE);
         if (StringUtils.isBlank(configTypeName)) {
             throw new NotSupportYetException("config type can not be null");
         }
-        return ConfigType.getType(configTypeName);
+        return configTypeName;
     }
 
     public static Optional<FileConfiguration> getOriginFileInstance() {
@@ -139,24 +154,14 @@ public final class ConfigurationFactory {
     }
 
     private static Configuration buildConfiguration() {
-        ConfigType configType = getConfigType();
-        Configuration extConfiguration = null;
+        String configTypeName = getConfigType();
         Configuration configuration = ORIGIN_FILE_INSTANCE;
-        if (configuration != null) {
-            try {
-                extConfiguration = EnhancedServiceLoader.load(ExtConfigurationProvider.class).provide(configuration);
-                if (LOGGER.isInfoEnabled()) {
-                    LOGGER.info("load Configuration from :{}",
-                        extConfiguration == null ? configuration.getClass().getSimpleName() : "Spring Configuration");
-                }
-            } catch (EnhancedServiceNotFoundException ignore) {
-
-            } catch (Exception e) {
-                LOGGER.error("failed to load extConfiguration:{}", e.getMessage(), e);
+        Configuration extConfiguration = getSpringConfiguration();
+        if (null == extConfiguration) {
+            Configuration springConfiguration = getNonSpringConfiguration(configTypeName);
+            if (null != springConfiguration) {
+                configuration = springConfiguration;
             }
-        } else {
-            configuration = EnhancedServiceLoader
-                    .load(ConfigurationProvider.class, Objects.requireNonNull(configType).name()).provide();
         }
         try {
             Configuration configurationCache;
@@ -176,6 +181,50 @@ public final class ConfigurationFactory {
         return null == extConfiguration ? configuration : extConfiguration;
     }
 
+    private static Configuration getSpringConfiguration() {
+        Configuration configuration = ORIGIN_FILE_INSTANCE;
+        if (null != configuration) {
+            try {
+                Configuration extConfiguration = EnhancedServiceLoader.load(ExtConfigurationProvider.class, false).provide(
+                    configuration);
+                if (null != extConfiguration) {
+                    return extConfiguration;
+                }
+            } catch (EnhancedServiceNotFoundException ignore) {
+                //ignore
+
+            } catch (Exception exx) {
+                LOGGER.error("failed to load spring configuration :{}", exx.getMessage(), exx);
+            }
+        }
+        return null;
+    }
+
+    private static Configuration getNonSpringConfiguration(String configTypeName) {
+        try {
+            io.seata.config.Configuration oldConfiguration = EnhancedServiceLoader.load(
+                io.seata.config.ConfigurationProvider.class, Objects.requireNonNull(configTypeName)).provide();
+            if (null != oldConfiguration) {
+                Configuration configurationSPIInstanceProxy = (Configuration)Proxy.newProxyInstance(
+                    ConfigurationFactory.class.getClassLoader(), new Class[] {Configuration.class},
+                    new OldConfigurationInvocationHandler(oldConfiguration));
+                return configurationSPIInstanceProxy;
+            }
+        } catch (EnhancedServiceNotFoundException ignore) {
+            //ignore
+        } catch (Exception exx) {
+            LOGGER.error("failed to load non-spring configuration :{}", exx.getMessage(), exx);
+        }
+        try {
+            Configuration configuration = EnhancedServiceLoader.load(ConfigurationProvider.class,
+                Objects.requireNonNull(configTypeName), false).provide();
+            return configuration;
+        }  catch (Exception exx) {
+            LOGGER.error("failed to load non-spring configuration :{}", exx.getMessage(), exx);
+        }
+        return null;
+    }
+
     protected static void reload() {
         ConfigurationCache.clear();
         initOriginConfiguraction();
@@ -184,4 +233,107 @@ public final class ConfigurationFactory {
         instance = null;
         getInstance();
     }
+
+    static class OldConfigurationInvocationHandler implements InvocationHandler {
+        private final io.seata.config.Configuration configuration;
+
+        private static final String[] SIMPLE_PARAMS_METHOD_NAMES = new String[] {"getShort", "getInt", "getLong", "getDuration", "getBoolean", "getConfig", "putConfig", "getLatestConfig", "putConfigIfAbsent", "removeConfig", "getConfigFromSys"};
+
+        private static final List<String> SIMPLE_METHOD_NAMES =
+            Arrays.stream(SIMPLE_PARAMS_METHOD_NAMES).collect(Collectors.toList());
+
+        public OldConfigurationInvocationHandler(io.seata.config.Configuration configuration) {
+            this.configuration = configuration;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            if (SIMPLE_METHOD_NAMES.contains(method.getName())) {
+                Class[] classes = new Class[args.length];
+                for (int i = 0; i < args.length; i++) {
+                    classes[i] = args[i].getClass();
+                }
+                Method oldMethod = this.configuration.getClass().getMethod(method.getName(), classes);
+                return oldMethod.invoke(configuration, args);
+            } else if ("addConfigListener".equals(method.getName()) || "removeConfigListener".equals(
+                method.getName())) {
+                if (args.length == 2) {
+                    if (args[1] instanceof ConfigurationChangeListener) {
+                        ConfigurationChangeListener listener = (ConfigurationChangeListener)args[1];
+                        OldConfigurationChangeListenerWrapper wrapper = new OldConfigurationChangeListenerWrapper(
+                            listener);
+                        Method oldMethod = this.configuration.getClass().getMethod(method.getName(),
+                            new Class[] {String.class, io.seata.config.ConfigurationChangeListener.class});
+                        return oldMethod.invoke(configuration, args[0], wrapper);
+                    }
+                }
+            } else if ("getConfigListeners".equals(method.getName())) {
+                Method oldMethod = this.configuration.getClass().getMethod(method.getName(),
+                    new Class[] {String.class});
+                Set<io.seata.config.ConfigurationChangeListener> listeners
+                    = (Set<io.seata.config.ConfigurationChangeListener>)oldMethod.invoke(configuration, args);
+                if (CollectionUtils.isEmpty(listeners)) {
+                    return null;
+                }
+                Set<ConfigurationChangeListener> newListeners = new HashSet<>();
+                for (io.seata.config.ConfigurationChangeListener listener : listeners) {
+                    if (listener instanceof OldConfigurationChangeListenerWrapper) {
+                        newListeners.add(((OldConfigurationChangeListenerWrapper)listener).getTargetListener());
+                    }
+                }
+                return newListeners;
+            }
+            throw new NotSupportYetException(String.format("not support method:%s", method.getName()));
+        }
+    }
+
+    static class OldConfigurationChangeListenerWrapper implements io.seata.config.ConfigurationChangeListener {
+        private final ConfigurationChangeListener listener;
+
+        public OldConfigurationChangeListenerWrapper(ConfigurationChangeListener listener) {
+            this.listener = listener;
+        }
+
+        private ConfigurationChangeEvent convert(io.seata.config.ConfigurationChangeEvent event) {
+            ConfigurationChangeEvent newEvent = new ConfigurationChangeEvent();
+            newEvent.setDataId(event.getDataId()).setOldValue(event.getOldValue()).setNewValue(event.getNewValue())
+                .setNamespace(event.getNamespace());
+            newEvent.setChangeType(ConfigurationChangeType.values()[event.getChangeType().ordinal()]);
+            return newEvent;
+        }
+
+        @Override
+        public void onChangeEvent(io.seata.config.ConfigurationChangeEvent event) {
+            listener.onChangeEvent(convert(event));
+        }
+
+        @Override
+        public void onProcessEvent(io.seata.config.ConfigurationChangeEvent event) {
+            listener.onProcessEvent(convert(event));
+        }
+
+        @Override
+        public void onShutDown() {
+            listener.onShutDown();
+        }
+
+        @Override
+        public ExecutorService getExecutorService() {
+            return listener.getExecutorService();
+        }
+
+        @Override
+        public void beforeEvent() {
+            listener.beforeEvent(null);
+        }
+
+        @Override
+        public void afterEvent() {
+            listener.afterEvent(null);
+        }
+
+        public ConfigurationChangeListener getTargetListener() {
+            return listener;
+        }
+    }
 }
diff --git a/config/seata-config-nacos/src/test/java/io/seata/config/nacos/NacosConfiguration.java b/config/seata-config-nacos/src/test/java/io/seata/config/nacos/NacosConfiguration.java
new file mode 100644
index 0000000000..e3c3116bd3
--- /dev/null
+++ b/config/seata-config-nacos/src/test/java/io/seata/config/nacos/NacosConfiguration.java
@@ -0,0 +1,346 @@
+/*
+ * 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 io.seata.config.nacos;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import com.alibaba.nacos.api.NacosFactory;
+import com.alibaba.nacos.api.config.ConfigService;
+import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
+import com.alibaba.nacos.api.exception.NacosException;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+import io.seata.config.ConfigurationChangeEvent;
+import io.seata.config.ConfigurationChangeListener;
+import org.apache.seata.common.exception.NotSupportYetException;
+import org.apache.seata.common.util.CollectionUtils;
+import org.apache.seata.common.util.StringUtils;
+import org.apache.seata.config.ConfigurationKeys;
+import org.apache.seata.config.processor.ConfigProcessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test for io.seata.config SPI impl
+ */
+public class NacosConfiguration extends io.seata.config.AbstractConfiguration {
+    private static volatile NacosConfiguration instance;
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(NacosConfiguration.class);
+    private static final String DEFAULT_GROUP = "SEATA_GROUP";
+    private static final String DEFAULT_DATA_ID = "seata.properties";
+    private static final String GROUP_KEY = "group";
+    private static final String PRO_SERVER_ADDR_KEY = "serverAddr";
+    private static final String NACOS_DATA_ID_KEY = "dataId";
+    private static final String CONFIG_TYPE = "test";
+    private static final String DEFAULT_NAMESPACE = "";
+    private static final String PRO_NAMESPACE_KEY = "namespace";
+    private static final String USER_NAME = "username";
+    private static final String PASSWORD = "password";
+    private static final String ACCESS_KEY = "accessKey";
+    private static final String SECRET_KEY = "secretKey";
+    private static final String RAM_ROLE_NAME_KEY = "ramRoleName";
+    private static final String USE_PARSE_RULE = "false";
+    private static final String CONTEXT_PATH = "contextPath";
+    private static final Config FILE_CONFIG = ConfigFactory.load("registry-test.conf");
+    private static volatile ConfigService configService;
+    private static final int MAP_INITIAL_CAPACITY = 8;
+    private static final ConcurrentMap<String, ConcurrentMap<ConfigurationChangeListener, NacosListener>>
+        CONFIG_LISTENERS_MAP = new ConcurrentHashMap<>(MAP_INITIAL_CAPACITY);
+    private static volatile Properties seataConfig = new Properties();
+
+    /**
+     * Get instance of NacosConfiguration
+     *
+     * @return instance
+     */
+    public static NacosConfiguration getInstance() {
+        if (instance == null) {
+            synchronized (NacosConfiguration.class) {
+                if (instance == null) {
+                    instance = new NacosConfiguration();
+                }
+            }
+        }
+        return instance;
+    }
+
+    /**
+     * Instantiates a new Nacos configuration.
+     */
+    private NacosConfiguration() {
+        if (configService == null) {
+            try {
+                configService = NacosFactory.createConfigService(getConfigProperties());
+            } catch (NacosException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    @Override
+    public String getLatestConfig(String dataId, String defaultValue, long timeoutMills) {
+        String value = seataConfig.getProperty(dataId);
+        if (null == value) {
+            try {
+                value = configService.getConfig(dataId, getNacosGroup(), timeoutMills);
+            } catch (NacosException exx) {
+                LOGGER.error(exx.getErrMsg());
+            }
+        }
+
+        return value == null ? defaultValue : value;
+    }
+
+    @Override
+    public boolean putConfig(String dataId, String content, long timeoutMills) {
+        boolean result = false;
+        try {
+            if (!seataConfig.isEmpty()) {
+                seataConfig.setProperty(dataId, content);
+                result = configService.publishConfig(getNacosDataId(), getNacosGroup(), getSeataConfigStr());
+            } else {
+                result = configService.publishConfig(dataId, getNacosGroup(), content);
+            }
+        } catch (NacosException exx) {
+            LOGGER.error(exx.getErrMsg());
+        }
+        return result;
+    }
+
+    @Override
+    public boolean putConfigIfAbsent(String dataId, String content, long timeoutMills) {
+        throw new NotSupportYetException("not support atomic operation putConfigIfAbsent");
+    }
+
+    @Override
+    public boolean removeConfig(String dataId, long timeoutMills) {
+        boolean result = false;
+        try {
+            if (!seataConfig.isEmpty()) {
+                seataConfig.remove(dataId);
+                result = configService.publishConfig(getNacosDataId(), getNacosGroup(), getSeataConfigStr());
+            } else {
+                result = configService.removeConfig(dataId, getNacosGroup());
+            }
+        } catch (NacosException exx) {
+            LOGGER.error(exx.getErrMsg());
+        }
+        return result;
+    }
+
+    @Override
+    public void addConfigListener(String dataId, ConfigurationChangeListener listener) {
+        if (StringUtils.isBlank(dataId) || listener == null) {
+            return;
+        }
+        try {
+            NacosListener nacosListener = new NacosListener(dataId, listener);
+            CONFIG_LISTENERS_MAP.computeIfAbsent(dataId, key -> new ConcurrentHashMap<>()).put(listener, nacosListener);
+            configService.addListener(dataId, getNacosGroup(), nacosListener);
+        } catch (Exception exx) {
+            LOGGER.error("add nacos listener error:{}", exx.getMessage(), exx);
+        }
+    }
+
+    @Override
+    public void removeConfigListener(String dataId, ConfigurationChangeListener listener) {
+        if (StringUtils.isBlank(dataId) || listener == null) {
+            return;
+        }
+        Set<ConfigurationChangeListener> configChangeListeners = getConfigListeners(dataId);
+        if (CollectionUtils.isNotEmpty(configChangeListeners)) {
+            for (ConfigurationChangeListener entry : configChangeListeners) {
+                if (listener.equals(entry)) {
+                    NacosListener nacosListener = null;
+                    Map<ConfigurationChangeListener, NacosListener> configListeners = CONFIG_LISTENERS_MAP.get(dataId);
+                    if (configListeners != null) {
+                        nacosListener = configListeners.get(listener);
+                        configListeners.remove(entry);
+                    }
+                    if (nacosListener != null) {
+                        configService.removeListener(dataId, getNacosGroup(), nacosListener);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    @Override
+    public Set<ConfigurationChangeListener> getConfigListeners(String dataId) {
+        Map<ConfigurationChangeListener, NacosListener> configListeners = CONFIG_LISTENERS_MAP.get(dataId);
+        if (CollectionUtils.isNotEmpty(configListeners)) {
+            return configListeners.keySet();
+        } else {
+            return null;
+        }
+    }
+
+    private static Properties getConfigProperties() {
+        Properties properties = new Properties();
+        properties.setProperty(ConfigurationKeys.IS_USE_CLOUD_NAMESPACE_PARSING, USE_PARSE_RULE);
+        properties.setProperty(ConfigurationKeys.IS_USE_ENDPOINT_PARSING_RULE, USE_PARSE_RULE);
+        if (System.getProperty(PRO_SERVER_ADDR_KEY) != null) {
+            properties.setProperty(PRO_SERVER_ADDR_KEY, System.getProperty(PRO_SERVER_ADDR_KEY));
+        } else {
+            String address = FILE_CONFIG.getString(getNacosAddrFileKey());
+            if (address != null) {
+                properties.setProperty(PRO_SERVER_ADDR_KEY, address);
+            }
+        }
+
+        if (System.getProperty(PRO_NAMESPACE_KEY) != null) {
+            properties.setProperty(PRO_NAMESPACE_KEY, System.getProperty(PRO_NAMESPACE_KEY));
+        } else {
+            String namespace = FILE_CONFIG.getString(getNacosNameSpaceFileKey());
+            if (namespace == null) {
+                namespace = DEFAULT_NAMESPACE;
+            }
+            properties.setProperty(PRO_NAMESPACE_KEY, namespace);
+        }
+        return properties;
+    }
+
+    public static String getNacosNameSpaceFileKey() {
+        return String.join(ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR, ConfigurationKeys.FILE_ROOT_CONFIG, CONFIG_TYPE,
+            PRO_NAMESPACE_KEY);
+    }
+
+    public static String getNacosAddrFileKey() {
+        return String.join(ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR, ConfigurationKeys.FILE_ROOT_CONFIG, CONFIG_TYPE,
+            PRO_SERVER_ADDR_KEY);
+    }
+
+    public static String getNacosGroupKey() {
+        return String.join(ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR, ConfigurationKeys.FILE_ROOT_CONFIG, CONFIG_TYPE,
+            GROUP_KEY);
+    }
+
+    public static String getNacosDataIdKey() {
+        return String.join(ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR, ConfigurationKeys.FILE_ROOT_CONFIG, CONFIG_TYPE,
+            NACOS_DATA_ID_KEY);
+    }
+
+
+    private static String getNacosGroup() {
+        return FILE_CONFIG.getString(getNacosGroupKey());
+    }
+
+    private static String getNacosDataId() {
+        return FILE_CONFIG.getString(getNacosDataIdKey());
+    }
+
+    private static String getNacosDataType() {
+        return ConfigProcessor.resolverConfigDataType(getNacosDataId());
+    }
+
+    private static String getSeataConfigStr() {
+        StringBuilder sb = new StringBuilder();
+
+        Enumeration<?> enumeration = seataConfig.propertyNames();
+        while (enumeration.hasMoreElements()) {
+            String key = (String)enumeration.nextElement();
+            String property = seataConfig.getProperty(key);
+            sb.append(key).append("=").append(property).append("\n");
+        }
+
+        return sb.toString();
+    }
+
+    @Override
+    public String getTypeName() {
+        return CONFIG_TYPE;
+    }
+
+    /**
+     * Non-blocking subscriptions prohibit adding subscriptions in the thread pool to prevent thread termination
+     */
+    public static class NacosListener extends AbstractSharedListener {
+        private final String dataId;
+        private final ConfigurationChangeListener listener;
+
+        /**
+         * Instantiates a new Nacos listener.
+         *
+         * @param dataId   the data id
+         * @param listener the listener
+         */
+        public NacosListener(String dataId, ConfigurationChangeListener listener) {
+            this.dataId = dataId;
+            this.listener = listener;
+        }
+
+        /**
+         * Gets target listener.
+         *
+         * @return the target listener
+         */
+        public ConfigurationChangeListener getTargetListener() {
+            return this.listener;
+        }
+
+        @Override
+        public void innerReceive(String dataId, String group, String configInfo) {
+            //The new configuration method to puts all configurations into a dateId
+            if (getNacosDataId().equals(dataId)) {
+                Properties seataConfigNew = new Properties();
+                if (StringUtils.isNotBlank(configInfo)) {
+                    try {
+                        seataConfigNew = ConfigProcessor.processConfig(configInfo, getNacosDataType());
+                    } catch (IOException e) {
+                        LOGGER.error("load config properties error", e);
+                        return;
+                    }
+                }
+
+                //Get all the monitored dataids and judge whether it has been modified
+                for (Map.Entry<String, ConcurrentMap<ConfigurationChangeListener, NacosListener>> entry :
+                    CONFIG_LISTENERS_MAP.entrySet()) {
+                    String listenedDataId = entry.getKey();
+                    String propertyOld = seataConfig.getProperty(listenedDataId, "");
+                    String propertyNew = seataConfigNew.getProperty(listenedDataId, "");
+                    if (!propertyOld.equals(propertyNew)) {
+                        ConfigurationChangeEvent event = new ConfigurationChangeEvent().setDataId(listenedDataId)
+                            .setNewValue(propertyNew).setNamespace(group);
+
+                        ConcurrentMap<ConfigurationChangeListener, NacosListener> configListeners = entry.getValue();
+                        for (ConfigurationChangeListener configListener : configListeners.keySet()) {
+                            configListener.onProcessEvent(event);
+                        }
+                    }
+                }
+
+                seataConfig = seataConfigNew;
+                return;
+            }
+
+            //Compatible with old writing
+            ConfigurationChangeEvent event = new ConfigurationChangeEvent().setDataId(dataId).setNewValue(configInfo)
+                .setNamespace(group);
+            listener.onProcessEvent(event);
+        }
+    }
+
+}
diff --git a/config/seata-config-core/src/main/java/org/apache/seata/config/CachedConfigurationChangeListener.java b/config/seata-config-nacos/src/test/java/io/seata/config/nacos/NacosConfigurationProvider.java
similarity index 71%
copy from config/seata-config-core/src/main/java/org/apache/seata/config/CachedConfigurationChangeListener.java
copy to config/seata-config-nacos/src/test/java/io/seata/config/nacos/NacosConfigurationProvider.java
index 526bc4b53f..54bfe67b3a 100644
--- a/config/seata-config-core/src/main/java/org/apache/seata/config/CachedConfigurationChangeListener.java
+++ b/config/seata-config-nacos/src/test/java/io/seata/config/nacos/NacosConfigurationProvider.java
@@ -14,15 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.seata.config;
+package io.seata.config.nacos;
 
-public interface CachedConfigurationChangeListener extends ConfigurationChangeListener {
-
-    ConfigurationChangeListener CONFIGURATION_CACHE = ConfigurationCache.getInstance();
+import io.seata.config.Configuration;
+import org.apache.seata.common.loader.LoadLevel;
 
+@LoadLevel(name = "Test", order = 1)
+public class NacosConfigurationProvider implements io.seata.config.ConfigurationProvider {
     @Override
-    default void beforeEvent(ConfigurationChangeEvent event) {
-        CONFIGURATION_CACHE.onProcessEvent(event);
+    public Configuration provide() {
+        return NacosConfiguration.getInstance();
     }
-
 }
diff --git a/config/seata-config-nacos/src/test/java/io/seata/config/nacos/TestConfigCustomSPI.java b/config/seata-config-nacos/src/test/java/io/seata/config/nacos/TestConfigCustomSPI.java
new file mode 100644
index 0000000000..2bdd58858f
--- /dev/null
+++ b/config/seata-config-nacos/src/test/java/io/seata/config/nacos/TestConfigCustomSPI.java
@@ -0,0 +1,70 @@
+/*
+ * 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 io.seata.config.nacos;
+
+import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import com.alibaba.nacos.api.NacosFactory;
+import com.alibaba.nacos.api.config.ConfigService;
+import com.alibaba.nacos.api.exception.NacosException;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+import org.apache.seata.config.CachedConfigurationChangeListener;
+import org.apache.seata.config.Configuration;
+import org.apache.seata.config.ConfigurationChangeEvent;
+import org.apache.seata.config.ConfigurationChangeListener;
+import org.apache.seata.config.ConfigurationFactory;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class TestConfigCustomSPI {
+
+    private static final Config FILE_CONFIG = ConfigFactory.load("registry-test.conf");
+    private static ConfigService configService;
+
+    @BeforeAll
+    public static void setup() throws NacosException {
+        String serverAddr = FILE_CONFIG.getString("config.test.serverAddr");
+        Properties properties = new Properties();
+        properties.put("serverAddr", serverAddr);
+        configService = NacosFactory.createConfigService(properties);
+        System.setProperty("seataEnv", "test");
+    }
+
+    @Test
+    public void testGetConfigProperties() throws Exception {
+        Assertions.assertNotNull(configService);
+        Configuration configuration = ConfigurationFactory.getInstance();
+        String dataId = "nacos.config.custom.spi.test";
+        String group = FILE_CONFIG.getString("config.test.group");
+        String content = "seata";
+        configService.publishConfig(dataId, group, content);
+        //get config
+        String config = configuration.getConfig(dataId);
+        Assertions.assertEquals(content, config);
+
+    }
+
+    @AfterAll
+    public static void afterAll() {
+    }
+}
diff --git a/config/seata-config-nacos/src/test/resources/META-INF/services/io.seata.config.ConfigurationProvider b/config/seata-config-nacos/src/test/resources/META-INF/services/io.seata.config.ConfigurationProvider
new file mode 100644
index 0000000000..64e931fa25
--- /dev/null
+++ b/config/seata-config-nacos/src/test/resources/META-INF/services/io.seata.config.ConfigurationProvider
@@ -0,0 +1 @@
+io.seata.config.nacos.NacosConfigurationProvider
\ No newline at end of file
diff --git a/config/seata-config-nacos/src/test/resources/registry-test.conf b/config/seata-config-nacos/src/test/resources/registry-test.conf
new file mode 100644
index 0000000000..2b094f0433
--- /dev/null
+++ b/config/seata-config-nacos/src/test/resources/registry-test.conf
@@ -0,0 +1,125 @@
+#
+# 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.
+#
+
+registry {
+  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa、custom
+  type = "nacos"
+
+  nacos {
+    application = "seata-server"
+    serverAddr = "127.0.0.1:8848"
+    group = "SEATA_GROUP"
+    namespace = ""
+    username = ""
+    password = ""
+    contextPath = "/foo"
+    ##if use MSE Nacos with auth, mutex with username/password attribute
+    #accessKey = ""
+    #secretKey = ""
+    ##if use Nacos naming meta-data for SLB service registry, specify nacos address pattern rules here
+    #slbPattern = ""
+  }
+  eureka {
+    serviceUrl = "http://localhost:8761/eureka"
+    weight = "1"
+  }
+  redis {
+    serverAddr = "localhost:6379"
+    db = "0"
+    password = ""
+    timeout = "0"
+  }
+  zk {
+    serverAddr = "127.0.0.1:2181"
+    sessionTimeout = 6000
+    connectTimeout = 2000
+    username = ""
+    password = ""
+  }
+  consul {
+    serverAddr = "127.0.0.1:8500"
+    aclToken = ""
+  }
+  etcd3 {
+    serverAddr = "http://localhost:2379"
+  }
+  sofa {
+    serverAddr = "127.0.0.1:9603"
+    region = "DEFAULT_ZONE"
+    datacenter = "DefaultDataCenter"
+    group = "SEATA_GROUP"
+    addressWaitTime = "3000"
+  }
+  file {
+    name = "file.conf"
+  }
+  custom {
+    name = ""
+  }
+}
+
+config {
+  # file、nacos 、apollo、zk、consul、etcd3、springCloudConfig、custom
+  type = "test"
+
+  nacos {
+    serverAddr = "127.0.0.1:8848"
+    namespace = ""
+    group = "SEATA_GROUP"
+    username = ""
+    password = ""
+    contextPath = "/bar"
+    ##if use MSE Nacos with auth, mutex with username/password attribute
+    #accessKey = ""
+    #secretKey = ""
+    dataId = "seata.properties"
+  }
+  test {
+      serverAddr = "console.nacos.io:80"
+      namespace = ""
+      group = "SEATA_GROUP"
+  }
+  consul {
+    serverAddr = "127.0.0.1:8500"
+	key = "seata.properties"
+    aclToken = ""
+  }
+  apollo {
+    appId = "seata-server"
+    apolloMeta = "http://192.168.1.204:8801"
+    namespace = "application"
+    apolloAccesskeySecret = ""
+  }
+  zk {
+    serverAddr = "127.0.0.1:2181"
+    sessionTimeout = 6000
+    connectTimeout = 2000
+    username = ""
+    password = ""
+    nodePath = "/seata/seata.properties"
+  }
+  etcd3 {
+    serverAddr = "http://localhost:2379"
+    key = "seata.properties"
+  }
+  file {
+    name = "file.conf"
+  }
+  custom {
+    name = ""
+  }
+}
diff --git a/core/src/main/java/org/apache/seata/core/constants/DubboConstants.java b/core/src/main/java/org/apache/seata/core/constants/DubboConstants.java
index 3b33630f36..8eb848c04d 100644
--- a/core/src/main/java/org/apache/seata/core/constants/DubboConstants.java
+++ b/core/src/main/java/org/apache/seata/core/constants/DubboConstants.java
@@ -18,7 +18,9 @@ package org.apache.seata.core.constants;
 
 /**
  * DubboConstants
- *
+ * Notes:
+ * https://github.com/apache/dubbo-spi-extensions/blob/master/dubbo-filter-extensions/dubbo-filter-seata/src/main
+ * /java/org/apache/dubbo/seata/SeataTransactionPropagationConsumerFilter.java
  */
 public class DubboConstants {
 


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@seata.apache.org
For additional commands, e-mail: notifications-help@seata.apache.org