前言
在專案最好不要透過程式修改 nacos 配置,這樣比較危險,如果程式碼有問題或者將其他的配置給覆蓋了,可能會造成生產事故。需要頻繁修改的配置資訊最好儲存到資料庫。
修改 yaml 型別的配置
bootstrap.yaml 配置
spring:
application:
name: cnblogs
cloud:
nacos:
config:
server-addr: http://ip:8848
namespace: d8b0df04-aa58-4a5b-b582-7d133b9e8b2c #名稱空間ID
file-extension: yaml
username: xxx
password: xxx
extension-configs:
- data-id: server.yaml
group: DEFAULT_GROUP
refresh: true
- data-id: testUpdateNacos.yaml
group: DEFAULT_GROUP
refresh: true
server.yaml
server:
port: 8090
servlet:
context-path: /cnblogs
dynamic:
nacos:
config:
server-addr: http://ip:8848
namespace: d8b0df04-aa58-4a5b-b582-7d133b9e8b2c
username: xxx
password: xxx
timeout: 5000
data-id: testUpdateNacos.yaml
group-id: DEFAULT_GROUP
key: myuser.name
testUpdateNacos.yaml,隨便配置一些資料
order:
timeout: 1000
myuser:
address:
province: 上海
name: lisi
pwd: test123
product:
quantity: 2000
我們透過程式來修改 testUpdateNacos.yaml 配置檔案中 myuser.name 的值
注意:testUpdateNacos.yaml 此檔案必須提前建立好,且 myuser.name 的值也必須提前配置好(有一個預設值)
程式碼如下
@RestController
@RefreshScope
public class TestNacosController {
@Autowired
private DynamicNacosConfig dynamicNacosConfig;
@Value("${myuser.name}")
private String myUserName;
@PostMapping("testUpdateNacos")
public String testUpdateNacos(String updateValue) throws NacosException {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, dynamicNacosConfig.getServerAddr());
properties.put(PropertyKeyConst.NAMESPACE, dynamicNacosConfig.getNamespace());
properties.put(PropertyKeyConst.USERNAME, dynamicNacosConfig.getUsername());
properties.put(PropertyKeyConst.PASSWORD, dynamicNacosConfig.getPassword());
ConfigService configService = NacosFactory.createConfigService(properties);
//獲取當前配置
String config = configService.getConfig(dynamicNacosConfig.getDataId(), dynamicNacosConfig.getGroupId(), dynamicNacosConfig.getTimeout());
System.out.println(config);
DumperOptions dumperOptions = new DumperOptions();
//一定要設定
dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
Yaml yaml = new Yaml(dumperOptions);
//如果value為物件,那麼型別為LinkedHashMap
Map<String, Object> newMap = yaml.load(config);
String updateKey = dynamicNacosConfig.getKey();
String[] words = updateKey.split("[.]");
Map<String, Object> currentMap = newMap;
for (int i = 0; i < words.length; i++) {
String currentWord = words[i];
if (!currentMap.containsKey(currentWord)) {
break;
}
if (i != words.length - 1) {
currentMap = (Map<String, Object>) newMap.get(currentWord);
} else {
currentMap.put(currentWord, updateValue);
}
}
String newContent = yaml.dump(newMap);
System.out.println(newContent);
boolean success = configService.publishConfig(
dynamicNacosConfig.getDataId(),
dynamicNacosConfig.getGroupId(),
newContent,
ConfigType.YAML.getType());
return success ? "success" : "fail";
}
@GetMapping("/testQueryNacos")
public String testQueryNacos() {
return myUserName;
}
@ConfigurationProperties(prefix = "dynamic.nacos.config")
@Data
@Component
public static class DynamicNacosConfig {
//連線nacos的配置
private String serverAddr;
private String namespace;
private String username;
private String password;
private Integer timeout;
//要修改的配置
private String dataId;
private String groupId;
private String key;
}
}
透過 publishConfig() 方法修改配置和我們透過 nacos 管理後臺頁面修改是同樣的效果,最終也會走 SpringCloud 的 RefreshScope 流程,達到自動重新整理配置的效果。
以上面的程式為例,我們呼叫了 testUpdateNacos 請求之後,再呼叫 testQueryNacos,就會得到更新後的值。
注意:如果 testUpdateNacos.yaml 配置檔案中,我們配置了註釋,那麼會被覆蓋掉(yaml.dump()方法),但是 key 的順序不會變,因為 yaml.load() 方法返回的是 LinkedHashMap。
修改 properties 型別的配置
bootstrap.properties
spring.application.name=cnblogs
spring.cloud.nacos.config.server-addr=http://ip:8848
spring.cloud.nacos.config.namespace=d8b0df04-aa58-4a5b-b582-7d133b9e8b2c
spring.cloud.nacos.config.file-extension=properties
spring.cloud.nacos.config.username=xxx
spring.cloud.nacos.config.password=xxx
spring.cloud.nacos.config.extension-configs[0].data-id=server.properties
spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[0].refresh=true
spring.cloud.nacos.config.extension-configs[1].data-id=testUpdateNacos.properties
spring.cloud.nacos.config.extension-configs[1].group=DEFAULT_GROUP
spring.cloud.nacos.config.extension-configs[1].refresh=true
server.properties
server.port=8090
server.servlet.context-path=/cnblogs
dynamic.nacos.config.server-addr=http://ip:8848
dynamic.nacos.config.namespace=d8b0df04-aa58-4a5b-b582-7d133b9e8b2c
dynamic.nacos.config.username=xxx
dynamic.nacos.config.password=xxx
dynamic.nacos.config.timeout=5000
dynamic.nacos.config.data-id=testUpdateNacos.properties
dynamic.nacos.config.group-id=DEFAULT_GROUP
dynamic.nacos.config.key=myuser.name
testUpdateNacos.properties
order.timeout=1000
myuser.address.province=上海
myuser.name=lisi
myuser.pwd=test123
product.quantity=2000
程式碼如下
@RestController
@RefreshScope
public class TestNacosController2 {
@Autowired
private DynamicNacosConfig dynamicNacosConfig;
@Value("${myuser.name}")
private String myUserName;
@PostMapping("testUpdateNacos2")
public String testUpdateNacos(String updateValue) throws NacosException, IOException {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, dynamicNacosConfig.getServerAddr());
properties.put(PropertyKeyConst.NAMESPACE, dynamicNacosConfig.getNamespace());
properties.put(PropertyKeyConst.USERNAME, dynamicNacosConfig.getUsername());
properties.put(PropertyKeyConst.PASSWORD, dynamicNacosConfig.getPassword());
ConfigService configService = NacosFactory.createConfigService(properties);
//獲取當前配置
String config = configService.getConfig(dynamicNacosConfig.getDataId(), dynamicNacosConfig.getGroupId(), dynamicNacosConfig.getTimeout());
System.out.println(config);
Properties configProperties = new Properties();
configProperties.load(new StringReader(config));
//更新配置,只做修改,不做新增
String updateKey = dynamicNacosConfig.getKey();
if (configProperties.containsKey(updateKey)) {
configProperties.put(updateKey,updateValue);
}
StringWriter stringWriter = new StringWriter();
configProperties.store(stringWriter,null);
String newContent = stringWriter.toString();
boolean success = configService.publishConfig(
dynamicNacosConfig.getDataId(),
dynamicNacosConfig.getGroupId(),
newContent,
ConfigType.PROPERTIES.getType());
return success ? "success" : "fail";
}
@GetMapping("/testQueryNacos2")
public String testQueryNacos() {
return myUserName;
}
@ConfigurationProperties(prefix = "dynamic.nacos.config")
@Data
@Component
public static class DynamicNacosConfig {
//連線nacos的配置
private String serverAddr;
private String namespace;
private String username;
private String password;
private Integer timeout;
//要修改的配置
private String dataId;
private String groupId;
private String key;
}
}
透過 Properties.store() 方法得到的字串,key 的順序是亂的,而且其中的註釋也會被覆蓋掉。我們可以透過手動拼接字串的方式來避免這個問題。
@PostMapping("testUpdateNacos3")
public String testUpdateNacos3(String updateValue) throws NacosException, IOException {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, dynamicNacosConfig.getServerAddr());
properties.put(PropertyKeyConst.NAMESPACE, dynamicNacosConfig.getNamespace());
properties.put(PropertyKeyConst.USERNAME, dynamicNacosConfig.getUsername());
properties.put(PropertyKeyConst.PASSWORD, dynamicNacosConfig.getPassword());
ConfigService configService = NacosFactory.createConfigService(properties);
//獲取當前配置
String config = configService.getConfig(dynamicNacosConfig.getDataId(), dynamicNacosConfig.getGroupId(), dynamicNacosConfig.getTimeout());
System.out.println(config);
//更新配置,只做修改,不做新增
String updateKey = dynamicNacosConfig.getKey();
StringBuilder newContent = new StringBuilder();
String[] lines = config.split("\n");
for (String line : lines) {
String[] arr = line.split("=");
String key = arr[0].trim();
// 排除註釋
if (!line.startsWith("#") && Objects.equals(key,updateKey)) {
newContent.append(key).append("=").append(updateValue);
} else {
//原來的配置
newContent.append(line);
}
newContent.append("\n");
}
boolean success = configService.publishConfig(
dynamicNacosConfig.getDataId(),
dynamicNacosConfig.getGroupId(),
newContent.toString(),
ConfigType.PROPERTIES.getType());
return success ? "success" : "fail";
}
當然我們自己拼接,肯定是不支援 properties 中冒號、反斜槓等高階語法了。