[ISSUE #8622] 移除 environment 概念 (#8991)

* [ISSUE #8622] 移除 environment 概念

* [ISSUE #8622] 使用尾递归优化循环

- SYS更名为ENV
- SHARED更改为PROTOTYPE

* [ISSUE #8622] rename lookingForProperties

* [ISSUE #8622] NProperties is renamed SearchableProperties and add some comments

* [ISSUE #8622] update some comments
This commit is contained in:
onewe 2022-09-22 09:26:51 +08:00 committed by GitHub
parent b37d100eb3
commit 6278e7eadb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 732 additions and 625 deletions

View File

@ -35,7 +35,7 @@ public class Constants {
public static final String JM_SNAPSHOT_PATH = "JM.SNAPSHOT.PATH"; public static final String JM_SNAPSHOT_PATH = "JM.SNAPSHOT.PATH";
public static final String NACOS_ENVS_SEARCH = "nacos.envs.search"; public static final String NACOS_ENV_FIRST = "nacos.env.first";
} }

View File

@ -16,6 +16,8 @@
package com.alibaba.nacos.client.env; package com.alibaba.nacos.client.env;
import java.util.Properties;
abstract class AbstractPropertySource { abstract class AbstractPropertySource {
/** /**
@ -31,4 +33,17 @@ abstract class AbstractPropertySource {
*/ */
abstract String getProperty(String key); abstract String getProperty(String key);
/**
* Tests if the specified object is a key in this propertySource.
* @param key key possible key
* @return true if and only if the specified object is a key in this propertySource, false otherwise.
*/
abstract boolean containsKey(String key);
/**
* to properties.
* @return properties
*/
abstract Properties asProperties();
} }

View File

@ -21,7 +21,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import java.util.Properties; import java.util.Properties;
class DefaultSettingPropertySource extends AbstractPropertySource { class DefaultSettingPropertySource extends AbstractPropertySource {
@ -33,12 +32,10 @@ class DefaultSettingPropertySource extends AbstractPropertySource {
private final Properties defaultSetting = new Properties(); private final Properties defaultSetting = new Properties();
DefaultSettingPropertySource() { DefaultSettingPropertySource() {
try { try (final InputStream inputStream = ResourceUtils.getResourceUrl(DEFAULT_SETTING_PATH).openStream()) {
final URL resourceUrl = ResourceUtils.getResourceUrl(DEFAULT_SETTING_PATH);
final InputStream inputStream = resourceUrl.openStream();
defaultSetting.load(inputStream); defaultSetting.load(inputStream);
} catch (Exception e) { } catch (Exception e) {
LOGGER.warn("load default setting failed"); LOGGER.error("load default setting failed", e);
} }
} }
@ -51,4 +48,16 @@ class DefaultSettingPropertySource extends AbstractPropertySource {
String getProperty(String key) { String getProperty(String key) {
return defaultSetting.getProperty(key); return defaultSetting.getProperty(key);
} }
@Override
boolean containsKey(String key) {
return defaultSetting.containsKey(key);
}
@Override
Properties asProperties() {
Properties properties = new Properties();
properties.putAll(defaultSetting);
return properties;
}
} }

View File

@ -35,4 +35,16 @@ class JvmArgsPropertySource extends AbstractPropertySource {
String getProperty(String key) { String getProperty(String key) {
return properties.getProperty(key); return properties.getProperty(key);
} }
@Override
boolean containsKey(String key) {
return properties.containsKey(key);
}
@Override
Properties asProperties() {
Properties properties = new Properties();
properties.putAll(this.properties);
return properties;
}
} }

View File

@ -16,12 +16,27 @@
package com.alibaba.nacos.client.env; package com.alibaba.nacos.client.env;
import java.util.Properties;
/** /**
* nacos env interface. * NacosClientProperties interface.
* * include all the properties from jvm args, system environment, default setting.
* more details you can see https://github.com/alibaba/nacos/issues/8622
* @author onewe * @author onewe
*/ */
public interface NacosEnvironment { public interface NacosClientProperties {
/**
* all the NacosClientProperties object must be created by PROTOTYPE,
* so child NacosClientProperties can read properties from the PROTOTYPE.
* it looks like this:
* |-PROTOTYPE----------------> ip=127.0.0.1
* |---|-child1---------------> port=6379
* if you search key called "port" from child1, certainly you will get 6379
* if you search key called "ip" from child1, you will get 127.0.0.1.
* because the child can read properties from parent NacosClientProperties
*/
NacosClientProperties PROTOTYPE = SearchableProperties.INSTANCE;
/** /**
* get property, if the value can not be got by the special key, the null will be returned. * get property, if the value can not be got by the special key, the null will be returned.
@ -87,4 +102,42 @@ public interface NacosEnvironment {
*/ */
Long getLong(String key, Long defaultValue); Long getLong(String key, Long defaultValue);
/**
* set property.
* @param key key
* @param value value
*/
void setProperty(String key, String value);
/**
* add properties.
* @param properties properties
*/
void addProperties(Properties properties);
/**
* Tests if the specified object is a key in this NacosClientProperties.
* @param key key possible key
* @return true if and only if the specified object is a key in this NacosClientProperties, false otherwise.
*/
boolean containsKey(String key);
/**
* get properties from NacosClientProperties.
* @return properties
*/
Properties asProperties();
/**
* create a new NacosClientProperties which scope is itself.
* @return NacosClientProperties
*/
NacosClientProperties derive();
/**
* create a new NacosClientProperties from NacosClientProperties#PROTOTYPE and init.
* @param properties properties
* @return NacosClientProperties
*/
NacosClientProperties derive(Properties properties);
} }

View File

@ -1,68 +0,0 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.nacos.client.env;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Properties;
class NacosEnvironmentFactory {
/**
* create nacos environment.
* @return NacosEnvironment's proxy object, it contains a SearchableEnvironment object.
* @see SearchableEnvironment
*/
static NacosEnvironment createEnvironment() {
return (NacosEnvironment) Proxy.newProxyInstance(NacosEnvironmentFactory.class.getClassLoader(), new Class[] {NacosEnvironment.class},
new NacosEnvironmentDelegate() {
volatile NacosEnvironment environment;
@Override
public void init(Properties properties) {
if (environment == null) {
synchronized (NacosEnvironmentFactory.class) {
if (environment == null) {
environment = new SearchableEnvironment(properties);
}
}
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (environment == null) {
throw new IllegalStateException(
"Nacos environment doesn't init, please call NacosEnvs#init method then try it again.");
}
return method.invoke(environment, args);
}
});
}
interface NacosEnvironmentDelegate extends InvocationHandler {
/**
* init environment.
* @param properties user customize properties
*/
void init(Properties properties);
}
}

View File

@ -1,116 +0,0 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.nacos.client.env;
import java.lang.reflect.Proxy;
import java.util.Properties;
/**
* environment utils.
* @author onewe
*/
public class NacosEnvs {
private static final NacosEnvironment ENVIRONMENT = NacosEnvironmentFactory.createEnvironment();
/**
* init environment.
* @param properties properties
*/
public static void init(Properties properties) {
NacosEnvironmentFactory.NacosEnvironmentDelegate warrper = (NacosEnvironmentFactory.NacosEnvironmentDelegate) Proxy.getInvocationHandler(
ENVIRONMENT);
warrper.init(properties);
}
public static String getProperty(String key, String defaultValue) {
return ENVIRONMENT.getProperty(key, defaultValue);
}
/**
* get property, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return string value or null.
*/
public static String getProperty(String key) {
return ENVIRONMENT.getProperty(key);
}
/**
* get boolean, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return boolean value or null.
*/
public static Boolean getBoolean(String key) {
return ENVIRONMENT.getBoolean(key);
}
/**
* get boolean, if the value can not be got by the special key, the default value will be returned.
*
* @param key special key
* @param defaultValue default value
* @return boolean value or defaultValue.
*/
public static Boolean getBoolean(String key, Boolean defaultValue) {
return ENVIRONMENT.getBoolean(key, defaultValue);
}
/**
* get integer, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return integer value or null
*/
public static Integer getInteger(String key) {
return ENVIRONMENT.getInteger(key);
}
/**
* get integer, if the value can not be got by the special key, the default value will be returned.
*
* @param key special key
* @param defaultValue default value
* @return integer value or default value
*/
public static Integer getInteger(String key, Integer defaultValue) {
return ENVIRONMENT.getInteger(key, defaultValue);
}
/**
* get long, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return long value or null
*/
public static Long getLong(String key) {
return ENVIRONMENT.getLong(key);
}
/**
* get long, if the value can not be got by the special key, the default value will be returned.
*
* @param key special key
* @param defaultValue default value
* @return long value or default value
*/
public static Long getLong(String key, Long defaultValue) {
return ENVIRONMENT.getLong(key, defaultValue);
}
}

View File

@ -16,14 +16,23 @@
package com.alibaba.nacos.client.env; package com.alibaba.nacos.client.env;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Properties; import java.util.Properties;
class PropertiesPropertySource extends AbstractPropertySource { class PropertiesPropertySource extends AbstractPropertySource {
private final Properties properties; private final Properties properties = new Properties();
PropertiesPropertySource(Properties properties) { private final PropertiesPropertySource parent;
this.properties = properties;
PropertiesPropertySource() {
this.parent = null;
}
PropertiesPropertySource(PropertiesPropertySource parent) {
this.parent = parent;
} }
@Override @Override
@ -33,6 +42,67 @@ class PropertiesPropertySource extends AbstractPropertySource {
@Override @Override
String getProperty(String key) { String getProperty(String key) {
return properties.getProperty(key); return getProperty(this, key);
}
private String getProperty(PropertiesPropertySource propertiesPropertySource, String key) {
final String value = propertiesPropertySource.properties.getProperty(key);
if (value != null) {
return value;
}
final PropertiesPropertySource parent = propertiesPropertySource.parent;
if (parent == null) {
return null;
}
return getProperty(parent, key);
}
@Override
boolean containsKey(String key) {
return containsKey(this, key);
}
boolean containsKey(PropertiesPropertySource propertiesPropertySource, String key) {
final boolean exist = propertiesPropertySource.properties.containsKey(key);
if (exist) {
return true;
}
final PropertiesPropertySource parent = propertiesPropertySource.parent;
if (parent == null) {
return false;
}
return containsKey(parent, key);
}
@Override
Properties asProperties() {
List<Properties> propertiesList = new ArrayList<>(8);
propertiesList = lookForProperties(this, propertiesList);
Properties ret = new Properties();
final ListIterator<Properties> iterator = propertiesList.listIterator(propertiesList.size());
while (iterator.hasPrevious()) {
final Properties properties = iterator.previous();
ret.putAll(properties);
}
return ret;
}
List<Properties> lookForProperties(PropertiesPropertySource propertiesPropertySource, List<Properties> propertiesList) {
propertiesList.add(propertiesPropertySource.properties);
final PropertiesPropertySource parent = propertiesPropertySource.parent;
if (parent == null) {
return propertiesList;
}
return lookForProperties(parent, propertiesList);
}
synchronized void setProperty(String key, String value) {
properties.setProperty(key, value);
}
synchronized void addProperties(Properties source) {
properties.putAll(source);
} }
} }

View File

@ -1,119 +0,0 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.nacos.client.env;
import com.alibaba.nacos.client.constant.Constants;
import com.alibaba.nacos.client.env.convert.CompositeConverter;
import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;
class PropertySourceSearch {
private static final Logger LOGGER = LoggerFactory.getLogger(PropertySourceSearch.class);
private static final List<SourceType> DEFAULT_ORDER = Arrays.asList(SourceType.PROPERTIES, SourceType.JVM,
SourceType.SYS);
private final List<AbstractPropertySource> propertySources;
private final CompositeConverter converter;
private PropertySourceSearch(List<AbstractPropertySource> propertySources) {
this.propertySources = propertySources;
this.propertySources.add(new DefaultSettingPropertySource());
this.converter = new CompositeConverter();
}
static PropertySourceSearch build(Properties properties) {
if (properties == null) {
properties = new Properties();
}
PropertiesPropertySource customizePropertySource = new PropertiesPropertySource(properties);
JvmArgsPropertySource jvmArgsPropertySource = new JvmArgsPropertySource();
SystemEnvPropertySource systemEnvPropertySource = new SystemEnvPropertySource();
String searchPattern = jvmArgsPropertySource.getProperty(Constants.SysEnv.NACOS_ENVS_SEARCH);
if (StringUtils.isBlank(searchPattern)) {
searchPattern = systemEnvPropertySource.getProperty(Constants.SysEnv.NACOS_ENVS_SEARCH);
}
return resolve(searchPattern, customizePropertySource, jvmArgsPropertySource, systemEnvPropertySource);
}
private static PropertySourceSearch resolve(String pattern, AbstractPropertySource... propertySources) {
if (StringUtils.isBlank(pattern)) {
return createPropertySourceSearchWithDefaultOrder(propertySources);
}
try {
final SourceType sourceType = SourceType.valueOf(pattern.toUpperCase());
return createPropertySourceSearchByFirstType(sourceType, propertySources);
} catch (Exception e) {
LOGGER.error("first source type parse error, it will be use default order!");
return createPropertySourceSearchWithDefaultOrder(propertySources);
}
}
private static PropertySourceSearch createPropertySourceSearchWithDefaultOrder(AbstractPropertySource... propertySources) {
final Map<SourceType, AbstractPropertySource> sourceMap = Arrays.stream(propertySources)
.collect(Collectors.toMap(AbstractPropertySource::getType, propertySource -> propertySource));
final List<AbstractPropertySource> collect = DEFAULT_ORDER.stream().map(sourceMap::get).collect(Collectors.toList());
return new PropertySourceSearch(collect);
}
private static PropertySourceSearch createPropertySourceSearchByFirstType(SourceType firstType,
AbstractPropertySource... propertySources) {
List<SourceType> tempList = new ArrayList<>(4);
tempList.add(firstType);
final Map<SourceType, AbstractPropertySource> sourceMap = Arrays.stream(propertySources)
.collect(Collectors.toMap(AbstractPropertySource::getType, propertySource -> propertySource));
final List<AbstractPropertySource> collect = DEFAULT_ORDER.stream().filter(sourceType -> !sourceType.equals(firstType))
.collect(() -> tempList, List::add, List::addAll).stream().map(sourceMap::get)
.collect(Collectors.toList());
return new PropertySourceSearch(collect);
}
<T> Optional<T> search(String key, Class<T> targetType) {
if (targetType == null) {
throw new IllegalArgumentException("target type must be not null!");
}
for (AbstractPropertySource propertySource : propertySources) {
final String value = propertySource.getProperty(key);
if (value != null) {
if (String.class.isAssignableFrom(targetType)) {
return (Optional<T>) Optional.of(value);
}
return Optional.ofNullable(converter.convert(value, targetType));
}
}
return Optional.empty();
}
}

View File

@ -1,74 +0,0 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.nacos.client.env;
import java.util.Properties;
/**
* Searchable environment.
*
* @author onewe
*/
class SearchableEnvironment implements NacosEnvironment {
private final PropertySourceSearch sourceSearch;
SearchableEnvironment(Properties properties) {
this.sourceSearch = PropertySourceSearch.build(properties);
}
@Override
public String getProperty(String key) {
return getProperty(key, null);
}
@Override
public String getProperty(String key, String defaultValue) {
return sourceSearch.search(key, String.class).orElse(defaultValue);
}
@Override
public Boolean getBoolean(String key) {
return getBoolean(key, null);
}
@Override
public Boolean getBoolean(String key, Boolean defaultValue) {
return sourceSearch.search(key, Boolean.class).orElse(defaultValue);
}
@Override
public Integer getInteger(String key) {
return getInteger(key, null);
}
@Override
public Integer getInteger(String key, Integer defaultValue) {
return sourceSearch.search(key, Integer.class).orElse(defaultValue);
}
@Override
public Long getLong(String key) {
return getLong(key, null);
}
@Override
public Long getLong(String key, Long defaultValue) {
return sourceSearch.search(key, Long.class).orElse(defaultValue);
}
}

View File

@ -0,0 +1,236 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.nacos.client.env;
import com.alibaba.nacos.client.constant.Constants;
import com.alibaba.nacos.client.env.convert.CompositeConverter;
import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;
/**
* Searchable NacosClientProperties.
* the SearchableProperties that it can be specified search order by
* nacos.env.first
* @author onewe
*/
class SearchableProperties implements NacosClientProperties {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchableProperties.class);
private static final JvmArgsPropertySource JVM_ARGS_PROPERTY_SOURCE = new JvmArgsPropertySource();
private static final SystemEnvPropertySource SYSTEM_ENV_PROPERTY_SOURCE = new SystemEnvPropertySource();
private static final DefaultSettingPropertySource DEFAULT_SETTING_PROPERTY_SOURCE = new DefaultSettingPropertySource();
private static final List<SourceType> DEFAULT_ORDER = Arrays.asList(SourceType.PROPERTIES, SourceType.JVM,
SourceType.ENV, SourceType.DEFAULT_SETTING);
private static final CompositeConverter CONVERTER = new CompositeConverter();
static final SearchableProperties INSTANCE = new SearchableProperties();
private final List<AbstractPropertySource> propertySources;
private final PropertiesPropertySource propertiesPropertySource;
private SearchableProperties() {
this(new PropertiesPropertySource());
}
private SearchableProperties(PropertiesPropertySource propertiesPropertySource) {
this.propertiesPropertySource = propertiesPropertySource;
this.propertySources = build(propertiesPropertySource,
JVM_ARGS_PROPERTY_SOURCE, SYSTEM_ENV_PROPERTY_SOURCE, DEFAULT_SETTING_PROPERTY_SOURCE);
}
@Override
public String getProperty(String key) {
return getProperty(key, null);
}
@Override
public String getProperty(String key, String defaultValue) {
return this.search(key, String.class).orElse(defaultValue);
}
@Override
public Boolean getBoolean(String key) {
return getBoolean(key, null);
}
@Override
public Boolean getBoolean(String key, Boolean defaultValue) {
return this.search(key, Boolean.class).orElse(defaultValue);
}
@Override
public Integer getInteger(String key) {
return getInteger(key, null);
}
@Override
public Integer getInteger(String key, Integer defaultValue) {
return this.search(key, Integer.class).orElse(defaultValue);
}
@Override
public Long getLong(String key) {
return getLong(key, null);
}
@Override
public Long getLong(String key, Long defaultValue) {
return this.search(key, Long.class).orElse(defaultValue);
}
@Override
public void setProperty(String key, String value) {
propertiesPropertySource.setProperty(key, value);
}
@Override
public void addProperties(Properties properties) {
propertiesPropertySource.addProperties(properties);
}
@Override
public Properties asProperties() {
Properties properties = new Properties();
final ListIterator<AbstractPropertySource> iterator = propertySources.listIterator(
propertySources.size());
while (iterator.hasPrevious()) {
final AbstractPropertySource previous = iterator.previous();
properties.putAll(previous.asProperties());
}
return properties;
}
@Override
public boolean containsKey(String key) {
for (AbstractPropertySource propertySource : propertySources) {
final boolean containing = propertySource.containsKey(key);
if (containing) {
return true;
}
}
return false;
}
private <T> Optional<T> search(String key, Class<T> targetType) {
if (targetType == null) {
throw new IllegalArgumentException("target type must not be null!");
}
for (AbstractPropertySource propertySource : propertySources) {
final String value = propertySource.getProperty(key);
if (value != null) {
if (String.class.isAssignableFrom(targetType)) {
try {
return (Optional<T>) Optional.of(value);
} catch (Exception e) {
LOGGER.error("target type convert error", e);
return Optional.empty();
}
}
return Optional.ofNullable(CONVERTER.convert(value, targetType));
}
}
return Optional.empty();
}
private List<AbstractPropertySource> build(AbstractPropertySource... propertySources) {
String firstEnv = JVM_ARGS_PROPERTY_SOURCE.getProperty(Constants.SysEnv.NACOS_ENV_FIRST);
if (StringUtils.isBlank(firstEnv)) {
firstEnv = SYSTEM_ENV_PROPERTY_SOURCE.getProperty(Constants.SysEnv.NACOS_ENV_FIRST);
}
if (StringUtils.isBlank(firstEnv)) {
return sortPropertySourceDefaultOrder(propertySources);
}
try {
final SourceType sourceType = SourceType.valueOf(firstEnv.toUpperCase());
if (SourceType.DEFAULT_SETTING.equals(sourceType) || SourceType.PROPERTIES.equals(sourceType)) {
return sortPropertySourceDefaultOrder(propertySources);
}
return sortPropertySource(sourceType, propertySources);
} catch (Exception e) {
LOGGER.error("first source type parse error, it will be used default order!", e);
return sortPropertySourceDefaultOrder(propertySources);
}
}
private List<AbstractPropertySource> sortPropertySourceDefaultOrder(
AbstractPropertySource... propertySources) {
final Map<SourceType, AbstractPropertySource> sourceMap = Arrays.stream(propertySources)
.collect(Collectors.toMap(AbstractPropertySource::getType, propertySource -> propertySource));
final List<AbstractPropertySource> collect = DEFAULT_ORDER.stream().map(sourceMap::get)
.collect(Collectors.toList());
LOGGER.info("properties search order:PROPERTIES->JVM->ENV->DEFAULT_SETTING");
return collect;
}
private List<AbstractPropertySource> sortPropertySource(SourceType firstType,
AbstractPropertySource... propertySources) {
List<SourceType> tempList = new ArrayList<>(4);
tempList.add(firstType);
final Map<SourceType, AbstractPropertySource> sourceMap = Arrays.stream(propertySources)
.collect(Collectors.toMap(AbstractPropertySource::getType, propertySource -> propertySource));
final List<AbstractPropertySource> collect = DEFAULT_ORDER.stream()
.filter(sourceType -> !sourceType.equals(firstType)).collect(() -> tempList, List::add, List::addAll)
.stream().map(sourceMap::get).filter(Objects::nonNull).collect(Collectors.toList());
StringBuilder orderInfo = new StringBuilder("properties search order:");
for (int i = 0; i < collect.size(); i++) {
final AbstractPropertySource abstractPropertySource = collect.get(i);
orderInfo.append(abstractPropertySource.getType().toString());
if (i < collect.size() - 1) {
orderInfo.append("->");
}
}
LOGGER.info(orderInfo.toString());
return collect;
}
@Override
public NacosClientProperties derive() {
return new SearchableProperties(new PropertiesPropertySource(this.propertiesPropertySource));
}
@Override
public NacosClientProperties derive(Properties properties) {
final NacosClientProperties nacosClientProperties = this.derive();
nacosClientProperties.addProperties(properties);
return nacosClientProperties;
}
}

View File

@ -18,17 +18,17 @@ package com.alibaba.nacos.client.env;
enum SourceType { enum SourceType {
/** /**
* get value from system environment. * get value from properties.
*/ */
SYS, PROPERTIES,
/** /**
* get value from jvm args. * get value from jvm args.
*/ */
JVM, JVM,
/** /**
* get value from properties. * get value from system environment.
*/ */
PROPERTIES, ENV,
/** /**
* get value from default setting. * get value from default setting.
*/ */

View File

@ -17,18 +17,15 @@
package com.alibaba.nacos.client.env; package com.alibaba.nacos.client.env;
import java.util.Map; import java.util.Map;
import java.util.Properties;
class SystemEnvPropertySource extends AbstractPropertySource { class SystemEnvPropertySource extends AbstractPropertySource {
private final Map<String, String> env; private final Map<String, String> env = System.getenv();
SystemEnvPropertySource() {
this.env = System.getenv();
}
@Override @Override
SourceType getType() { SourceType getType() {
return SourceType.SYS; return SourceType.ENV;
} }
@Override @Override
@ -78,7 +75,15 @@ class SystemEnvPropertySource extends AbstractPropertySource {
return null; return null;
} }
private boolean containsKey(String name) { @Override
boolean containsKey(String name) {
return this.env.containsKey(name); return this.env.containsKey(name);
} }
@Override
Properties asProperties() {
Properties properties = new Properties();
properties.putAll(this.env);
return properties;
}
} }

View File

@ -0,0 +1,308 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.nacos.client.env;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Properties;
public class NacosClientPropertiesTest {
@BeforeClass
public static void init() {
System.setProperty("nacos.env.first", "jvm");
}
@AfterClass
public static void teardown() {
System.clearProperty("nacos.env.first");
}
@Test
public void testGetProperty() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.home", "/home/nacos");
final String value = NacosClientProperties.PROTOTYPE.getProperty("nacos.home");
Assert.assertEquals("/home/nacos", value);
}
@Test
public void testGetPropertyMultiLayer() {
NacosClientProperties.PROTOTYPE.setProperty("top.layer", "top");
final NacosClientProperties layerAEnv = NacosClientProperties.PROTOTYPE.derive();
layerAEnv.setProperty("a.layer", "a");
final NacosClientProperties layerBEnv = layerAEnv.derive();
layerBEnv.setProperty("b.layer", "b");
final NacosClientProperties layerCEnv = layerBEnv.derive();
layerCEnv.setProperty("c.layer", "c");
String value = layerCEnv.getProperty("c.layer");
Assert.assertEquals("c", value);
value = layerCEnv.getProperty("b.layer");
Assert.assertEquals("b", value);
value = layerCEnv.getProperty("a.layer");
Assert.assertEquals("a", value);
value = layerCEnv.getProperty("top.layer");
Assert.assertEquals("top", value);
}
@Test
public void testGetPropertyDefaultValue() {
final String value = NacosClientProperties.PROTOTYPE.getProperty("nacos.home.default", "/home/default_value");
Assert.assertEquals("/home/default_value", value);
}
@Test
public void testGetBoolean() {
NacosClientProperties.PROTOTYPE.setProperty("use.cluster", "true");
final Boolean value = NacosClientProperties.PROTOTYPE.getBoolean("use.cluster");
Assert.assertTrue(value);
}
@Test
public void testGetBooleanDefaultValue() {
final Boolean value = NacosClientProperties.PROTOTYPE.getBoolean("use.cluster.default", false);
Assert.assertFalse(value);
}
@Test
public void testGetInteger() {
NacosClientProperties.PROTOTYPE.setProperty("max.timeout", "200");
final Integer value = NacosClientProperties.PROTOTYPE.getInteger("max.timeout");
Assert.assertEquals(200, value.intValue());
}
@Test
public void testGetIntegerDefaultValue() {
final Integer value = NacosClientProperties.PROTOTYPE.getInteger("max.timeout.default", 400);
Assert.assertEquals(400, value.intValue());
}
@Test
public void testGetLong() {
NacosClientProperties.PROTOTYPE.setProperty("connection.timeout", "200");
final Long value = NacosClientProperties.PROTOTYPE.getLong("connection.timeout");
Assert.assertEquals(200L, value.longValue());
}
@Test
public void testGetLongDefault() {
final Long value = NacosClientProperties.PROTOTYPE.getLong("connection.timeout.default", 400L);
Assert.assertEquals(400L, value.longValue());
}
@Test
public void testGetPropertyDefaultSetting() {
final String value = NacosClientProperties.PROTOTYPE.getProperty("nacos.home.default.test");
Assert.assertEquals("/home/default_setting", value);
}
@Test
public void setProperty() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.set.property", "true");
final String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.set.property");
Assert.assertEquals("true", ret);
}
@Test
public void setPropertyWithScope() {
final NacosClientProperties properties = NacosClientProperties.PROTOTYPE.derive();
properties.setProperty("nacos.set.property.scope", "config");
String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.set.property.scope");
Assert.assertNull(ret);
ret = properties.getProperty("nacos.set.property.scope");
Assert.assertEquals("config", ret);
}
@Test
public void testAddProperties() {
Properties properties = new Properties();
properties.setProperty("nacos.add.properties", "true");
NacosClientProperties.PROTOTYPE.addProperties(properties);
final String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.add.properties");
Assert.assertEquals("true", ret);
}
@Test
public void testAddPropertiesWithScope() {
Properties properties = new Properties();
properties.setProperty("nacos.add.properties.scope", "config");
final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive();
nacosClientProperties.addProperties(properties);
String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.add.properties.scope");
Assert.assertNull(ret);
ret = nacosClientProperties.getProperty("nacos.add.properties.scope");
Assert.assertEquals("config", ret);
}
@Test
public void testTestDerive() {
Properties properties = new Properties();
properties.setProperty("nacos.derive.properties.scope", "derive");
final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(properties);
final String value = nacosClientProperties.getProperty("nacos.derive.properties.scope");
Assert.assertEquals("derive", value);
}
@Test
public void testContainsKey() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.contains.key", "true");
boolean ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.key");
Assert.assertTrue(ret);
ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.key.in.sys");
Assert.assertFalse(ret);
}
@Test
public void testContainsKeyMultiLayers() {
NacosClientProperties.PROTOTYPE.setProperty("top.layer", "top");
final NacosClientProperties layerAEnv = NacosClientProperties.PROTOTYPE.derive();
layerAEnv.setProperty("a.layer", "a");
final NacosClientProperties layerBEnv = layerAEnv.derive();
layerBEnv.setProperty("b.layer", "b");
final NacosClientProperties layerCEnv = layerBEnv.derive();
layerCEnv.setProperty("c.layer", "c");
boolean exist = layerCEnv.containsKey("c.layer");
Assert.assertTrue(exist);
exist = layerCEnv.containsKey("b.layer");
Assert.assertTrue(exist);
exist = layerCEnv.containsKey("a.layer");
Assert.assertTrue(exist);
exist = layerCEnv.containsKey("top.layer");
Assert.assertTrue(exist);
}
@Test
public void testContainsKeyWithScope() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.contains.global.scope", "global");
final NacosClientProperties namingProperties = NacosClientProperties.PROTOTYPE.derive();
namingProperties.setProperty("nacos.contains.naming.scope", "naming");
boolean ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.global.scope");
Assert.assertTrue(ret);
ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.naming.scope");
Assert.assertFalse(ret);
ret = namingProperties.containsKey("nacos.contains.naming.scope");
Assert.assertTrue(ret);
ret = namingProperties.containsKey("nacos.contains.global.scope");
Assert.assertTrue(ret);
}
@Test
public void testAsProperties() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.as.properties", "true");
final Properties properties = NacosClientProperties.PROTOTYPE.asProperties();
Assert.assertNotNull(properties);
Assert.assertEquals("true", properties.getProperty("nacos.as.properties"));
}
@Test
public void testAsPropertiesWithScope() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.as.properties.global.scope", "global");
NacosClientProperties.PROTOTYPE.setProperty("nacos.server.addr.scope", "global");
final NacosClientProperties configProperties = NacosClientProperties.PROTOTYPE.derive();
configProperties.setProperty("nacos.server.addr.scope", "config");
final Properties properties = configProperties.asProperties();
Assert.assertNotNull(properties);
String ret = properties.getProperty("nacos.as.properties.global.scope");
Assert.assertEquals("global", ret);
ret = properties.getProperty("nacos.server.addr.scope");
Assert.assertEquals("config", ret);
}
@Test
public void testGetPropertyWithScope() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.global.scope", "global");
final NacosClientProperties configProperties = NacosClientProperties.PROTOTYPE.derive();
configProperties.setProperty("nacos.config.scope", "config");
final NacosClientProperties namingProperties = NacosClientProperties.PROTOTYPE.derive();
namingProperties.setProperty("nacos.naming.scope", "naming");
String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.global.scope");
Assert.assertEquals("global", ret);
ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.config.scope");
Assert.assertNull(ret);
ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.naming.scope");
Assert.assertNull(ret);
ret = configProperties.getProperty("nacos.config.scope");
Assert.assertEquals("config", ret);
ret = configProperties.getProperty("nacos.global.scope");
Assert.assertEquals("global", ret);
ret = configProperties.getProperty("nacos.naming.scope");
Assert.assertNull(ret);
ret = namingProperties.getProperty("nacos.naming.scope");
Assert.assertEquals("naming", ret);
ret = namingProperties.getProperty("nacos.global.scope");
Assert.assertEquals("global", ret);
ret = namingProperties.getProperty("nacos.config.scope");
Assert.assertNull(ret);
}
}

View File

@ -1,50 +0,0 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.nacos.client.env;
import org.junit.Assert;
import org.junit.Test;
import java.lang.reflect.Proxy;
import java.util.Properties;
public class NacosEnvironmentFactoryTest {
@Test(expected = IllegalStateException.class)
public void testCreateEnvironment() {
final NacosEnvironment environment = NacosEnvironmentFactory.createEnvironment();
Assert.assertNotNull(environment);
Assert.assertTrue(Proxy.isProxyClass(environment.getClass()));
environment.getProperty("test.exception");
}
@Test
public void testNacosEnvInit() {
final NacosEnvironment environment = NacosEnvironmentFactory.createEnvironment();
final NacosEnvironmentFactory.NacosEnvironmentDelegate invocationHandler =
(NacosEnvironmentFactory.NacosEnvironmentDelegate) Proxy.getInvocationHandler(
environment);
Properties properties = new Properties();
properties.setProperty("init.nacos", "true");
invocationHandler.init(properties);
final String property = environment.getProperty("init.nacos");
Assert.assertEquals("true", property);
}
}

View File

@ -1,174 +0,0 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.nacos.client.env;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Properties;
public class NacosEnvsTest {
static MockedStatic<NacosEnvironmentFactory> mockedStatic;
@BeforeClass
public static void before() {
mockedStatic = Mockito.mockStatic(NacosEnvironmentFactory.class);
mockedStatic.when(NacosEnvironmentFactory::createEnvironment).thenReturn(createProxy());
}
@AfterClass
public static void teardown() {
if (mockedStatic != null) {
mockedStatic.close();
}
}
private static NacosEnvironment createProxy() {
return (NacosEnvironment) Proxy.newProxyInstance(NacosEnvironmentFactory.class.getClassLoader(),
new Class[] {NacosEnvironment.class}, new NacosEnvironmentFactory.NacosEnvironmentDelegate() {
volatile NacosEnvironment environment;
@Override
public void init(Properties properties) {
environment = new SearchableEnvironment(properties);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (environment == null) {
throw new IllegalStateException(
"Nacos environment doesn't init, please call NEnvs#init method then try it again.");
}
return method.invoke(environment, args);
}
});
}
@Test
public void testGetProperty() {
final Properties properties = new Properties();
properties.setProperty("nacos.home", "/home/nacos");
NacosEnvs.init(properties);
final String value = NacosEnvs.getProperty("nacos.home");
Assert.assertEquals("/home/nacos", value);
}
@Test
public void testGetPropertyDefaultValue() {
final Properties properties = new Properties();
NacosEnvs.init(properties);
final String value = NacosEnvs.getProperty("nacos.home", "/home/default_value");
Assert.assertEquals("/home/default_value", value);
}
@Test
public void testGetBoolean() {
final Properties properties = new Properties();
properties.setProperty("use.cluster", "true");
NacosEnvs.init(properties);
final Boolean value = NacosEnvs.getBoolean("use.cluster");
Assert.assertTrue(value);
}
@Test
public void testGetBooleanDefaultValue() {
final Properties properties = new Properties();
NacosEnvs.init(properties);
final Boolean value = NacosEnvs.getBoolean("use.cluster", false);
Assert.assertFalse(value);
}
@Test
public void testGetInteger() {
final Properties properties = new Properties();
properties.setProperty("max.timeout", "200");
NacosEnvs.init(properties);
final Integer value = NacosEnvs.getInteger("max.timeout");
Assert.assertEquals(200, value.intValue());
}
@Test
public void testGetIntegerDefaultValue() {
final Properties properties = new Properties();
NacosEnvs.init(properties);
final Integer value = NacosEnvs.getInteger("max.timeout", 400);
Assert.assertEquals(400, value.intValue());
}
@Test
public void testGetLong() {
final Properties properties = new Properties();
properties.setProperty("connection.timeout", "200");
NacosEnvs.init(properties);
final Long value = NacosEnvs.getLong("connection.timeout");
Assert.assertEquals(200L, value.longValue());
}
@Test
public void testGetLongDefault() {
final Properties properties = new Properties();
NacosEnvs.init(properties);
final Long value = NacosEnvs.getLong("connection.timeout", 400L);
Assert.assertEquals(400L, value.longValue());
}
@Test
public void testGetPropertyJvmFirst() {
System.setProperty("nacos.envs.search", "jvm");
System.setProperty("nacos.home", "/home/jvm_first");
Properties properties = new Properties();
properties.setProperty("nacos.home", "/home/properties_first");
NacosEnvs.init(properties);
final String value = NacosEnvs.getProperty("nacos.home");
Assert.assertEquals("/home/jvm_first", value);
System.clearProperty("nacos.envs.search");
System.clearProperty("nacos.home");
}
@Test
public void testGetPropertyDefaultSetting() {
Properties properties = new Properties();
NacosEnvs.init(properties);
final String value = NacosEnvs.getProperty("nacos.home.default.test");
Assert.assertEquals("/home/default_setting", value);
}
}