tem ,配置项,是 Namespace 下最小颗粒度的单位。在 Namespace 分成五种类型:properties
yml
yaml
json
xml
。其中:
properties
:每一行配置对应一条 Item 记录。- 后四者:无法进行拆分,所以一个 Namespace 仅仅对应一条 Item 记录,名称为 content。
在portal侧的 ItemController 中,
// 检查用户是否拥有修改namespace权限
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")
@PostMapping("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item")
public ItemDTO createItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@RequestBody ItemDTO item) {
checkModel(isValidItem(item));
//protect
item.setLineNum(0);
item.setId(0);
String userId = userInfoHolder.getUser().getUserId();
item.setDataChangeCreatedBy(userId);
item.setDataChangeLastModifiedBy(userId);
item.setDataChangeCreatedTime(null);
item.setDataChangeLastModifiedTime(null);
return configService.createItem(appId, Env.fromString(env), clusterName, namespaceName, item);
}
public ItemDTO createItem(String appId, Env env, String clusterName, String namespaceName, ItemDTO item) {
// add basic type check。校验配置值的格式
verifyItemValueFormat(appId, env.name(), clusterName, namespaceName, item.getKey(), item.getType(), item.getValue());
NamespaceDTO namespace = namespaceAPI.loadNamespace(appId, env, clusterName, namespaceName);
if (namespace == null) {
throw new BadRequestException(
"namespace:" + namespaceName + " not exist in env:" + env + ", cluster:" + clusterName);
}
item.setNamespaceId(namespace.getId());
ItemDTO itemDTO = itemAPI.createItem(appId, env, clusterName, namespaceName, item);
Tracer.logEvent(TracerEventType.MODIFY_NAMESPACE, String.format("%s+%s+%s+%s", appId, env, clusterName, namespaceName));
return itemDTO;
}
在admin service侧的 ItemController中,
@PreAcquireNamespaceLock
@PostMapping("/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items")
public ItemDTO create(@PathVariable("appId") String appId,
@PathVariable("clusterName") String clusterName,
@PathVariable("namespaceName") String namespaceName, @RequestBody ItemDTO dto) {
Item entity = BeanUtils.transform(Item.class, dto);
ConfigChangeContentBuilder builder = new ConfigChangeContentBuilder();
Item managedEntity = itemService.findOne(appId, clusterName, namespaceName, entity.getKey());
// 唯一性检查
if (managedEntity != null) {
throw new BadRequestException("item already exists");
} else {
entity = itemService.save(entity);
builder.createItem(entity);
}
dto = BeanUtils.transform(ItemDTO.class, entity);
Commit commit = new Commit();
commit.setAppId(appId);
commit.setClusterName(clusterName);
commit.setNamespaceName(namespaceName);
commit.setChangeSets(builder.build());
commit.setDataChangeCreatedBy(dto.getDataChangeLastModifiedBy());
commit.setDataChangeLastModifiedBy(dto.getDataChangeLastModifiedBy());
commitService.save(commit);
return dto;
}
@Transactional
public Item save(Item entity) {
// 检查key、value的长度
checkItemKeyLength(entity.getKey());
checkItemType(entity.getType());
checkItemValueLength(entity.getNamespaceId(), entity.getValue());
entity.setId(0);//protection
if (entity.getLineNum() == 0) {
Item lastItem = findLastOne(entity.getNamespaceId());
int lineNum = lastItem == null ? 1 : lastItem.getLineNum() + 1;
entity.setLineNum(lineNum);
}
// 对配置值进行加密后再存储
entity = doEncryptEntity(entity);
Item item = itemRepository.save(entity);
auditService.audit(Item.class.getSimpleName(), item.getId(), Audit.OP.INSERT,
item.getDataChangeCreatedBy());
// 返回界面显示时再解密
return doDecryptEntity(item);
}
总结:创建item的逻辑比较简单,主要是插入了item表和commit操作变更历史表。