Nacos配置中心——namespace

王守钰 2021-11-03 09:11:07

NamespaceController

image
从结构图中可以看出NamespaceController大致分为getNamespacesgetNamespacecreateNamespacecheckNamespaceIdExisteditNamespacedeleteConfig方法。

NamespaceController.getNamespaces

@GetMapping
public RestResult<List<Namespace>> getNamespaces(HttpServletRequest request, HttpServletResponse response) {
    // TODO 获取用kp
    // private static final String DEFAULT_KP = "1";
    List<TenantInfo> tenantInfos = persistService.findTenantByKp(DEFAULT_KP);
    // 默认的namespace
    // private static final String DEFAULT_NAMESPACE = "public";
    // private static final int DEFAULT_QUOTA = 200;
    Namespace namespace0 = new Namespace("", DEFAULT_NAMESPACE, DEFAULT_QUOTA, persistService.configInfoCount(DEFAULT_TENANT),
            NamespaceTypeEnum.GLOBAL.getType());
    List<Namespace> namespaces = new ArrayList<Namespace>();
    namespaces.add(namespace0);
    for (TenantInfo tenantInfo : tenantInfos) {
        int configCount = persistService.configInfoCount(tenantInfo.getTenantId());
        Namespace namespaceTmp = new Namespace(tenantInfo.getTenantId(), tenantInfo.getTenantName(), DEFAULT_QUOTA,
                configCount, NamespaceTypeEnum.CUSTOM.getType());
        namespaces.add(namespaceTmp);
    }
    return RestResultUtils.success(namespaces);
}

persistService进行获取全部tenant列表。构建默认namespace并查询配置文件数量,循环构建返回namespaces

public List<TenantInfo> findTenantByKp(String kp) {
    String sql = "SELECT tenant_id,tenant_name,tenant_desc FROM tenant_info WHERE kp=?";
    try {
        return this.jt.query(sql, new Object[] {kp}, TENANT_INFO_ROW_MAPPER);
    } catch (CannotGetJdbcConnectionException e) {
        LogUtil.FATAL_LOG.error("[db-error] " + e.toString(), e);
        throw e;
    } catch (EmptyResultDataAccessException e) {
        return Collections.emptyList();
    } catch (Exception e) {
        LogUtil.FATAL_LOG.error("[db-other-error]" + e.getMessage(), e);
        throw new RuntimeException(e);
    }
}

查询命名空间最终的sql也就是SELECT tenant_id,tenant_name,tenant_desc FROM tenant_info WHERE kp= 1

public int configInfoCount(String tenant) {
    String sql = " SELECT count(*) FROM config_info WHERE tenant_id LIKE ?";
    Integer result = jt.queryForObject(sql, new Object[] {tenant}, Integer.class);
    if (result == null) {
        throw new IllegalArgumentException("configInfoCount error");
    }
    return result.intValue();
}

查询配置数量最终sqlSELECT count(*) FROM config_info WHERE tenant_id LIKE ?

NamespaceController.deleteConfig

@DeleteMapping
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "namespaces", action = ActionTypes.WRITE)
public Boolean deleteConfig(HttpServletRequest request, HttpServletResponse response,
        @RequestParam("namespaceId") String namespaceId) {
    persistService.removeTenantInfoAtomic(DEFAULT_KP, namespaceId);
    return true;
}
public void removeTenantInfoAtomic(final String kp, final String tenantId) {
    try {
        jt.update("DELETE FROM tenant_info WHERE kp=? AND tenant_id=?", kp, tenantId);
    } catch (CannotGetJdbcConnectionException e) {
        LogUtil.FATAL_LOG.error("[db-error] " + e.toString(), e);
        throw e;
    }
}

删除的逻辑相对会比较简单一些,直接执行DELETE FROM tenant_info WHERE kp=1 AND tenant_id=?,tenant_id也就是对应的namespaceId

NamespaceController.checkNamespaceIdExist

public Boolean checkNamespaceIdExist(@RequestParam("customNamespaceId") String namespaceId) {
    if (StringUtils.isBlank(namespaceId)) {
        return false;
    }
    return (persistService.tenantInfoCountByTenantId(namespaceId) > 0);
}
public int tenantInfoCountByTenantId(String tenantId) {
    Assert.hasText(tenantId, "tenantId can not be null");
    // private static final String SQL_TENANT_INFO_COUNT_BY_TENANT_ID = "SELECT count(*) FROM tenant_info WHERE tenant_id = ?";
    Integer result = this.jt
            .queryForObject(SQL_TENANT_INFO_COUNT_BY_TENANT_ID, new String[] {tenantId}, Integer.class);
    if (result == null) {
        return 0;
    }
    return result.intValue();
}

校验namespaceId是否存在直接执行SELECT count(*) FROM tenant_info WHERE tenant_id = ?

NamespaceController.createNamespace

@PostMapping
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "namespaces", action = ActionTypes.WRITE)
public Boolean createNamespace(HttpServletRequest request, HttpServletResponse response,
        @RequestParam("customNamespaceId") String namespaceId, @RequestParam("namespaceName") String namespaceName,
        @RequestParam(value = "namespaceDesc", required = false) String namespaceDesc) {
    // TODO 获取用kp
    if (StringUtils.isBlank(namespaceId)) {
        namespaceId = UUID.randomUUID().toString();
    } else {
        namespaceId = namespaceId.trim();
        if (!namespaceIdCheckPattern.matcher(namespaceId).matches()) {
            return false;
        }
        if (namespaceId.length() > NAMESPACE_ID_MAX_LENGTH) {
            return false;
        }
        if (persistService.tenantInfoCountByTenantId(namespaceId) > 0) {
            return false;
        }
    }
    persistService.insertTenantInfoAtomic(DEFAULT_KP, namespaceId, namespaceName, namespaceDesc, DEFAULT_CREATE_SOURCE,
            System.currentTimeMillis());
    return true;
}
public void insertTenantInfoAtomic(String kp, String tenantId, String tenantName, String tenantDesc,
        String createResoure, final long time) {
    try {
        jt.update(
                "INSERT INTO tenant_info(kp,tenant_id,tenant_name,tenant_desc,create_source,gmt_create,gmt_modified) VALUES(?,?,?,?,?,?,?)",
                kp, tenantId, tenantName, tenantDesc, createResoure, time, time);
    } catch (DataAccessException e) {
        LogUtil.FATAL_LOG.error("[db-error] " + e.toString(), e);
        throw e;
    }
}

创建namespace时,先校验namespaceId是否为空,为空的话通过UUID生成随机字符串 作为唯一标识,校验namespaceId是否合法,是否存在。最终插入到库中。

NamespaceController.getNamespace

@GetMapping(params = "show=all")
public NamespaceAllInfo getNamespace(HttpServletRequest request, HttpServletResponse response,
        @RequestParam("namespaceId") String namespaceId) {
    // TODO 获取用kp
    if (StringUtils.isBlank(namespaceId)) {
        return new NamespaceAllInfo(namespaceId, DEFAULT_NAMESPACE_SHOW_NAME, DEFAULT_QUOTA, persistService.configInfoCount(DEFAULT_TENANT),
                NamespaceTypeEnum.GLOBAL.getType(), DEFAULT_NAMESPACE_DESCRIPTION);
    } else {
        TenantInfo tenantInfo = persistService.findTenantByKp(DEFAULT_KP, namespaceId);
        int configCount = persistService.configInfoCount(namespaceId);
        return new NamespaceAllInfo(namespaceId, tenantInfo.getTenantName(), DEFAULT_QUOTA, configCount, NamespaceTypeEnum.CUSTOM.getType(),
                tenantInfo.getTenantDesc());
    }
}
public TenantInfo findTenantByKp(String kp, String tenantId) {
    String sql = "SELECT tenant_id,tenant_name,tenant_desc FROM tenant_info WHERE kp=? AND tenant_id=?";
    try {
        return jt.queryForObject(sql, new Object[] {kp, tenantId}, TENANT_INFO_ROW_MAPPER);
    } catch (CannotGetJdbcConnectionException e) {
        LogUtil.FATAL_LOG.error("[db-error] " + e.toString(), e);
        throw e;
    } catch (EmptyResultDataAccessException e) {
        return null;
    } catch (Exception e) {
        LogUtil.FATAL_LOG.error("[db-other-error]" + e.getMessage(), e);
        throw new RuntimeException(e);
    }
}

如果传入的namespaceId为空的话,直接查询出默认namespace下的配置数量,构建返回信息。否则通过"SELECT tenant_id,tenant_name,tenant_desc FROM tenant_info WHERE kp=1 AND tenant_id=?来进行查询。

NamespaceController.editNamespace

@PutMapping
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "namespaces", action = ActionTypes.WRITE)
public Boolean editNamespace(@RequestParam("namespace") String namespace,
        @RequestParam("namespaceShowName") String namespaceShowName,
        @RequestParam(value = "namespaceDesc", required = false) String namespaceDesc) {
    // TODO 获取用kp
    persistService.updateTenantNameAtomic(DEFAULT_KP, namespace, namespaceShowName, namespaceDesc);
    return true;
}
public void updateTenantNameAtomic(String kp, String tenantId, String tenantName, String tenantDesc) {
    try {
        jt.update(
                "UPDATE tenant_info SET tenant_name = ?, tenant_desc = ?, gmt_modified= ? WHERE kp=? AND tenant_id=?",
                tenantName, tenantDesc, System.currentTimeMillis(), kp, tenantId);
    } catch (DataAccessException e) {
        LogUtil.FATAL_LOG.error("[db-error] " + e.toString(), e);
        throw e;
    }
}

修改namespace的时候,直接进行执行UPDATE tenant_info SET tenant_name = ?, tenant_desc = ?, gmt_modified= ? WHERE kp=1 AND tenant_id=?的sql语句。

tenant_info表信息

CREATE TABLE `tenant_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `kp` varchar(128) NOT NULL COMMENT 'kp',
  `tenant_id` varchar(128) default '' COMMENT 'tenant_id',
  `tenant_name` varchar(128) default '' COMMENT 'tenant_name',
  `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
  `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
  `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
  `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';

这里面创建了kptenant_id的唯一索引。也就保证了tenant_id的唯一性。