Skip to content

Commit

Permalink
[SCB-2813]Nacos dynamic properties support and improvement (#3984)
Browse files Browse the repository at this point in the history
  • Loading branch information
liubao68 authored Oct 23, 2023
1 parent 4a1da76 commit c1ddf4a
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 282 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,126 +17,246 @@

package org.apache.servicecomb.config.nacos;

import static org.apache.servicecomb.config.nacos.ConfigurationAction.CREATE;
import static org.apache.servicecomb.config.nacos.ConfigurationAction.DELETE;
import static org.apache.servicecomb.config.nacos.ConfigurationAction.SET;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;

import org.apache.commons.lang3.StringUtils;
import org.apache.servicecomb.config.BootStrapProperties;
import org.apache.servicecomb.config.nacos.NacosDynamicPropertiesSource.UpdateHandler;
import org.apache.servicecomb.config.parser.Parser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;

public class NacosClient {
private final UpdateHandler updateHandler;

private final NacosConfig nacosConfig;

private static final Logger LOGGER = LoggerFactory.getLogger(NacosClient.class);
private final Environment environment;

private static final Map<String, Object> originalConfigMap = new ConcurrentHashMap<>();
private final Object lock = new Object();

private final UpdateHandler updateHandler;
private Map<String, Object> application = new HashMap<>();

private final NacosConfig nacosConfig;
private Map<String, Object> service = new HashMap<>();

private Map<String, Object> version = new HashMap<>();

private Map<String, Object> profile = new HashMap<>();

private Map<String, Object> custom = new HashMap<>();

private Map<String, Object> allLast = new HashMap<>();

public NacosClient(UpdateHandler updateHandler, Environment environment) {
this.updateHandler = updateHandler;
this.nacosConfig = new NacosConfig(environment);
this.environment = environment;
}

public void refreshNacosConfig() {
new ConfigRefresh().refreshConfig();
public void refreshNacosConfig() throws NacosException {
Properties properties = nacosProperties(environment, nacosConfig);

ConfigService configService = NacosFactory.createConfigService(properties);
addApplicationConfig(configService);
addServiceConfig(configService);
addVersionConfig(configService);
addProfileConfig(configService);
addCustomConfig(configService);

refreshConfigItems();
}

class ConfigRefresh {
Parser contentParser = Parser.findParser(nacosConfig.getContentType());
private void addApplicationConfig(ConfigService configService) throws NacosException {
String content = configService.getConfig(BootStrapProperties.readApplication(environment),
BootStrapProperties.readApplication(environment), 5000);
processApplicationConfig(content);
configService.addListener(BootStrapProperties.readApplication(environment),
BootStrapProperties.readApplication(environment), new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
processApplicationConfig(configInfo);
refreshConfigItems();
}

String keyPrefix = nacosConfig.getGroup() + "." +
nacosConfig.getDataId();
@Override
public Executor getExecutor() {
return null;
}
});
}

ConfigRefresh() {
private void processApplicationConfig(String content) {
if (StringUtils.isEmpty(content)) {
this.application = new HashMap<>();
return;
}
Parser contentParser = Parser.findParser("yaml");
this.application = contentParser.parse(content, "", false);
}

private void addServiceConfig(ConfigService configService) throws NacosException {
String content = configService.getConfig(BootStrapProperties.readServiceName(environment),
BootStrapProperties.readApplication(environment),
5000);
processServiceConfig(content);
configService.addListener(BootStrapProperties.readServiceName(environment),
BootStrapProperties.readApplication(environment), new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
processServiceConfig(configInfo);
refreshConfigItems();
}

@SuppressWarnings("unchecked")
void refreshConfig() {
Properties properties = new Properties();
properties.put("serverAddr", nacosConfig.getServerAddr());
properties.put("namespace", nacosConfig.getNameSpace());

try {
ConfigService configService = NacosFactory.createConfigService(properties);
String content = configService.getConfig(nacosConfig.getDataId(),
nacosConfig.getGroup(), 5000);
processContent(content);
configService.addListener(nacosConfig.getDataId(),
nacosConfig.getGroup(), new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
LOGGER.info("receive from nacos:" + configInfo);
processContent(configInfo);
}

@Override
public Executor getExecutor() {
return null;
}
});
} catch (Exception e) {
LOGGER.error("Receive nacos config error: ", e);
}
@Override
public Executor getExecutor() {
return null;
}
});
}

private void processServiceConfig(String content) {
if (StringUtils.isEmpty(content)) {
this.service = new HashMap<>();
return;
}
Parser contentParser = Parser.findParser("yaml");
this.service = contentParser.parse(content, "", false);
}

private void processContent(String content) {
if (StringUtils.isEmpty(content)) {
return;
}
private void addVersionConfig(ConfigService configService) throws NacosException {
String content = configService.getConfig(
BootStrapProperties.readServiceName(environment) + "-" +
BootStrapProperties.readServiceVersion(environment),
BootStrapProperties.readApplication(environment),
5000);
processVersionConfig(content);
configService.addListener(BootStrapProperties.readServiceName(environment) + "-" +
BootStrapProperties.readServiceVersion(environment),
BootStrapProperties.readApplication(environment), new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
processVersionConfig(configInfo);
refreshConfigItems();
}

@Override
public Executor getExecutor() {
return null;
}
});
}

refreshConfigItems(contentParser.parse(content, keyPrefix, nacosConfig.getAddPrefix()));
private void processVersionConfig(String content) {
if (StringUtils.isEmpty(content)) {
this.version = new HashMap<>();
return;
}
Parser contentParser = Parser.findParser("yaml");
this.version = contentParser.parse(content, "", false);
}

private void addProfileConfig(ConfigService configService) throws NacosException {
String profile = environment.getProperty("spring.profiles.active");
if (StringUtils.isEmpty(profile)) {
return;
}
String content = configService.getConfig(BootStrapProperties.readServiceName(environment) + "-" + profile,
BootStrapProperties.readApplication(environment), 5000);
processProfileConfig(content);
configService.addListener(BootStrapProperties.readServiceName(environment) + "-" + profile,
BootStrapProperties.readApplication(environment), new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
processProfileConfig(configInfo);
refreshConfigItems();
}

@Override
public Executor getExecutor() {
return null;
}
});
}

private void processProfileConfig(String content) {
if (StringUtils.isEmpty(content)) {
this.profile = new HashMap<>();
return;
}
Parser contentParser = Parser.findParser("yaml");
this.profile = contentParser.parse(content, "", false);
}

private void addCustomConfig(ConfigService configService) throws NacosException {
if (StringUtils.isEmpty(nacosConfig.getDataId()) || StringUtils.isEmpty(nacosConfig.getGroup())) {
return;
}
String content = configService.getConfig(nacosConfig.getDataId(),
nacosConfig.getGroup(), 5000);
processCustomConfig(content);
configService.addListener(nacosConfig.getDataId(),
nacosConfig.getGroup(), new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
processCustomConfig(configInfo);
refreshConfigItems();
}

@Override
public Executor getExecutor() {
return null;
}
});
}

private void refreshConfigItems(Map<String, Object> map) {
compareChangedConfig(originalConfigMap, map);
originalConfigMap.clear();
originalConfigMap.putAll(map);
private void processCustomConfig(String content) {
if (StringUtils.isEmpty(content)) {
this.custom = new HashMap<>();
return;
}
Parser contentParser = Parser.findParser(nacosConfig.getContentType());
String keyPrefix = nacosConfig.getGroup() + "." +
nacosConfig.getDataId();
this.custom = contentParser.parse(content, keyPrefix, nacosConfig.getAddPrefix());
}

void compareChangedConfig(Map<String, Object> before, Map<String, Object> after) {
Map<String, Object> itemsCreated = new HashMap<>();
Map<String, Object> itemsDeleted = new HashMap<>();
Map<String, Object> itemsModified = new HashMap<>();
if (before == null || before.isEmpty()) {
updateHandler.handle(CREATE, after);
return;
}
if (after == null || after.isEmpty()) {
updateHandler.handle(DELETE, before);
return;
}
after.forEach((itemKey, itemValue) -> {
if (!before.containsKey(itemKey)) {
itemsCreated.put(itemKey, itemValue);
} else if (!itemValue.equals(before.get(itemKey))) {
itemsModified.put(itemKey, itemValue);
}
});
for (String itemKey : before.keySet()) {
if (!after.containsKey(itemKey)) {
itemsDeleted.put(itemKey, "");
}
}
updateHandler.handle(CREATE, itemsCreated);
updateHandler.handle(SET, itemsModified);
updateHandler.handle(DELETE, itemsDeleted);
private void refreshConfigItems() {
synchronized (lock) {
Map<String, Object> all = new HashMap<>();
all.putAll(application);
all.putAll(service);
all.putAll(version);
all.putAll(profile);
all.putAll(custom);
updateHandler.handle(all, allLast);
this.allLast = all;
}
}

private static Properties nacosProperties(Environment environment, NacosConfig nacosConfig) {
Properties properties = new Properties();
properties.put(NacosConfig.PROP_NAMESPACE, BootStrapProperties.readServiceEnvironment(environment));
properties.put(NacosConfig.PROP_ADDRESS, nacosConfig.getServerAddr());
if (nacosConfig.getUsername() != null) {
properties.put(NacosConfig.PROP_USERNAME, nacosConfig.getUsername());
}
if (nacosConfig.getPassword() != null) {
properties.put(NacosConfig.PROP_PASSWORD, nacosConfig.getPassword());
}
if (nacosConfig.getAccessKey() != null) {
properties.put(NacosConfig.PROP_ACCESS_KEY, nacosConfig.getAccessKey());
}
if (nacosConfig.getSecretKey() != null) {
properties.put(NacosConfig.PROP_SECRET_KEY, nacosConfig.getSecretKey());
}
return properties;
}
}

Loading

0 comments on commit c1ddf4a

Please sign in to comment.