vlambda博客
学习文章列表

nacos配置发布之源码解析

  最近项目上面有个需求,需要动态创建和修改nacos的namespace,查询过nacos的api接口,并没有相关的api,于是准备先查看下nacos实现配置发布的接口configService.publishConfig实现方式,通过参考这种方式,自定义实现个namespace的新增、修改的接口

configService.publishConfig(dataId, group, content)

  我们看到这个接口需要传递三个参数,一个是dataID,还有一个group,还有一个配置的内容。再看看其实现类com.alibaba.nacos.client.config.NacosConfigService

public boolean publishConfig(String dataId, String group, String content) throws NacosException {
return this.publishConfigInner(this.namespace, dataId, group, (String)null, (String)null, (String)null, content);
}
private boolean publishConfigInner(String tenant, String dataId, String group, String tag, String appName, String betaIps, String content) throws NacosException {
group = this.null2defaultGroup(group);
ParamUtils.checkParam(dataId, group, content);
ConfigRequest cr = new ConfigRequest();
cr.setDataId(dataId);
cr.setTenant(tenant);
cr.setGroup(group);
cr.setContent(content);
this.configFilterChainManager.doFilter(cr, (IConfigResponse)null);
content = cr.getContent();
String url = "/v1/cs/configs";
List<String> params = new ArrayList();
params.add("dataId");
params.add(dataId);
params.add("group");
params.add(group);
params.add("content");
params.add(content);
if (StringUtils.isNotEmpty(tenant)) {
params.add("tenant");
params.add(tenant);
}

if (StringUtils.isNotEmpty(appName)) {
params.add("appName");
params.add(appName);
}

if (StringUtils.isNotEmpty(tag)) {
params.add("tag");
params.add(tag);
}

List<String> headers = new ArrayList();
if (StringUtils.isNotEmpty(betaIps)) {
headers.add("betaIps");
headers.add(betaIps);
}

HttpResult result = null;

try {
result = this.agent.httpPost(url, headers, params, this.encode, 3000L);
} catch (IOException var14) {
LOGGER.warn("[{}] [publish-single] exception, dataId={}, group={}, msg={}", new Object[]{this.agent.getName(), dataId, group, var14.toString()});
return false;
}

if (200 == result.code) {
LOGGER.info("[{}] [publish-single] ok, dataId={}, group={}, tenant={}, config={}", new Object[]{this.agent.getName(), dataId, group, tenant, ContentUtils.truncateContent(content)});
return true;
} else if (403 == result.code) {
LOGGER.warn("[{}] [publish-single] error, dataId={}, group={}, tenant={}, code={}, msg={}", new Object[]{this.agent.getName(), dataId, group, tenant, result.code, result.content});
throw new NacosException(result.code, result.content);
} else {
LOGGER.warn("[{}] [publish-single] error, dataId={}, group={}, tenant={}, code={}, msg={}", new Object[]{this.agent.getName(), dataId, group, tenant, result.code, result.content});
return false;
}
}

  首先判断传入的group是否为空,为空的话,传入默认值“DEFAULT_GROUP”,接下来是校验dataId和group的参数是否为空等,后面是构造一个ConfigRequest对象,为了后面的过滤器链用的,再后面就是拼装参数知道发送请求result = this.agent.httpPost(url, headers, params, this.encode, 3000L);   看到这里,可以对agent对象存疑,这是个什么对象?怎么创建的?需要传入哪些参数?通过分析发现,agent是在NacosConfigService的构造方法里面初始化的,其实例化过程是通过传入properties参数再实例化MetricsHttpAgent对象,再次往上找,看看properties参数是如何传递进去的。

ConfigFactory.createConfigService(properties)

  再往上一层是一个工厂类,通过Class.forName的方式实例化ConfigService对象的

public static ConfigService createConfigService(Properties properties) throws NacosException {
try {
Class<?> driverImplClass = Class.forName("com.alibaba.nacos.client.config.NacosConfigService");
Constructor constructor = driverImplClass.getConstructor(Properties.class);
ConfigService vendorImpl = (ConfigService) constructor.newInstance(properties);
return vendorImpl;
} catch (Throwable e) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, e);
}
}

NacosFactory.createConfigService(properties)

  再往上一层依然是一个工厂类。

com.alibaba.cloud.nacos.NacosConfigManager

  再往上一层通过一个简单的单例模式创建了ConfigService对象,这时候还需要往上找找,看哪里创建的NacosConfigManager对象。

public NacosConfigManager(NacosConfigProperties nacosConfigProperties) {
this.nacosConfigProperties = nacosConfigProperties;
createConfigService(nacosConfigProperties);
}

static ConfigService createConfigService(NacosConfigProperties nacosConfigProperties) {
if (Objects.isNull(service)) {
Class var1 = NacosConfigManager.class;
synchronized(NacosConfigManager.class) {
try {
if (Objects.isNull(service)) {
service = NacosFactory.createConfigService(nacosConfigProperties.assembleConfigServiceProperties());
}
} catch (NacosException var4) {
log.error(var4.getMessage());
throw new NacosConnectionFailureException(nacosConfigProperties.getServerAddr(), var4.getMessage(), var4);
}
}
}

return service;
}

com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration

  看到这里,基本上就结束了,这里直接通过bean注解创建实例化NacosConfigManager对象。初始化的时候,会把NacosConfigProperties注入进去。

  @Bean
@ConditionalOnMissingBean
public NacosConfigManager nacosConfigManager(NacosConfigProperties nacosConfigProperties) {
return new NacosConfigManager(nacosConfigProperties);
}

总结

  分析到这里,总结下,整个过程是启动时,先通过依赖注入的方式注入NacosConfigProperties,然后初始化ConfigService对象,构造好agent对象。