chore(project): 添加项目配置文件和忽略规则
- 添加 Babel 配置文件支持 ES6+ 语法转换 - 添加 ESLint 忽略规则和配置文件 - 添加 Git 忽略规则文件 - 添加 Travis CI 配置文件 - 添加 1.4.2 版本变更日志文件 - 添加 Helm 图表辅助模板文件 - 添加 Helm 忽略规则文件
This commit is contained in:
48
config/seata-config-core/pom.xml
Normal file
48
config/seata-config-core/pom.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 1999-2019 Seata.io Group.
|
||||
~
|
||||
~ Licensed 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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>io.seata</groupId>
|
||||
<artifactId>seata-config</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>seata-config-core</artifactId>
|
||||
<name>seata-config-core ${project.version}</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>seata-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe</groupId>
|
||||
<artifactId>config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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 io.seata.common.util.DurationUtil;
|
||||
|
||||
/**
|
||||
* The type Abstract configuration.
|
||||
*
|
||||
* @author slievrly
|
||||
*/
|
||||
public abstract class AbstractConfiguration implements Configuration {
|
||||
|
||||
/**
|
||||
* The constant DEFAULT_CONFIG_TIMEOUT.
|
||||
*/
|
||||
protected static final long DEFAULT_CONFIG_TIMEOUT = 5 * 1000;
|
||||
|
||||
@Override
|
||||
public short getShort(String dataId, int defaultValue, long timeoutMills) {
|
||||
String result = getConfig(dataId, String.valueOf(defaultValue), timeoutMills);
|
||||
return 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, (short) 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(String dataId, int defaultValue, long timeoutMills) {
|
||||
String result = getConfig(dataId, String.valueOf(defaultValue), timeoutMills);
|
||||
return 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, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(String dataId, long defaultValue, long timeoutMills) {
|
||||
String result = getConfig(dataId, String.valueOf(defaultValue), timeoutMills);
|
||||
return 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, 0L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getDuration(String dataId) {
|
||||
return getDuration(dataId, Duration.ZERO);
|
||||
}
|
||||
|
||||
@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, defaultValue.toMillis() + "ms", timeoutMills);
|
||||
return DurationUtil.parse(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String dataId, boolean defaultValue, long timeoutMills) {
|
||||
String result = getConfig(dataId, String.valueOf(defaultValue), timeoutMills);
|
||||
return 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, false);
|
||||
}
|
||||
|
||||
@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) {
|
||||
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();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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;
|
||||
|
||||
/**
|
||||
* The interface Config change listener.
|
||||
*
|
||||
* @author slievrly
|
||||
*/
|
||||
public interface ConfigChangeListener {
|
||||
|
||||
/**
|
||||
* Gets executor.
|
||||
*
|
||||
* @return the executor
|
||||
*/
|
||||
ExecutorService getExecutor();
|
||||
|
||||
/**
|
||||
* Receive config info.
|
||||
*
|
||||
* @param configInfo the config info
|
||||
*/
|
||||
void receiveConfigInfo(final String configInfo);
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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 io.seata.common.exception.ShouldNeverHappenException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* The type Config future.
|
||||
*
|
||||
* @author slievrly
|
||||
*/
|
||||
public class ConfigFuture {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigFuture.class);
|
||||
private static final long DEFAULT_CONFIG_TIMEOUT = 5 * 1000;
|
||||
private long timeoutMills;
|
||||
private long start = System.currentTimeMillis();
|
||||
private String dataId;
|
||||
private String content;
|
||||
private ConfigOperation operation;
|
||||
private transient CompletableFuture<Object> origin = new CompletableFuture<>();
|
||||
|
||||
/**
|
||||
* Instantiates a new Config future.
|
||||
*
|
||||
* @param dataId the data id
|
||||
* @param content the content
|
||||
* @param operation the operation
|
||||
*/
|
||||
public ConfigFuture(String dataId, String content, ConfigOperation operation) {
|
||||
this(dataId, content, operation, DEFAULT_CONFIG_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Config future.
|
||||
*
|
||||
* @param dataId the data id
|
||||
* @param content the content
|
||||
* @param operation the operation
|
||||
* @param timeoutMills the timeout mills
|
||||
*/
|
||||
public ConfigFuture(String dataId, String content, ConfigOperation operation, long timeoutMills) {
|
||||
this.dataId = dataId;
|
||||
this.content = content;
|
||||
this.operation = operation;
|
||||
this.timeoutMills = timeoutMills;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets timeout mills.
|
||||
*
|
||||
* @return the timeout mills
|
||||
*/
|
||||
public boolean isTimeout() {
|
||||
return System.currentTimeMillis() - start > timeoutMills;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object.
|
||||
*
|
||||
* @return the object
|
||||
*/
|
||||
public Object get() {
|
||||
return get(this.timeoutMills, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object.
|
||||
*
|
||||
* @param timeout the timeout
|
||||
* @param unit the unit
|
||||
* @return the object
|
||||
*/
|
||||
public Object get(long timeout, TimeUnit unit) {
|
||||
this.timeoutMills = unit.toMillis(timeout);
|
||||
Object result;
|
||||
try {
|
||||
result = origin.get(timeout, unit);
|
||||
} catch (ExecutionException e) {
|
||||
throw new ShouldNeverHappenException("Should not get results in a multi-threaded environment", e);
|
||||
} catch (TimeoutException e) {
|
||||
LOGGER.error("config operation timeout,cost:{} ms,op:{},dataId:{}", System.currentTimeMillis() - start, operation.name(), dataId);
|
||||
return getFailResult();
|
||||
} catch (InterruptedException exx) {
|
||||
LOGGER.error("config operate interrupted,error:{}", exx.getMessage(), exx);
|
||||
return getFailResult();
|
||||
}
|
||||
if (operation == ConfigOperation.GET) {
|
||||
return result == null ? content : result;
|
||||
} else {
|
||||
return result == null ? Boolean.FALSE : result;
|
||||
}
|
||||
}
|
||||
|
||||
private Object getFailResult() {
|
||||
if (operation == ConfigOperation.GET) {
|
||||
return content;
|
||||
} else {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets result.
|
||||
*
|
||||
* @param result the result
|
||||
*/
|
||||
public void setResult(Object result) {
|
||||
origin.complete(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data id.
|
||||
*
|
||||
* @return the data id
|
||||
*/
|
||||
public String getDataId() {
|
||||
return dataId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets data id.
|
||||
*
|
||||
* @param dataId the data id
|
||||
*/
|
||||
public void setDataId(String dataId) {
|
||||
this.dataId = dataId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets content.
|
||||
*
|
||||
* @return the content
|
||||
*/
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets content.
|
||||
*
|
||||
* @param content the content
|
||||
*/
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets operation.
|
||||
*
|
||||
* @return the operation
|
||||
*/
|
||||
public ConfigOperation getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets operation.
|
||||
*
|
||||
* @param operation the operation
|
||||
*/
|
||||
public void setOperation(ConfigOperation operation) {
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
/**
|
||||
* The enum Config operation.
|
||||
*/
|
||||
public enum ConfigOperation {
|
||||
/**
|
||||
* Get config operation.
|
||||
*/
|
||||
GET,
|
||||
/**
|
||||
* Put config operation.
|
||||
*/
|
||||
PUT,
|
||||
/**
|
||||
* Putifabsent config operation.
|
||||
*/
|
||||
PUTIFABSENT,
|
||||
/**
|
||||
* Remove config operation.
|
||||
*/
|
||||
REMOVE
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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;
|
||||
|
||||
/**
|
||||
* The enum Config type.
|
||||
*
|
||||
* @author slievrly
|
||||
*/
|
||||
public enum ConfigType {
|
||||
/**
|
||||
* File config type.
|
||||
*/
|
||||
File,
|
||||
/**
|
||||
* zookeeper config type.
|
||||
*/
|
||||
ZK,
|
||||
/**
|
||||
* Nacos config type.
|
||||
*/
|
||||
Nacos,
|
||||
/**
|
||||
* Apollo config type.
|
||||
*/
|
||||
Apollo,
|
||||
/**
|
||||
* Consul config type
|
||||
*/
|
||||
Consul,
|
||||
/**
|
||||
* Etcd3 config type
|
||||
*/
|
||||
Etcd3,
|
||||
/**
|
||||
* spring cloud config type
|
||||
*/
|
||||
SpringCloudConfig,
|
||||
/**
|
||||
* Custom config type
|
||||
*/
|
||||
Custom;
|
||||
|
||||
/**
|
||||
* Gets type.
|
||||
*
|
||||
* @param name the name
|
||||
* @return the type
|
||||
*/
|
||||
public static ConfigType getType(String name) {
|
||||
for (ConfigType configType : values()) {
|
||||
if (configType.name().equalsIgnoreCase(name)) {
|
||||
return configType;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("not support config type: " + name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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.Set;
|
||||
|
||||
/**
|
||||
* The interface Configuration.
|
||||
*
|
||||
* @author slievrly
|
||||
*/
|
||||
public interface Configuration {
|
||||
|
||||
/**
|
||||
* Gets short.
|
||||
*
|
||||
* @param dataId the data id
|
||||
* @param defaultValue the default value
|
||||
* @param timeoutMills the timeout mills
|
||||
* @return the short
|
||||
*/
|
||||
short getShort(String dataId, int 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 he 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);
|
||||
|
||||
/**
|
||||
*
|
||||
* @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 getConfigFromSysPro(String dataId) {
|
||||
return System.getProperty(dataId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import io.seata.common.util.DurationUtil;
|
||||
import io.seata.common.util.StringUtils;
|
||||
import net.sf.cglib.proxy.Enhancer;
|
||||
import net.sf.cglib.proxy.MethodInterceptor;
|
||||
|
||||
/**
|
||||
* @author funkye
|
||||
*/
|
||||
public class ConfigurationCache implements ConfigurationChangeListener {
|
||||
|
||||
private static final String METHOD_PREFIX = "get";
|
||||
|
||||
private static final String METHOD_LATEST_CONFIG = METHOD_PREFIX + "LatestConfig";
|
||||
|
||||
private static final ConcurrentHashMap<String, ObjectWrapper> CONFIG_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private Map<String, HashSet<ConfigurationChangeListener>> configListenersMap = new HashMap<>();
|
||||
|
||||
public static void addConfigListener(String dataId, ConfigurationChangeListener... listeners) {
|
||||
if (StringUtils.isBlank(dataId)) {
|
||||
return;
|
||||
}
|
||||
synchronized (ConfigurationCache.class) {
|
||||
HashSet<ConfigurationChangeListener> listenerHashSet =
|
||||
getInstance().configListenersMap.computeIfAbsent(dataId, key -> new HashSet<>());
|
||||
if (!listenerHashSet.contains(getInstance())) {
|
||||
ConfigurationFactory.getInstance().addConfigListener(dataId, getInstance());
|
||||
listenerHashSet.add(getInstance());
|
||||
}
|
||||
if (null != listeners && listeners.length > 0) {
|
||||
for (ConfigurationChangeListener listener : listeners) {
|
||||
if (!listenerHashSet.contains(listener)) {
|
||||
listenerHashSet.add(listener);
|
||||
ConfigurationFactory.getInstance().addConfigListener(dataId, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ConfigurationCache getInstance() {
|
||||
return ConfigurationCacheInstance.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChangeEvent(ConfigurationChangeEvent event) {
|
||||
ObjectWrapper wrapper = CONFIG_CACHE.get(event.getDataId());
|
||||
// The wrapper.data only exists in the cache when it is not null.
|
||||
if (StringUtils.isNotBlank(event.getNewValue())) {
|
||||
if (wrapper == null) {
|
||||
CONFIG_CACHE.put(event.getDataId(), new ObjectWrapper(event.getNewValue(), null));
|
||||
} else {
|
||||
Object newValue = new ObjectWrapper(event.getNewValue(), null).convertData(wrapper.getType());
|
||||
if (!Objects.equals(wrapper.getData(), newValue)) {
|
||||
CONFIG_CACHE.put(event.getDataId(), new ObjectWrapper(newValue, wrapper.getType()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CONFIG_CACHE.remove(event.getDataId());
|
||||
}
|
||||
}
|
||||
|
||||
public Configuration proxy(Configuration originalConfiguration) {
|
||||
return (Configuration)Enhancer.create(Configuration.class,
|
||||
(MethodInterceptor)(proxy, method, args, methodProxy) -> {
|
||||
if (method.getName().startsWith(METHOD_PREFIX)
|
||||
&& !method.getName().equalsIgnoreCase(METHOD_LATEST_CONFIG)) {
|
||||
String rawDataId = (String)args[0];
|
||||
ObjectWrapper wrapper = CONFIG_CACHE.get(rawDataId);
|
||||
String type = method.getName().substring(METHOD_PREFIX.length());
|
||||
if (!ObjectWrapper.supportType(type)) {
|
||||
type = null;
|
||||
}
|
||||
if (null == wrapper) {
|
||||
Object result = method.invoke(originalConfiguration, args);
|
||||
// The wrapper.data only exists in the cache when it is not null.
|
||||
if (result != null) {
|
||||
wrapper = new ObjectWrapper(result, type);
|
||||
CONFIG_CACHE.put(rawDataId, wrapper);
|
||||
}
|
||||
}
|
||||
return wrapper == null ? null : wrapper.convertData(type);
|
||||
}
|
||||
return method.invoke(originalConfiguration, args);
|
||||
});
|
||||
}
|
||||
|
||||
private static class ConfigurationCacheInstance {
|
||||
private static final ConfigurationCache INSTANCE = new ConfigurationCache();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
CONFIG_CACHE.clear();
|
||||
}
|
||||
|
||||
private static class ObjectWrapper {
|
||||
|
||||
static final String INT = "Int";
|
||||
static final String BOOLEAN = "Boolean";
|
||||
static final String DURATION = "Duration";
|
||||
static final String LONG = "Long";
|
||||
static final String SHORT = "Short";
|
||||
|
||||
private final Object data;
|
||||
private final String type;
|
||||
|
||||
ObjectWrapper(Object data, String type) {
|
||||
this.data = data;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Object convertData(String aType) {
|
||||
if (data != null && Objects.equals(type, aType)) {
|
||||
return data;
|
||||
}
|
||||
if (data != null) {
|
||||
if (INT.equals(aType)) {
|
||||
return Integer.parseInt(data.toString());
|
||||
} else if (BOOLEAN.equals(aType)) {
|
||||
return Boolean.parseBoolean(data.toString());
|
||||
} else if (DURATION.equals(aType)) {
|
||||
return DurationUtil.parse(data.toString());
|
||||
} else if (LONG.equals(aType)) {
|
||||
return Long.parseLong(data.toString());
|
||||
} else if (SHORT.equals(aType)) {
|
||||
return Short.parseShort(data.toString());
|
||||
}
|
||||
return String.valueOf(data);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean supportType(String type) {
|
||||
return INT.equalsIgnoreCase(type)
|
||||
|| BOOLEAN.equalsIgnoreCase(type)
|
||||
|| DURATION.equalsIgnoreCase(type)
|
||||
|| LONG.equalsIgnoreCase(type)
|
||||
|| SHORT.equalsIgnoreCase(type);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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;
|
||||
|
||||
/**
|
||||
* The type Configuration change event.
|
||||
*
|
||||
* @author slievrly
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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 io.seata.common.thread.NamedThreadFactory;
|
||||
|
||||
/**
|
||||
* The interface Configuration change listener.
|
||||
*
|
||||
* @author slievrly
|
||||
*/
|
||||
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() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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;
|
||||
|
||||
/**
|
||||
* The enum Configuration change type.
|
||||
*
|
||||
* @author slievrly
|
||||
*/
|
||||
public enum ConfigurationChangeType {
|
||||
/**
|
||||
* Add configuration change type.
|
||||
*/
|
||||
ADD,
|
||||
/**
|
||||
* Modify configuration change type.
|
||||
*/
|
||||
MODIFY,
|
||||
/**
|
||||
* Delete configuration change type.
|
||||
*/
|
||||
DELETE
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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.Objects;
|
||||
|
||||
import io.seata.common.exception.NotSupportYetException;
|
||||
import io.seata.common.loader.EnhancedServiceLoader;
|
||||
import io.seata.common.loader.EnhancedServiceNotFoundException;
|
||||
import io.seata.common.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The type Configuration factory.
|
||||
*
|
||||
* @author slievrly
|
||||
* @author Geng Zhang
|
||||
*/
|
||||
public final class ConfigurationFactory {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationFactory.class);
|
||||
|
||||
private static final String REGISTRY_CONF_DEFAULT = "registry";
|
||||
private static final String ENV_SYSTEM_KEY = "SEATA_ENV";
|
||||
public static final String ENV_PROPERTY_KEY = "seataEnv";
|
||||
|
||||
private static final String SYSTEM_PROPERTY_SEATA_CONFIG_NAME = "seata.config.name";
|
||||
|
||||
private static final String ENV_SEATA_CONFIG_NAME = "SEATA_CONFIG_NAME";
|
||||
|
||||
public static Configuration CURRENT_FILE_INSTANCE;
|
||||
|
||||
static {
|
||||
load();
|
||||
}
|
||||
|
||||
private static void load() {
|
||||
String seataConfigName = System.getProperty(SYSTEM_PROPERTY_SEATA_CONFIG_NAME);
|
||||
if (seataConfigName == null) {
|
||||
seataConfigName = System.getenv(ENV_SEATA_CONFIG_NAME);
|
||||
}
|
||||
if (seataConfigName == null) {
|
||||
seataConfigName = REGISTRY_CONF_DEFAULT;
|
||||
}
|
||||
String envValue = System.getProperty(ENV_PROPERTY_KEY);
|
||||
if (envValue == null) {
|
||||
envValue = System.getenv(ENV_SYSTEM_KEY);
|
||||
}
|
||||
Configuration configuration = (envValue == null) ? new FileConfiguration(seataConfigName,
|
||||
false) : new FileConfiguration(seataConfigName + "-" + envValue, false);
|
||||
Configuration extConfiguration = null;
|
||||
try {
|
||||
extConfiguration = EnhancedServiceLoader.load(ExtConfigurationProvider.class).provide(configuration);
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("load Configuration:{}", extConfiguration == null ? configuration.getClass().getSimpleName()
|
||||
: extConfiguration.getClass().getSimpleName());
|
||||
}
|
||||
} catch (EnhancedServiceNotFoundException ignore) {
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("failed to load extConfiguration:{}", e.getMessage(), e);
|
||||
}
|
||||
CURRENT_FILE_INSTANCE = extConfiguration == null ? configuration : extConfiguration;
|
||||
}
|
||||
|
||||
private static final String NAME_KEY = "name";
|
||||
private static final String FILE_TYPE = "file";
|
||||
|
||||
private static volatile Configuration instance = null;
|
||||
|
||||
/**
|
||||
* Gets instance.
|
||||
*
|
||||
* @return the instance
|
||||
*/
|
||||
public static Configuration getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (Configuration.class) {
|
||||
if (instance == null) {
|
||||
instance = buildConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static Configuration buildConfiguration() {
|
||||
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");
|
||||
}
|
||||
ConfigType configType = ConfigType.getType(configTypeName);
|
||||
|
||||
Configuration extConfiguration = null;
|
||||
Configuration configuration;
|
||||
if (ConfigType.File == configType) {
|
||||
String pathDataId = String.join(ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR,
|
||||
ConfigurationKeys.FILE_ROOT_CONFIG, FILE_TYPE, NAME_KEY);
|
||||
String name = CURRENT_FILE_INSTANCE.getConfig(pathDataId);
|
||||
configuration = new FileConfiguration(name);
|
||||
try {
|
||||
extConfiguration = EnhancedServiceLoader.load(ExtConfigurationProvider.class).provide(configuration);
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("load Configuration:{}", extConfiguration == null
|
||||
? configuration.getClass().getSimpleName() : extConfiguration.getClass().getSimpleName());
|
||||
}
|
||||
} catch (EnhancedServiceNotFoundException ignore) {
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("failed to load extConfiguration:{}", e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
configuration = EnhancedServiceLoader
|
||||
.load(ConfigurationProvider.class, Objects.requireNonNull(configType).name()).provide();
|
||||
}
|
||||
try {
|
||||
Configuration configurationCache;
|
||||
if (null != extConfiguration) {
|
||||
configurationCache = ConfigurationCache.getInstance().proxy(extConfiguration);
|
||||
} else {
|
||||
configurationCache = ConfigurationCache.getInstance().proxy(configuration);
|
||||
}
|
||||
if (null != configurationCache) {
|
||||
extConfiguration = configurationCache;
|
||||
}
|
||||
} catch (EnhancedServiceNotFoundException ignore) {
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("failed to load configurationCacheProvider:{}", e.getMessage(), e);
|
||||
}
|
||||
return null == extConfiguration ? configuration : extConfiguration;
|
||||
}
|
||||
|
||||
protected static void reload() {
|
||||
ConfigurationCache.getInstance().clear();
|
||||
load();
|
||||
instance = null;
|
||||
getInstance();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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;
|
||||
|
||||
/**
|
||||
* The type Configuration keys.
|
||||
*
|
||||
* @author slievrly
|
||||
*/
|
||||
public interface ConfigurationKeys {
|
||||
/**
|
||||
* The constant FILE_ROOT_REGISTRY.
|
||||
*/
|
||||
String FILE_ROOT_REGISTRY = "registry";
|
||||
/**
|
||||
* The constant FILE_ROOT_CONFIG.
|
||||
*/
|
||||
String FILE_ROOT_CONFIG = "config";
|
||||
/**
|
||||
* The constant SEATA_FILE_ROOT_CONFIG
|
||||
*/
|
||||
String SEATA_FILE_ROOT_CONFIG = "seata";
|
||||
/**
|
||||
* The constant FILE_CONFIG_SPLIT_CHAR.
|
||||
*/
|
||||
String FILE_CONFIG_SPLIT_CHAR = ".";
|
||||
/**
|
||||
* The constant FILE_ROOT_TYPE.
|
||||
*/
|
||||
String FILE_ROOT_TYPE = "type";
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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;
|
||||
|
||||
/**
|
||||
* the interface configuration provider
|
||||
* @author xingfudeshi@gmail.com
|
||||
*/
|
||||
public interface ConfigurationProvider {
|
||||
/**
|
||||
* provide a AbstractConfiguration implementation instance
|
||||
* @return Configuration
|
||||
*/
|
||||
Configuration provide();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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;
|
||||
|
||||
/**
|
||||
* the interface ext configuration provider
|
||||
* @author xingfudeshi@gmail.com
|
||||
*/
|
||||
public interface ExtConfigurationProvider {
|
||||
/**
|
||||
* provide a AbstractConfiguration implementation instance
|
||||
* @param originalConfiguration
|
||||
* @return configuration
|
||||
*/
|
||||
Configuration provide(Configuration originalConfiguration);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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 io.seata.common.loader.EnhancedServiceLoader;
|
||||
import io.seata.config.file.FileConfig;
|
||||
import java.io.File;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author wangwei-ying
|
||||
*/
|
||||
public class FileConfigFactory {
|
||||
|
||||
public static final String DEFAULT_TYPE = "CONF";
|
||||
|
||||
public static final String YAML_TYPE = "YAML";
|
||||
|
||||
private static final LinkedHashMap<String, String> SUFFIX_MAP = new LinkedHashMap<String, String>(4) {
|
||||
{
|
||||
put("conf", DEFAULT_TYPE);
|
||||
put("properties", DEFAULT_TYPE);
|
||||
put("yml", YAML_TYPE);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static FileConfig load() {
|
||||
return loadService(DEFAULT_TYPE, null, null);
|
||||
}
|
||||
|
||||
public static FileConfig load(File targetFile, String name) {
|
||||
String fileName = targetFile.getName();
|
||||
String configType = getConfigType(fileName);
|
||||
return loadService(configType, new Class[]{File.class, String.class}, new Object[]{targetFile, name});
|
||||
}
|
||||
|
||||
private static String getConfigType(String fileName) {
|
||||
String configType = DEFAULT_TYPE;
|
||||
int suffixIndex = fileName.lastIndexOf(".");
|
||||
if (suffixIndex > 0) {
|
||||
configType = SUFFIX_MAP.getOrDefault(fileName.substring(suffixIndex + 1), DEFAULT_TYPE);
|
||||
}
|
||||
|
||||
return configType;
|
||||
}
|
||||
|
||||
private static FileConfig loadService(String name, Class[] argsType, Object[] args) {
|
||||
FileConfig fileConfig = EnhancedServiceLoader.load(FileConfig.class, name, argsType, args);
|
||||
return fileConfig;
|
||||
}
|
||||
|
||||
public static Set<String> getSuffixSet() {
|
||||
return SUFFIX_MAP.keySet();
|
||||
}
|
||||
|
||||
public synchronized static void register(String suffix, String beanActiveName) {
|
||||
SUFFIX_MAP.put(suffix, beanActiveName);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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.io.File;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.netty.util.internal.ConcurrentSet;
|
||||
import io.seata.common.thread.NamedThreadFactory;
|
||||
import io.seata.common.util.CollectionUtils;
|
||||
import io.seata.common.util.StringUtils;
|
||||
import io.seata.config.ConfigFuture.ConfigOperation;
|
||||
import io.seata.config.file.FileConfig;
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The type FileConfiguration.
|
||||
*
|
||||
* @author slievrly
|
||||
*/
|
||||
public class FileConfiguration extends AbstractConfiguration {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FileConfiguration.class);
|
||||
|
||||
private FileConfig fileConfig;
|
||||
|
||||
private ExecutorService configOperateExecutor;
|
||||
|
||||
private static final int CORE_CONFIG_OPERATE_THREAD = 1;
|
||||
|
||||
private static final int MAX_CONFIG_OPERATE_THREAD = 2;
|
||||
|
||||
private static final long LISTENER_CONFIG_INTERVAL = 1 * 1000;
|
||||
|
||||
private static final String REGISTRY_TYPE = "file";
|
||||
|
||||
public static final String SYS_FILE_RESOURCE_PREFIX = "file:";
|
||||
|
||||
private final ConcurrentMap<String, Set<ConfigurationChangeListener>> configListenersMap = new ConcurrentHashMap<>(
|
||||
8);
|
||||
|
||||
private final Map<String, String> listenedConfigMap = new HashMap<>(8);
|
||||
|
||||
private final String targetFilePath;
|
||||
|
||||
private volatile long targetFileLastModified;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final FileListener fileListener = new FileListener();
|
||||
|
||||
private final boolean allowDynamicRefresh;
|
||||
|
||||
/**
|
||||
* Note that:this constructor is only used to create proxy with CGLIB
|
||||
* see io.seata.spring.boot.autoconfigure.provider.SpringBootConfigurationProvider#provide
|
||||
*/
|
||||
public FileConfiguration() {
|
||||
this.name = null;
|
||||
this.targetFilePath = null;
|
||||
this.allowDynamicRefresh = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new File configuration.
|
||||
*
|
||||
* @param name the name
|
||||
*/
|
||||
public FileConfiguration(String name) {
|
||||
this(name, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new File configuration.
|
||||
*
|
||||
* @param name the name
|
||||
* @param allowDynamicRefresh the allow dynamic refresh
|
||||
*/
|
||||
public FileConfiguration(String name, boolean allowDynamicRefresh) {
|
||||
LOGGER.info("The file name of the operation is {}", name);
|
||||
File file = getConfigFile(name);
|
||||
if (file == null) {
|
||||
targetFilePath = null;
|
||||
} else {
|
||||
targetFilePath = file.getPath();
|
||||
fileConfig = FileConfigFactory.load(file, name);
|
||||
}
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
if (targetFilePath == null) {
|
||||
fileConfig = FileConfigFactory.load();
|
||||
this.allowDynamicRefresh = false;
|
||||
} else {
|
||||
targetFileLastModified = new File(targetFilePath).lastModified();
|
||||
this.allowDynamicRefresh = allowDynamicRefresh;
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
configOperateExecutor = new ThreadPoolExecutor(CORE_CONFIG_OPERATE_THREAD, MAX_CONFIG_OPERATE_THREAD,
|
||||
Integer.MAX_VALUE, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(),
|
||||
new NamedThreadFactory("configOperate", MAX_CONFIG_OPERATE_THREAD));
|
||||
}
|
||||
|
||||
private File getConfigFile(String name) {
|
||||
try {
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("name can't be null");
|
||||
}
|
||||
|
||||
boolean filePathCustom = name.startsWith(SYS_FILE_RESOURCE_PREFIX);
|
||||
String filePath = filePathCustom ? name.substring(SYS_FILE_RESOURCE_PREFIX.length()) : name;
|
||||
String decodedPath = URLDecoder.decode(filePath, StandardCharsets.UTF_8.name());
|
||||
|
||||
File targetFile = getFileFromFileSystem(decodedPath);
|
||||
if (targetFile != null) {
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("The configuration file used is {}", targetFile.getPath());
|
||||
}
|
||||
return targetFile;
|
||||
}
|
||||
|
||||
if (!filePathCustom) {
|
||||
File classpathFile = getFileFromClasspath(name);
|
||||
if (classpathFile != null) {
|
||||
return classpathFile;
|
||||
}
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LOGGER.error("decode name error: {}", e.getMessage(), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private File getFileFromFileSystem(String decodedPath) {
|
||||
|
||||
// run with jar file and not package third lib into jar file, this.getClass().getClassLoader() will be null
|
||||
URL resourceUrl = this.getClass().getClassLoader().getResource("");
|
||||
String[] tryPaths = null;
|
||||
if (resourceUrl != null) {
|
||||
tryPaths = new String[]{
|
||||
// first: project dir
|
||||
resourceUrl.getPath() + decodedPath,
|
||||
// second: system path
|
||||
decodedPath
|
||||
};
|
||||
} else {
|
||||
tryPaths = new String[]{
|
||||
decodedPath
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
for (String tryPath : tryPaths) {
|
||||
File targetFile = new File(tryPath);
|
||||
if (targetFile.exists()) {
|
||||
return targetFile;
|
||||
}
|
||||
|
||||
// try to append config suffix
|
||||
for (String s : FileConfigFactory.getSuffixSet()) {
|
||||
targetFile = new File(tryPath + ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR + s);
|
||||
if (targetFile.exists()) {
|
||||
return targetFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private File getFileFromClasspath(String name) throws UnsupportedEncodingException {
|
||||
URL resource = this.getClass().getClassLoader().getResource(name);
|
||||
if (resource == null) {
|
||||
for (String s : FileConfigFactory.getSuffixSet()) {
|
||||
resource = this.getClass().getClassLoader().getResource(name + ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR + s);
|
||||
if (resource != null) {
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("The configuration file used is {}", resource.getPath());
|
||||
}
|
||||
String path = resource.getPath();
|
||||
path = URLDecoder.decode(path, StandardCharsets.UTF_8.name());
|
||||
return new File(path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("The configuration file used is {}", name);
|
||||
}
|
||||
String path = resource.getPath();
|
||||
path = URLDecoder.decode(path, StandardCharsets.UTF_8.name());
|
||||
return new File(path);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLatestConfig(String dataId, String defaultValue, long timeoutMills) {
|
||||
String value = getConfigFromSysPro(dataId);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
ConfigFuture configFuture = new ConfigFuture(dataId, defaultValue, ConfigOperation.GET, timeoutMills);
|
||||
configOperateExecutor.submit(new ConfigOperateRunnable(configFuture));
|
||||
Object getValue = configFuture.get();
|
||||
return getValue == null ? null : String.valueOf(getValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putConfig(String dataId, String content, long timeoutMills) {
|
||||
ConfigFuture configFuture = new ConfigFuture(dataId, content, ConfigOperation.PUT, timeoutMills);
|
||||
configOperateExecutor.submit(new ConfigOperateRunnable(configFuture));
|
||||
return (Boolean) configFuture.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putConfigIfAbsent(String dataId, String content, long timeoutMills) {
|
||||
ConfigFuture configFuture = new ConfigFuture(dataId, content, ConfigOperation.PUTIFABSENT, timeoutMills);
|
||||
configOperateExecutor.submit(new ConfigOperateRunnable(configFuture));
|
||||
return (Boolean) configFuture.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeConfig(String dataId, long timeoutMills) {
|
||||
ConfigFuture configFuture = new ConfigFuture(dataId, null, ConfigOperation.REMOVE, timeoutMills);
|
||||
configOperateExecutor.submit(new ConfigOperateRunnable(configFuture));
|
||||
return (Boolean) configFuture.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addConfigListener(String dataId, ConfigurationChangeListener listener) {
|
||||
if (StringUtils.isBlank(dataId) || listener == null) {
|
||||
return;
|
||||
}
|
||||
configListenersMap.computeIfAbsent(dataId, key -> new ConcurrentSet<>())
|
||||
.add(listener);
|
||||
listenedConfigMap.put(dataId, ConfigurationFactory.getInstance().getConfig(dataId));
|
||||
|
||||
// Start config change listener for the dataId.
|
||||
fileListener.addListener(dataId, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeConfigListener(String dataId, ConfigurationChangeListener listener) {
|
||||
if (StringUtils.isBlank(dataId) || listener == null) {
|
||||
return;
|
||||
}
|
||||
Set<ConfigurationChangeListener> configListeners = getConfigListeners(dataId);
|
||||
if (CollectionUtils.isNotEmpty(configListeners)) {
|
||||
configListeners.remove(listener);
|
||||
if (configListeners.isEmpty()) {
|
||||
configListenersMap.remove(dataId);
|
||||
listenedConfigMap.remove(dataId);
|
||||
}
|
||||
}
|
||||
listener.onShutDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConfigurationChangeListener> getConfigListeners(String dataId) {
|
||||
return configListenersMap.get(dataId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return REGISTRY_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type Config operate runnable.
|
||||
*/
|
||||
class ConfigOperateRunnable implements Runnable {
|
||||
|
||||
private ConfigFuture configFuture;
|
||||
|
||||
/**
|
||||
* Instantiates a new Config operate runnable.
|
||||
*
|
||||
* @param configFuture the config future
|
||||
*/
|
||||
public ConfigOperateRunnable(ConfigFuture configFuture) {
|
||||
this.configFuture = configFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (configFuture != null) {
|
||||
if (configFuture.isTimeout()) {
|
||||
setFailResult(configFuture);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (allowDynamicRefresh) {
|
||||
long tempLastModified = new File(targetFilePath).lastModified();
|
||||
if (tempLastModified > targetFileLastModified) {
|
||||
FileConfig tempConfig = FileConfigFactory.load(new File(targetFilePath), name);
|
||||
if (tempConfig != null) {
|
||||
fileConfig = tempConfig;
|
||||
targetFileLastModified = tempLastModified;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (configFuture.getOperation() == ConfigOperation.GET) {
|
||||
String result = fileConfig.getString(configFuture.getDataId());
|
||||
configFuture.setResult(result);
|
||||
} else if (configFuture.getOperation() == ConfigOperation.PUT) {
|
||||
//todo
|
||||
configFuture.setResult(Boolean.TRUE);
|
||||
} else if (configFuture.getOperation() == ConfigOperation.PUTIFABSENT) {
|
||||
//todo
|
||||
configFuture.setResult(Boolean.TRUE);
|
||||
} else if (configFuture.getOperation() == ConfigOperation.REMOVE) {
|
||||
//todo
|
||||
configFuture.setResult(Boolean.TRUE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
setFailResult(configFuture);
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Could not found property {}, try to use default value instead. exception:{}",
|
||||
configFuture.getDataId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setFailResult(ConfigFuture configFuture) {
|
||||
if (configFuture.getOperation() == ConfigOperation.GET) {
|
||||
String result = configFuture.getContent();
|
||||
configFuture.setResult(result);
|
||||
} else {
|
||||
configFuture.setResult(Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The type FileListener.
|
||||
*/
|
||||
class FileListener implements ConfigurationChangeListener {
|
||||
|
||||
private final Map<String, Set<ConfigurationChangeListener>> dataIdMap = new HashMap<>();
|
||||
|
||||
private final ExecutorService executor = new ThreadPoolExecutor(CORE_LISTENER_THREAD, MAX_LISTENER_THREAD, 0L,
|
||||
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(),
|
||||
new NamedThreadFactory("fileListener", MAX_LISTENER_THREAD));
|
||||
|
||||
/**
|
||||
* Instantiates a new FileListener.
|
||||
*/
|
||||
FileListener() {}
|
||||
|
||||
public synchronized void addListener(String dataId, ConfigurationChangeListener listener) {
|
||||
// only the first time add listener will trigger on process event
|
||||
if (dataIdMap.isEmpty()) {
|
||||
fileListener.onProcessEvent(new ConfigurationChangeEvent());
|
||||
}
|
||||
|
||||
dataIdMap.computeIfAbsent(dataId, value -> new HashSet<>()).add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChangeEvent(ConfigurationChangeEvent event) {
|
||||
while (true) {
|
||||
for (String dataId : dataIdMap.keySet()) {
|
||||
try {
|
||||
String currentConfig =
|
||||
ConfigurationFactory.getInstance().getLatestConfig(dataId, null, DEFAULT_CONFIG_TIMEOUT);
|
||||
if (StringUtils.isNotBlank(currentConfig)) {
|
||||
String oldConfig = listenedConfigMap.get(dataId);
|
||||
if (ObjectUtils.notEqual(currentConfig, oldConfig)) {
|
||||
listenedConfigMap.put(dataId, currentConfig);
|
||||
event.setDataId(dataId).setNewValue(currentConfig).setOldValue(oldConfig);
|
||||
|
||||
for (ConfigurationChangeListener listener : dataIdMap.get(dataId)) {
|
||||
listener.onChangeEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception exx) {
|
||||
LOGGER.error("fileListener execute error, dataId :{}", dataId, exx);
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(LISTENER_CONFIG_INTERVAL);
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.error("fileListener thread sleep error:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutorService getExecutorService() {
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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.file;
|
||||
|
||||
|
||||
/**
|
||||
* @author wangwei-ying
|
||||
*/
|
||||
public interface FileConfig {
|
||||
/**
|
||||
* @param path path expression
|
||||
*/
|
||||
String getString(String path);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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.file;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
|
||||
import io.seata.common.loader.LoadLevel;
|
||||
import io.seata.common.loader.Scope;
|
||||
import io.seata.config.FileConfigFactory;
|
||||
import io.seata.config.FileConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author wangwei-ying
|
||||
*/
|
||||
@LoadLevel(name = FileConfigFactory.DEFAULT_TYPE,scope = Scope.PROTOTYPE)
|
||||
public class SimpleFileConfig implements FileConfig {
|
||||
|
||||
private Config fileConfig;
|
||||
|
||||
public SimpleFileConfig() {
|
||||
fileConfig = ConfigFactory.load();
|
||||
}
|
||||
|
||||
public SimpleFileConfig(File file, String name) {
|
||||
if (name.startsWith(FileConfiguration.SYS_FILE_RESOURCE_PREFIX)) {
|
||||
Config appConfig = ConfigFactory.parseFileAnySyntax(file);
|
||||
fileConfig = ConfigFactory.load(appConfig);
|
||||
} else {
|
||||
fileConfig = ConfigFactory.load(file.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String path) {
|
||||
return fileConfig.getString(path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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.file;
|
||||
|
||||
import io.seata.common.loader.LoadLevel;
|
||||
import io.seata.common.loader.Scope;
|
||||
import io.seata.config.FileConfigFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author wangwei-ying
|
||||
*/
|
||||
@LoadLevel(name = FileConfigFactory.YAML_TYPE, order = 1, scope = Scope.PROTOTYPE)
|
||||
public class YamlFileConfig implements FileConfig {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(YamlFileConfig.class);
|
||||
private Map configMap;
|
||||
|
||||
public YamlFileConfig(File file, String name) {
|
||||
Yaml yaml = new Yaml();
|
||||
try {
|
||||
configMap = (Map) yaml.load(new FileInputStream(file));
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new IllegalArgumentException("file not found");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String path) {
|
||||
try {
|
||||
Map config = configMap;
|
||||
String[] dataId = path.split("\\.");
|
||||
for (int i = 0; i < dataId.length - 1; i++) {
|
||||
if (config.containsKey(dataId[i])) {
|
||||
config = (Map) config.get(dataId[i]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Object value = config.get(dataId[dataId.length - 1]);
|
||||
return value == null ? null : String.valueOf(value);
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("get config data error" + path, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
io.seata.config.file.SimpleFileConfig
|
||||
io.seata.config.file.YamlFileConfig
|
||||
8
config/seata-config-core/src/main/resources/file.conf
Normal file
8
config/seata-config-core/src/main/resources/file.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
service {
|
||||
#transaction service group mapping
|
||||
vgroupMapping.my_test_tx_group = "default"
|
||||
#only support when registry.type=file, please don't set multiple addresses
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#disable seata
|
||||
disableGlobalTransaction = false
|
||||
}
|
||||
76
config/seata-config-core/src/main/resources/registry.conf
Normal file
76
config/seata-config-core/src/main/resources/registry.conf
Normal file
@@ -0,0 +1,76 @@
|
||||
registry {
|
||||
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
application = "seata-server"
|
||||
serverAddr = "localhost"
|
||||
namespace = ""
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
serviceUrl = "http://localhost:8761/eureka"
|
||||
application = "default"
|
||||
weight = "1"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
zk {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
sessionTimeout = 6000
|
||||
connectTimeout = 2000
|
||||
}
|
||||
consul {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
}
|
||||
etcd3 {
|
||||
cluster = "default"
|
||||
serverAddr = "http://localhost:2379"
|
||||
}
|
||||
sofa {
|
||||
serverAddr = "127.0.0.1:9603"
|
||||
application = "default"
|
||||
region = "DEFAULT_ZONE"
|
||||
datacenter = "DefaultDataCenter"
|
||||
cluster = "default"
|
||||
group = "SEATA_GROUP"
|
||||
addressWaitTime = "3000"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file、nacos 、apollo、zk、consul、etcd3
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = ""
|
||||
group = "SEATA_GROUP"
|
||||
}
|
||||
consul {
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
}
|
||||
apollo {
|
||||
appId = "seata-server"
|
||||
apolloMeta = "http://192.168.1.204:8801"
|
||||
namespace = "application"
|
||||
}
|
||||
zk {
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
sessionTimeout = 6000
|
||||
connectTimeout = 2000
|
||||
}
|
||||
etcd3 {
|
||||
serverAddr = "http://localhost:2379"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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;
|
||||
|
||||
/**
|
||||
* @author wangwei-ying
|
||||
*/
|
||||
public interface ConfigProperty {
|
||||
final String ENV_PROPERTY_KEY = "seataEnv";
|
||||
final String SYSTEM_PROPERTY_SEATA_CONFIG_NAME = "seata.config.name";
|
||||
final String REGISTRY_CONF_DEFAULT = "registry";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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 io.seata.common.util.DurationUtil;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* @author jsbxyyx
|
||||
*/
|
||||
public class ConfigurationCacheTests {
|
||||
|
||||
@Test
|
||||
public void testChangeValue() throws Exception {
|
||||
Configuration configuration = new FileConfiguration("registry");
|
||||
configuration = ConfigurationCache.getInstance().proxy(configuration);
|
||||
configuration.getBoolean("aaa", false);
|
||||
ConfigurationCache.getInstance().onChangeEvent(new ConfigurationChangeEvent("aaa", "true"));
|
||||
boolean aaa = configuration.getBoolean("aaa", false);
|
||||
Assertions.assertTrue(aaa);
|
||||
|
||||
configuration.getShort("bbb", (short) 0);
|
||||
ConfigurationCache.getInstance().onChangeEvent(new ConfigurationChangeEvent("bbb", "1"));
|
||||
short bbb = configuration.getShort("bbb", (short) 0);
|
||||
Assertions.assertEquals((short) 1, bbb);
|
||||
|
||||
configuration.getDuration("ccc", Duration.ZERO);
|
||||
ConfigurationCache.getInstance().onChangeEvent(new ConfigurationChangeEvent("ccc", "1s"));
|
||||
Duration ccc = configuration.getDuration("ccc", Duration.ZERO);
|
||||
Assertions.assertEquals(ccc, DurationUtil.parse("1s"));
|
||||
|
||||
configuration.getInt("ddd", 0);
|
||||
ConfigurationCache.getInstance().onChangeEvent(new ConfigurationChangeEvent("ddd", "1"));
|
||||
int ddd = configuration.getInt("ddd", 0);
|
||||
Assertions.assertEquals(1, ddd);
|
||||
|
||||
configuration.getLong("eee", 0);
|
||||
ConfigurationCache.getInstance().onChangeEvent(new ConfigurationChangeEvent("eee", "1"));
|
||||
long eee = configuration.getLong("eee", 0);
|
||||
Assertions.assertEquals((long) 1, eee);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author slievrly
|
||||
*/
|
||||
class FileConfigurationTest {
|
||||
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void addConfigListener() throws InterruptedException {
|
||||
Configuration fileConfig = ConfigurationFactory.getInstance();
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
boolean value = fileConfig.getBoolean("service.disableGlobalTransaction");
|
||||
fileConfig.addConfigListener("service.disableGlobalTransaction", (event) -> {
|
||||
Assertions.assertEquals(Boolean.parseBoolean(event.getNewValue()), !Boolean.parseBoolean(event.getOldValue()));
|
||||
countDownLatch.countDown();
|
||||
});
|
||||
System.setProperty("service.disableGlobalTransaction", String.valueOf(!value));
|
||||
Assertions.assertTrue(countDownLatch.await(2000, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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 org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static io.seata.config.ConfigProperty.ENV_PROPERTY_KEY;
|
||||
import static io.seata.config.ConfigProperty.SYSTEM_PROPERTY_SEATA_CONFIG_NAME;
|
||||
import static io.seata.config.ConfigProperty.REGISTRY_CONF_DEFAULT;
|
||||
|
||||
/**
|
||||
* @author wangwei-ying
|
||||
*/
|
||||
class ProConfigurationFactoryTest {
|
||||
|
||||
@Test
|
||||
void getInstance() {
|
||||
System.setProperty(ENV_PROPERTY_KEY, "test-pro");
|
||||
System.setProperty(SYSTEM_PROPERTY_SEATA_CONFIG_NAME, REGISTRY_CONF_DEFAULT);
|
||||
ConfigurationFactory.reload();
|
||||
Assertions.assertEquals(ConfigurationFactory.CURRENT_FILE_INSTANCE.getConfig("config.file.name"), "file-test-pro.conf");
|
||||
Assertions.assertEquals(ConfigurationFactory.CURRENT_FILE_INSTANCE.getConfig("config.file.testBlank"), "");
|
||||
Assertions.assertEquals(ConfigurationFactory.CURRENT_FILE_INSTANCE.getConfig("config.file.testNull"), null);
|
||||
Assertions.assertEquals(ConfigurationFactory.CURRENT_FILE_INSTANCE.getConfig("config.file.testExist"), null);
|
||||
Configuration instance = ConfigurationFactory.getInstance();
|
||||
Assertions.assertEquals(instance.getConfig("service.disableGlobalTransaction"), "true");
|
||||
Assertions.assertEquals(instance.getConfig("service.default.grouplist"), "127.0.0.1:8092");
|
||||
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll() {
|
||||
System.clearProperty(ENV_PROPERTY_KEY);
|
||||
System.clearProperty(SYSTEM_PROPERTY_SEATA_CONFIG_NAME);
|
||||
ConfigurationFactory.reload();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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 org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static io.seata.config.ConfigProperty.ENV_PROPERTY_KEY;
|
||||
import static io.seata.config.ConfigProperty.SYSTEM_PROPERTY_SEATA_CONFIG_NAME;
|
||||
import static io.seata.config.ConfigProperty.REGISTRY_CONF_DEFAULT;
|
||||
|
||||
|
||||
/**
|
||||
* @author wangwei-ying
|
||||
*/
|
||||
class RegistryConfigurationFactoryTest {
|
||||
|
||||
@Test
|
||||
void getInstance() {
|
||||
System.setProperty(ENV_PROPERTY_KEY,"test");
|
||||
System.setProperty(SYSTEM_PROPERTY_SEATA_CONFIG_NAME,REGISTRY_CONF_DEFAULT);
|
||||
ConfigurationFactory.reload();
|
||||
Assertions.assertEquals(ConfigurationFactory.CURRENT_FILE_INSTANCE.getConfig("config.file.name"),"file-test.conf");
|
||||
Configuration instance = ConfigurationFactory.getInstance();
|
||||
Assertions.assertEquals(instance.getConfig("service.disableGlobalTransaction"),"true");
|
||||
Assertions.assertEquals(instance.getConfig("service.default.grouplist"), "127.0.0.1:8091");
|
||||
|
||||
}
|
||||
@AfterAll
|
||||
public static void afterAll(){
|
||||
System.clearProperty(ENV_PROPERTY_KEY);
|
||||
System.clearProperty(SYSTEM_PROPERTY_SEATA_CONFIG_NAME);
|
||||
ConfigurationFactory.reload();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 1999-2019 Seata.io Group.
|
||||
*
|
||||
* Licensed 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 org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import static io.seata.config.ConfigProperty.ENV_PROPERTY_KEY;
|
||||
import static io.seata.config.ConfigProperty.SYSTEM_PROPERTY_SEATA_CONFIG_NAME;
|
||||
import static io.seata.config.ConfigProperty.REGISTRY_CONF_DEFAULT;
|
||||
|
||||
/**
|
||||
* @author wangwei-ying
|
||||
*/
|
||||
class YamlConfigurationFactoryTest {
|
||||
|
||||
@Test
|
||||
public void getInstance() {
|
||||
System.setProperty(ENV_PROPERTY_KEY, "test-yaml");
|
||||
System.setProperty(SYSTEM_PROPERTY_SEATA_CONFIG_NAME, REGISTRY_CONF_DEFAULT);
|
||||
ConfigurationFactory.reload();
|
||||
Assertions.assertEquals(ConfigurationFactory.CURRENT_FILE_INSTANCE.getConfig("config.file.name"), "file-test-yaml.conf");
|
||||
Assertions.assertEquals(ConfigurationFactory.CURRENT_FILE_INSTANCE.getConfig("config.file.testBlank"), "");
|
||||
Assertions.assertEquals(ConfigurationFactory.CURRENT_FILE_INSTANCE.getConfig("config.file.testNull"), null);
|
||||
Assertions.assertEquals(ConfigurationFactory.CURRENT_FILE_INSTANCE.getConfig("config.file.testExist"), null);
|
||||
Configuration instance = ConfigurationFactory.getInstance();
|
||||
Assertions.assertEquals(instance.getConfig("service.disableGlobalTransaction"), "true");
|
||||
Assertions.assertEquals(instance.getConfig("service.default.grouplist"), "127.0.0.1:8093");
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll() {
|
||||
System.clearProperty(ENV_PROPERTY_KEY);
|
||||
System.clearProperty(SYSTEM_PROPERTY_SEATA_CONFIG_NAME);
|
||||
ConfigurationFactory.reload();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
service {
|
||||
#transaction service group mapping
|
||||
vgroupMapping.my_test_tx_group = "default"
|
||||
#only support when registry.type=file, please don't set multiple addresses
|
||||
default.grouplist = "127.0.0.1:8092"
|
||||
#disable seata
|
||||
disableGlobalTransaction = true
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
service {
|
||||
#transaction service group mapping
|
||||
vgroupMapping.my_test_tx_group = "default"
|
||||
#only support when registry.type=file, please don't set multiple addresses
|
||||
default.grouplist = "127.0.0.1:8093"
|
||||
#disable seata
|
||||
disableGlobalTransaction = true
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
service {
|
||||
#transaction service group mapping
|
||||
vgroupMapping.my_test_tx_group = "default"
|
||||
#only support when registry.type=file, please don't set multiple addresses
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#disable seata
|
||||
disableGlobalTransaction = true
|
||||
}
|
||||
8
config/seata-config-core/src/test/resources/file.conf
Normal file
8
config/seata-config-core/src/test/resources/file.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
service {
|
||||
#transaction service group mapping
|
||||
vgroupMapping.my_test_tx_group = "default"
|
||||
#only support when registry.type=file, please don't set multiple addresses
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#disable seata
|
||||
disableGlobalTransaction = false
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
#Copyright 1999-2019 Seata.io Group.
|
||||
#
|
||||
#Licensed 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.type=file
|
||||
registry.file.name=file-test-pro.conf
|
||||
|
||||
config.type=file
|
||||
config.file.name=file-test-pro.conf
|
||||
config.file.testBlank=
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
registry:
|
||||
type: file
|
||||
file:
|
||||
name: file.conf
|
||||
config:
|
||||
type: file
|
||||
file:
|
||||
name: file-test-yaml.conf
|
||||
# for test
|
||||
testBlank: ''
|
||||
testNull:
|
||||
@@ -0,0 +1,73 @@
|
||||
registry {
|
||||
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = ""
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
serviceUrl = "http://localhost:8761/eureka"
|
||||
application = "default"
|
||||
weight = "1"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
zk {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
sessionTimeout = 6000
|
||||
connectTimeout = 2000
|
||||
}
|
||||
consul {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
}
|
||||
etcd3 {
|
||||
cluster = "default"
|
||||
serverAddr = "http://localhost:2379"
|
||||
}
|
||||
sofa {
|
||||
serverAddr = "127.0.0.1:9603"
|
||||
application = "default"
|
||||
region = "DEFAULT_ZONE"
|
||||
datacenter = "DefaultDataCenter"
|
||||
cluster = "default"
|
||||
group = "SEATA_GROUP"
|
||||
addressWaitTime = "3000"
|
||||
}
|
||||
file {
|
||||
name = "file-test.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file、nacos 、apollo、zk、consul、etcd3
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = ""
|
||||
}
|
||||
consul {
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
}
|
||||
apollo {
|
||||
appId = "seata-server"
|
||||
apolloMeta = "http://192.168.1.204:8801"
|
||||
}
|
||||
zk {
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
sessionTimeout = 6000
|
||||
connectTimeout = 2000
|
||||
}
|
||||
etcd3 {
|
||||
serverAddr = "http://localhost:2379"
|
||||
}
|
||||
file {
|
||||
name = "file-test.conf"
|
||||
}
|
||||
}
|
||||
73
config/seata-config-core/src/test/resources/registry.conf
Normal file
73
config/seata-config-core/src/test/resources/registry.conf
Normal file
@@ -0,0 +1,73 @@
|
||||
registry {
|
||||
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = ""
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
serviceUrl = "http://localhost:8761/eureka"
|
||||
application = "default"
|
||||
weight = "1"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
zk {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
sessionTimeout = 6000
|
||||
connectTimeout = 2000
|
||||
}
|
||||
consul {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
}
|
||||
etcd3 {
|
||||
cluster = "default"
|
||||
serverAddr = "http://localhost:2379"
|
||||
}
|
||||
sofa {
|
||||
serverAddr = "127.0.0.1:9603"
|
||||
application = "default"
|
||||
region = "DEFAULT_ZONE"
|
||||
datacenter = "DefaultDataCenter"
|
||||
cluster = "default"
|
||||
group = "SEATA_GROUP"
|
||||
addressWaitTime = "3000"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file、nacos 、apollo、zk、consul、etcd3
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = ""
|
||||
}
|
||||
consul {
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
}
|
||||
apollo {
|
||||
appId = "seata-server"
|
||||
apolloMeta = "http://192.168.1.204:8801"
|
||||
}
|
||||
zk {
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
sessionTimeout = 6000
|
||||
connectTimeout = 2000
|
||||
}
|
||||
etcd3 {
|
||||
serverAddr = "http://localhost:2379"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user