Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
作为一个后台开发,nacos是我经常用到的一款集注册中心、配置中心于一身的平台,简单的配置启动,然后应用注册即可使用,还有简洁明了使用的UI页面,点个赞先!
贴上官网地址:
https://nacos.io/
在使用nacos页面更改配置并发布的时候发现一个问题:
当两个人A和B都打开了某个配置的编辑页面,都进行了修改,然后点了发布,则会出现后点发布的B提交的配置生效,因为会覆盖前者A发布的版本,而此时如果没做比对或确认的话A就会没有察觉,从而导致可能的一些问题…
该问题也很好复现,两个人直接按照步骤操作即可,一个人的话通过两个浏览器来模拟:
1、通过浏览器A打开nacos UI页面,找到一个配置文件,点击编辑,打开编辑页面;
2、通过浏览器B打开nacos UI页面,也找到刚刚打开的那个配置文件,点击编辑,打开编辑页面;
3、在浏览器A打开的nacos配置编辑页面对配置进行变更修改,然后点击发布;
4、在浏览器B打开的nacos配置编辑页面也对配置进行变更修改,然后点击发布;
5、再次查看nacos上这个配置文件的配置信息,会发现呈现的是浏览器B编辑发布后的结果;
思路:在发布之前进行MD5比对!拿到源码,本地对逻辑进行变更,然后编译打包使用…
代码修改处如下:
1、com.alibaba.nacos.config.server.model.form.ConfigForm
增加md5参数字段
package com.alibaba.nacos.config.server.model.form;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.common.utils.StringUtils;
import org.springframework.http.HttpStatus;
import java.io.Serializable;
import java.util.Objects;
public class ConfigForm implements Serializable {
// ... 代码省略
private String md5;
public ConfigForm() {
}
public ConfigForm(String dataId, String group, String namespaceId, String content, String tag, String appName,
String srcUser, String configTags, String desc, String use, String effect, String type, String schema,
String md5) {
this.dataId = dataId;
this.group = group;
this.namespaceId = namespaceId;
this.content = content;
this.tag = tag;
this.appName = appName;
this.srcUser = srcUser;
this.configTags = configTags;
this.desc = desc;
this.use = use;
this.effect = effect;
this.type = type;
this.schema = schema;
this.md5 = md5;
}
// ... 代码省略
public String getMd5() {
return md5;
}
public void setMd5(String md5) {
this.md5 = md5;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ConfigForm configForm = (ConfigForm) o;
return dataId.equals(configForm.dataId) && group.equals(configForm.group) && Objects.equals(namespaceId, configForm.namespaceId)
&& content.equals(configForm.content) && Objects.equals(tag, configForm.tag) && Objects
.equals(appName, configForm.appName) && Objects.equals(srcUser, configForm.srcUser) && Objects
.equals(configTags, configForm.configTags) && Objects.equals(desc, configForm.desc) && Objects
.equals(use, configForm.use) && Objects.equals(effect, configForm.effect) && Objects
.equals(type, configForm.type) && Objects.equals(schema, configForm.schema)
&& Objects.equals(md5, configForm.md5);
}
@Override
public int hashCode() {
return Objects.hash(dataId, group, namespaceId, content, tag, appName, srcUser, configTags, desc, use, effect, type,
schema, md5);
}
@Override
public String toString() {
return "ConfigVo{" +
"dataId='" + dataId + '\'' +
", group='" + group + '\'' +
", namespaceId='" + namespaceId + '\'' +
", content='" + content + '\'' +
", tag='" + tag + '\'' +
", appName='" + appName + '\'' +
", srcUser='" + srcUser + '\'' +
", configTags='" + configTags + '\'' +
", desc='" + desc + '\'' +
", use='" + use + '\'' +
", effect='" + effect + '\'' +
", type='" + type + '\'' +
", schema='" + schema + '\'' +
", md5='" + md5 + '\'' +
'}';
}
/**
* Validate.
*
* @throws NacosApiException NacosApiException.
*/
public void validate() throws NacosApiException {
if (StringUtils.isBlank(dataId)) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
"Required parameter 'dataId' type String is not present");
} else if (StringUtils.isBlank(group)) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
"Required parameter 'group' type String is not present");
} else if (StringUtils.isBlank(content)) {
throw new NacosApiException(HttpStatus.BAD_REQUEST.value(), ErrorCode.PARAMETER_MISSING,
"Required parameter 'content' type String is not present");
}
}
}
2、com.alibaba.nacos.config.server.controller.ConfigController#publishConfig
添加md5入参,前端有传,直接接收
@PostMapping
@TpsControl(pointName = "ConfigPublish")
@Secured(action = ActionTypes.WRITE, signType = SignType.CONFIG)
public Boolean publishConfig(HttpServletRequest request, HttpServletResponse response,
@RequestParam(value = "dataId") String dataId,
@RequestParam(value = "group") String group,
@RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY) String tenant,
@RequestParam(value = "content") String content, @RequestParam(value = "tag", required = false) String tag,
@RequestParam(value = "appName", required = false) String appName,
@RequestParam(value = "src_user", required = false) String srcUser,
@RequestParam(value = "config_tags", required = false) String configTags,
@RequestParam(value = "desc", required = false) String desc,
@RequestParam(value = "use", required = false) String use,
@RequestParam(value = "effect", required = false) String effect,
@RequestParam(value = "type", required = false) String type,
@RequestParam(value = "schema", required = false) String schema,
@RequestParam(value = "md5", required = false) String md5) throws NacosException {
// ... 代码省略
configForm.setMd5(md5);
// ... 代码省略
return configOperationService.publishConfig(configForm, configRequestInfo, encryptedDataKey);
}
3、com.alibaba.nacos.config.server.service.ConfigOperationService#publishConfig
添加校验逻辑
public Boolean publishConfig(ConfigForm configForm, ConfigRequestInfo configRequestInfo, String encryptedDataKey)
throws NacosException {
// ... 代码省略
ConfigInfo oldConfigInfo = configInfoPersistService.findConfigInfo(configInfo.getDataId(), configInfo.getGroup(),
configInfo.getTenant());
String oldConfigInfoMd5 = oldConfigInfo.getMd5();
String curMd5 = configForm.getMd5();
if (!StringUtils.equals(curMd5, oldConfigInfoMd5)) {
// 传进来的上一版本md5和数据库里现在的md5不相等,表示在此之前其他用户已更新,不能直接覆盖
throw new NacosApiException(HttpStatus.METHOD_NOT_ALLOWED.value(), ErrorCode.RESOURCE_CONFLICT, "已有其他用户更新了此配置,请先更新再修改发布!");
}
// ... 代码省略
return true;
}
4、编译打包
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
5、拿到打包后的新包使用即可
新包路径:项目代码路径/distribution/target
再次测试结果符合预期!
到此这个问题就可以如愿解决了,欢迎留言交流!
如果您看到了这里,欢迎和我沟通交流!
一个95后码农
个人博客:fy-blog