Merge pull request #135 from pbting/master

Nacos Config Support multi DataIds
pull/898/head
xiaojing 6 years ago committed by GitHub
commit f3a79612f3

@ -16,15 +16,8 @@
package org.springframework.cloud.alibaba.nacos;
import java.util.Arrays;
import java.util.Objects;
import java.util.Properties;
import javax.annotation.PostConstruct;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -32,20 +25,20 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.env.Environment;
import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
import static com.alibaba.nacos.api.PropertyKeyConst.CONTEXT_PATH;
import static com.alibaba.nacos.api.PropertyKeyConst.ENCODE;
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import static com.alibaba.nacos.api.PropertyKeyConst.*;
/**
* nacos properties
*
* @author leijuan
* @author xiaojing
* @author pbting
*/
@ConfigurationProperties("spring.cloud.nacos.config")
public class NacosConfigProperties {
@ -118,6 +111,22 @@ public class NacosConfigProperties {
private String[] activeProfiles;
/**
* the dataids for configurable multiple shared configurations , multiple separated by
* commas .
*/
private String sharedDataids;
/**
* refreshable dataids , multiple separated by commas .
*/
private String refreshableDataids;
/**
* a set of extended configurations .
*/
private List<Config> extConfig;
private ConfigService configService;
@Autowired
@ -234,10 +243,66 @@ public class NacosConfigProperties {
return activeProfiles;
}
public String getSharedDataids() {
return sharedDataids;
}
public void setSharedDataids(String sharedDataids) {
this.sharedDataids = sharedDataids;
}
public String getRefreshableDataids() {
return refreshableDataids;
}
public void setRefreshableDataids(String refreshableDataids) {
this.refreshableDataids = refreshableDataids;
}
public List<Config> getExtConfig() {
return extConfig;
}
public void setExtConfig(List<Config> extConfig) {
this.extConfig = extConfig;
}
public static class Config {
private String dataId;
private String group = "DEFAULT_GROUP";
private boolean refresh = false;
public String getDataId() {
return dataId;
}
public void setDataId(String dataId) {
this.dataId = dataId;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public boolean isRefresh() {
return refresh;
}
public void setRefresh(boolean refresh) {
this.refresh = refresh;
}
}
@Override
public String toString() {
return "NacosConfigProperties{" + "serverAddr='" + serverAddr + '\''
+ ", encode='" + encode + '\'' + ", group='" + group + '\'' + ", prefix='"
+ ", encode='" + encode + '\'' + ", group='" + group + '\''
+ ", sharedDataids='" + this.sharedDataids + '\''
+ ", refreshableDataids='" + this.refreshableDataids + '\'' + ", prefix='"
+ prefix + '\'' + ", fileExtension='" + fileExtension + '\''
+ ", timeout=" + timeout + ", endpoint='" + endpoint + '\''
+ ", namespace='" + namespace + '\'' + ", accessKey='" + accessKey + '\''

@ -16,16 +16,22 @@
package org.springframework.cloud.alibaba.nacos.client;
import org.springframework.core.env.MapPropertySource;
import java.util.Date;
import java.util.Map;
import org.springframework.core.env.MapPropertySource;
/**
* @author xiaojing
* @author pbting
*/
public class NacosPropertySource extends MapPropertySource {
/**
* Nacos Group
*/
private final String group;
/**
* Nacos dataID
*/
@ -36,11 +42,22 @@ public class NacosPropertySource extends MapPropertySource {
*/
private final Date timestamp;
/**
* Whether to support dynamic refresh for this Property Source
*/
private final boolean isRefreshable;
NacosPropertySource(String dataId, Map<String, Object> source, Date timestamp) {
NacosPropertySource(String group, String dataId, Map<String, Object> source,
Date timestamp, boolean isRefreshable) {
super(dataId, source);
this.group = group;
this.dataId = dataId;
this.timestamp = timestamp;
this.isRefreshable = isRefreshable;
}
public String getGroup() {
return this.group;
}
public String getDataId() {
@ -51,4 +68,7 @@ public class NacosPropertySource extends MapPropertySource {
return timestamp;
}
public boolean isRefreshable() {
return isRefreshable;
}
}

@ -16,24 +16,20 @@
package org.springframework.cloud.alibaba.nacos.client;
import java.io.StringReader;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.util.StringUtils;
import java.io.StringReader;
import java.util.*;
/**
* @author xiaojing
* @author pbting
*/
public class NacosPropertySourceBuilder {
@ -71,12 +67,14 @@ public class NacosPropertySourceBuilder {
* @param dataId Nacos dataId
* @param group Nacos group
*/
NacosPropertySource build(String dataId, String group, String fileExtension) {
NacosPropertySource build(String dataId, String group, String fileExtension,
boolean isRefreshable) {
Properties p = loadNacosData(dataId, group, fileExtension);
if (p == null) {
return null;
}
return new NacosPropertySource(dataId, propertiesToMap(p), new Date());
return new NacosPropertySource(group, dataId, propertiesToMap(p), new Date(),
isRefreshable);
}
private Properties loadNacosData(String dataId, String group, String fileExtension) {

@ -16,6 +16,7 @@
package org.springframework.cloud.alibaba.nacos.client;
import com.alibaba.nacos.api.config.ConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -26,8 +27,8 @@ import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.util.StringUtils;
import com.alibaba.nacos.api.config.ConfigService;
import java.util.Arrays;
import java.util.List;
/**
* @author xiaojing
@ -40,6 +41,9 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
private static final String NACOS_PROPERTY_SOURCE_NAME = "NACOS";
private static final String SEP1 = "-";
private static final String DOT = ".";
private static final String SHARED_CONFIG_SEPRATOR_CHAR = "[,]";
private static final List<String> SUPPORT_FILE_EXTENSION = Arrays.asList("properties",
"yaml", "yml");
@Autowired
private NacosConfigProperties nacosConfigProperties;
@ -73,29 +77,123 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
CompositePropertySource composite = new CompositePropertySource(
NACOS_PROPERTY_SOURCE_NAME);
loadSharedConfiguration(composite);
loadExtConfiguration(composite);
loadApplicationConfiguration(composite, nacosGroup, dataIdPrefix, fileExtension);
return composite;
}
private void loadSharedConfiguration(
CompositePropertySource compositePropertySource) {
String sharedDataIds = nacosConfigProperties.getSharedDataids();
String refreshDataIds = nacosConfigProperties.getRefreshableDataids();
if (sharedDataIds == null || sharedDataIds.trim().length() == 0) {
return;
}
String[] sharedDataIdArry = sharedDataIds.split(SHARED_CONFIG_SEPRATOR_CHAR);
checkDataIdFileExtension(sharedDataIdArry);
for (int i = 0; i < sharedDataIdArry.length; i++) {
String dataId = sharedDataIdArry[i];
String fileExtension = dataId.substring(dataId.lastIndexOf(".") + 1);
boolean isRefreshable = checkDataIdIsRefreshbable(refreshDataIds,
sharedDataIdArry[i]);
loadNacosDataIfPresent(compositePropertySource, dataId, "DEFAULT_GROUP",
fileExtension, isRefreshable);
}
}
private void loadExtConfiguration(CompositePropertySource compositePropertySource) {
if (nacosConfigProperties.getExtConfig() == null
|| nacosConfigProperties.getExtConfig().isEmpty()) {
return;
}
List<NacosConfigProperties.Config> extConfigs = nacosConfigProperties
.getExtConfig();
checkExtConfiguration(extConfigs);
for (NacosConfigProperties.Config config : extConfigs) {
String dataId = config.getDataId();
String fileExtension = dataId.substring(dataId.lastIndexOf(".") + 1);
loadNacosDataIfPresent(compositePropertySource, dataId, config.getGroup(),
fileExtension, config.isRefresh());
}
}
private void checkExtConfiguration(List<NacosConfigProperties.Config> extConfigs) {
String[] dataIds = new String[extConfigs.size()];
for (int i = 0; i < extConfigs.size(); i++) {
String dataId = extConfigs.get(i).getDataId();
if (dataId == null || dataId.trim().length() == 0) {
throw new IllegalStateException(String.format(
"the [ spring.cloud.nacos.config.ext-config[%s] ] must give a dataid",
i));
}
dataIds[i] = dataId;
}
checkDataIdFileExtension(dataIds);
}
private void loadApplicationConfiguration(
CompositePropertySource compositePropertySource, String nacosGroup,
String dataIdPrefix, String fileExtension) {
loadNacosDataIfPresent(compositePropertySource,
dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension);
dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true);
for (String profile : nacosConfigProperties.getActiveProfiles()) {
String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension;
loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
fileExtension);
fileExtension, true);
}
}
private void loadNacosDataIfPresent(final CompositePropertySource composite,
final String dataId, final String group, String fileExtension) {
final String dataId, final String group, String fileExtension,
boolean isRefreshable) {
NacosPropertySource ps = nacosPropertySourceBuilder.build(dataId, group,
fileExtension);
fileExtension, isRefreshable);
if (ps != null) {
composite.addFirstPropertySource(ps);
}
}
private static void checkDataIdFileExtension(String[] sharedDataIdArry) {
StringBuilder stringBuilder = new StringBuilder();
outline: for (int i = 0; i < sharedDataIdArry.length; i++) {
for (String fileExtension : SUPPORT_FILE_EXTENSION) {
if (sharedDataIdArry[i].indexOf(fileExtension) > 0) {
continue outline;
}
}
stringBuilder.append(sharedDataIdArry[i] + ",");
}
if (stringBuilder.length() > 0) {
String result = stringBuilder.substring(0, stringBuilder.length() - 1);
throw new IllegalStateException(String.format(
"[%s] must contains file extension with properties|yaml|yml",
result));
}
}
private boolean checkDataIdIsRefreshbable(String refreshDataIds,
String sharedDataId) {
if (refreshDataIds == null || "".equals(refreshDataIds)) {
return false;
}
String[] refreshDataIdArry = refreshDataIds.split(SHARED_CONFIG_SEPRATOR_CHAR);
for (String refreshDataId : refreshDataIdArry) {
if (refreshDataId.equals(sharedDataId)) {
return true;
}
}
return false;
}
}

@ -16,14 +16,9 @@
package org.springframework.cloud.alibaba.nacos.refresh;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
@ -34,9 +29,13 @@ import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.context.ApplicationListener;
import org.springframework.util.StringUtils;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
/**
* On application start up, NacosContextRefresher add nacos listeners to all application
@ -44,6 +43,7 @@ import com.alibaba.nacos.api.exception.NacosException;
* configurations.
*
* @author juven.xuxb
* @author pbting
*/
public class NacosContextRefresher implements ApplicationListener<ApplicationReadyEvent> {
@ -61,7 +61,7 @@ public class NacosContextRefresher implements ApplicationListener<ApplicationRea
private final ConfigService configService;
private Map<String,Listener> listenerMap = new ConcurrentHashMap<>(16);
private Map<String, Listener> listenerMap = new ConcurrentHashMap<>(16);
public NacosContextRefresher(ContextRefresher contextRefresher,
NacosConfigProperties properties, NacosRefreshProperties refreshProperties,
@ -85,13 +85,17 @@ public class NacosContextRefresher implements ApplicationListener<ApplicationRea
if (refreshProperties.isEnabled()) {
for (NacosPropertySource nacosPropertySource : nacosPropertySourceRepository
.getAll()) {
if (!nacosPropertySource.isRefreshable()) {
continue;
}
String dataId = nacosPropertySource.getDataId();
registerNacosListener(dataId);
registerNacosListener(nacosPropertySource.getGroup(), dataId);
}
}
}
private void registerNacosListener(final String dataId) {
private void registerNacosListener(final String group, final String dataId) {
Listener listener = listenerMap.computeIfAbsent(dataId, i -> new Listener() {
@Override
@ -101,9 +105,10 @@ public class NacosContextRefresher implements ApplicationListener<ApplicationRea
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md5 = new BigInteger(1, md.digest(configInfo.getBytes("UTF-8")))
.toString(16);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
logger.warn("unable to get md5 for dataId: " + dataId, e);
.toString(16);
}
catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
logger.warn("[Nacos] unable to get md5 for dataId: " + dataId, e);
}
}
refreshHistory.add(dataId, md5);
@ -117,8 +122,9 @@ public class NacosContextRefresher implements ApplicationListener<ApplicationRea
});
try {
configService.addListener(dataId, properties.getGroup(), listener);
} catch (NacosException e) {
configService.addListener(dataId, group, listener);
}
catch (NacosException e) {
e.printStackTrace();
}
}

@ -16,6 +16,8 @@
package org.springframework.cloud.alibaba.nacos;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -24,9 +26,6 @@ import org.springframework.cloud.client.discovery.DiscoveryClient;
import java.util.*;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
/**
* @author xiaojing
* @author renhaojun

@ -16,6 +16,9 @@
package org.springframework.cloud.alibaba.nacos;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -24,29 +27,14 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.*;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
import static com.alibaba.nacos.api.PropertyKeyConst.*;
/**
* @author dungu.zpf
@ -96,6 +84,11 @@ public class NacosDiscoveryProperties {
*/
private String clusterName = "DEFAULT";
/**
* naming load from local cache at application start. true is load
*/
private String namingLoadCacheAtStart = "false";
/**
* extra metadata to register.
*/
@ -313,7 +306,15 @@ public class NacosDiscoveryProperties {
this.secretKey = secretKey;
}
@Override
public String getNamingLoadCacheAtStart() {
return namingLoadCacheAtStart;
}
public void setNamingLoadCacheAtStart(String namingLoadCacheAtStart) {
this.namingLoadCacheAtStart = namingLoadCacheAtStart;
}
@Override
public String toString() {
return "NacosDiscoveryProperties{" + "serverAddr='" + serverAddr + '\''
+ ", endpoint='" + endpoint + '\'' + ", namespace='" + namespace + '\''
@ -322,7 +323,7 @@ public class NacosDiscoveryProperties {
+ ", metadata=" + metadata + ", registerEnabled=" + registerEnabled
+ ", ip='" + ip + '\'' + ", networkInterface='" + networkInterface + '\''
+ ", port=" + port + ", secure=" + secure + ", accessKey='" + accessKey
+ '\'' + ", secretKey='" + secretKey + '\'' + '}';
+ ", namingLoadCacheAtStart=" + namingLoadCacheAtStart + '\'' + ", secretKey='" + secretKey + '\'' + '}';
}
public void overrideFromEnv(Environment env) {
@ -371,6 +372,8 @@ public class NacosDiscoveryProperties {
properties.put(ACCESS_KEY, accessKey);
properties.put(SECRET_KEY, secretKey);
properties.put(CLUSTER_NAME, clusterName);
properties.put(NAMING_LOAD_CACHE_AT_START,namingLoadCacheAtStart);
try {
namingService = NacosFactory.createNamingService(properties);
return namingService;

@ -16,15 +16,13 @@
package org.springframework.cloud.alibaba.nacos.registry;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.StringUtils;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Cluster;
import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* @author xiaojing
*/

@ -16,12 +16,11 @@
package org.springframework.cloud.alibaba.nacos.ribbon;
import java.util.Map;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.loadbalancer.Server;
import java.util.Map;
/**
* @author xiaojing
*/

@ -4,5 +4,11 @@
"type": "java.lang.String",
"defaultValue": "${spring.application.name}",
"description": "the service name to register, default value is ${spring.application.name}."
},
{
"name": "spring.cloud.nacos.discovery.namingLoadCacheAtStart",
"type": "java.lang.Boolean",
"defaultValue": "false",
"description": "naming load from local cache at application start ."
}
]}

@ -0,0 +1,40 @@
package org.springframework.cloud.alicloud.context.nacos;
import com.alibaba.cloud.context.edas.EdasChangeOrderConfiguration;
import com.alibaba.cloud.context.edas.EdasChangeOrderConfigurationFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
public class NacosParameterInitListener
implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
private static final Logger log = LoggerFactory
.getLogger(NacosParameterInitListener.class);
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
preparedNacosConfiguration();
}
private void preparedNacosConfiguration() {
EdasChangeOrderConfiguration edasChangeOrderConfiguration = EdasChangeOrderConfigurationFactory
.buildEdasChangeOrderConfiguration();
log.info("Initialize Nacos Parameter from edas change order,is edas managed {}.",
edasChangeOrderConfiguration.isEdasManaged());
if (!edasChangeOrderConfiguration.isEdasManaged()) {
return;
}
// initialize nacos configuration
System.getProperties().setProperty("spring.cloud.nacos.config.server-addr", "");
System.getProperties().setProperty("spring.cloud.nacos.config.endpoint",
edasChangeOrderConfiguration.getAddressServerDomain());
System.getProperties().setProperty("spring.cloud.nacos.config.namespace",
edasChangeOrderConfiguration.getTenantId());
System.getProperties().setProperty("spring.cloud.nacos.config.access-key",
edasChangeOrderConfiguration.getDauthAccessKey());
System.getProperties().setProperty("spring.cloud.nacos.config.secret-key",
edasChangeOrderConfiguration.getDauthSecretKey());
}
}

@ -6,4 +6,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alicloud.context.ans.AnsContextAutoConfiguration,\
org.springframework.cloud.alicloud.context.oss.OssContextAutoConfiguration
org.springframework.context.ApplicationListener=\
org.springframework.cloud.alicloud.context.ans.AnsContextApplicationListener
org.springframework.cloud.alicloud.context.ans.AnsContextApplicationListener,\
org.springframework.cloud.alicloud.context.nacos.NacosParameterInitListener
Loading…
Cancel
Save