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