前言
近期在学习Spring Cloud Alibaba系统,便记录Nacos配置中心的源码学习
从nacos-github 下载源码,IDEA打开,启动过程这里不再叙述了。
ConfigService
example工程有个ConfigExample类,该类展示了如何从naocs控制台获取配置信息,我们一起来看一下
public class ConfigExample {
public static void main(String[] args) throws NacosException, InterruptedException {
String serverAddr = "localhost";
String dataId = "test";
String group = "DEFAULT_GROUP";
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
ConfigService configService = NacosFactory.createConfigService(properties);
String content = configService.getConfig(dataId, group, 5000);
System.out.println(content);
configService.addListener(dataId, group, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
System.out.println("receive:" + configInfo);
}
@Override
public Executor getExecutor() {
return null;
}
});
boolean isPublishOk = configService.publishConfig(dataId, group, "content");
System.out.println(isPublishOk);
Thread.sleep(3000);
content = configService.getConfig(dataId, group, 5000);
System.out.println(content);
boolean isRemoveOk = configService.removeConfig(dataId, group);
System.out.println(isRemoveOk);
Thread.sleep(3000);
content = configService.getConfig(dataId, group, 5000);
System.out.println(content);
Thread.sleep(300000);
}
}
两个关键信息
1.从 NacosFactory
创建 ConfigService
对象
2.加入 Listener
监听器,接收配置信息
我们先看 ConfigService
对象的创建过程
ConfigService 实例化过程
/**
* Create Config.
*
* @param properties init param
* @return ConfigService
* @throws NacosException Exception
*/
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);
}
}
可以看到是利用反射调用了 NacosConfigService
有参构造方法实例化 ConfigService
的,参数为 Properties
对象
我们看看 NacosConfigService
的构造方法做了些什么
public NacosConfigService(Properties properties) throws NacosException {
//检查初始化参数
ValidatorUtils.checkInitParam(properties);
//获取编码信息
String encodeTmp = properties.getProperty(PropertyKeyConst.ENCODE);
if (StringUtils.isBlank(encodeTmp)) {
//如果为空,默认UTF-8
this.encode = Constants.ENCODE;
} else {
this.encode = encodeTmp.trim();
}
//初始化namespace
initNamespace(properties);
//初始化HttpAgent
this.agent = new MetricsHttpAgent(new ServerHttpAgent(properties));
//调用start方法
this.agent.start();
//初始化ClientWorker
this.worker = new ClientWorker(this.agent, this.configFilterChainManager, properties);
}
step1.参数校验,主要是对 Properties
对象的 contextPath
进行正则匹配,不能同时出现两个//
step2. 初始化namespace
private void initNamespace(Properties properties) {
namespace = ParamUtil.parseNamespace(properties);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
}
/**
* Parse namespace from properties and environment.
*
* @param properties properties
* @return namespace
*/
public static String parseNamespace(Properties properties) {
String namespaceTmp = null;
String isUseCloudNamespaceParsing = properties.getProperty(PropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
System.getProperty(SystemPropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
String.valueOf(Constants.DEFAULT_USE_CLOUD_NAMESPACE_PARSING)));
if (Boolean.parseBoolean(isUseCloudNamespaceParsing)) {
namespaceTmp = TemplateUtils.stringBlankAndThenExecute(namespaceTmp, new Callable<String>() {
@Override
public String call() {
return TenantUtil.getUserTenantForAcm();
}
});
namespaceTmp = TemplateUtils.stringBlankAndThenExecute(namespaceTmp, new Callable<String>() {
@Override
public String call() {
String namespace = System.getenv(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_NAMESPACE);
return StringUtils.isNotBlank(namespace) ? namespace : StringUtils.EMPTY;
}
});
}
if (StringUtils.isBlank(namespaceTmp)) {
namespaceTmp = properties.getProperty(PropertyKeyConst.NAMESPACE);
}
return StringUtils.isNotBlank(namespaceTmp) ? namespaceTmp.trim() : StringUtils.EMPTY;
}
主要是从属性或环境变量中解析获取namespace。
step3. 初始化 ServerHttpAgent
并调用start方法
step4.初始化 ClientWorker
这两部分是重点,我们另起文章来写!