一 配置中心基本原理
- nacosServer将项目持久化到本地数据库中,nacosClient在启动项目的时候从配置中心拉取到相应的配置
- 客户端通过长轮询机制来实现配置更新时配置的实时刷新(比对文件md5值判断文件是否更新)
二 nacos客户端从配置中心拉取配置的基本流程
在spring cloud中Environment的扩展配置还可以借助PropertySourceBootstrapConfiguration这个ApplicationContextInitializer,通过自定义类实现PropertySourceLocator接口来扩展
org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration#initialize 在刷新容器前触发Environment环境的初始化
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
List<PropertySource<?>> composite = new ArrayList<>();
AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
boolean empty = true;
// 或得environment 对象
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for (PropertySourceLocator locator : this.propertySourceLocators) {
// 通过PropertySourceLocator获得PropertySource
Collection<PropertySource<?>> source = locator.locateCollection(environment);
if (source == null || source.size() == 0) {
continue;
}
List<PropertySource<?>> sourceList = new ArrayList<>();
for (PropertySource<?> p : source) {
if (p instanceof EnumerablePropertySource) {
EnumerablePropertySource<?> enumerable = (EnumerablePropertySource<?>) p;
sourceList.add(new BootstrapPropertySource<>(enumerable));
}
else {
sourceList.add(new SimpleBootstrapPropertySource(p));
}
}
logger.info("Located property source: " + sourceList);
composite.addAll(sourceList);
empty = false;
}
if (!empty) {
MutablePropertySources propertySources = environment.getPropertySources();
String logConfig = environment.resolvePlaceholders("${logging.config:}");
LogFile logFile = LogFile.get(environment);
for (PropertySource<?> p : environment.getPropertySources()) {
if (p.getName().startsWith(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
propertySources.remove(p.getName());
}
}
// 将PropertySource初始化到Environment
insertPropertySources(propertySources, composite);
reinitializeLoggingSystem(environment, logConfig, logFile);
setLogLevels(applicationContext, environment);
handleIncludedProfiles(environment);
}
}
通过com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#locate完成PropertySource的初始化
@Override
public PropertySource<?> locate(Environment env) {
nacosConfigProperties.setEnvironment(env);
// 获得configService 用于远程接口的调用
ConfigService configService = nacosConfigManager.getConfigService();
if (null == configService) {
log.warn("no instance of config service found, can't load config from nacos");
return null;
}
long timeout = nacosConfigProperties.getTimeout();
// 用于nacos配置的加载
nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService,
timeout);
// 获得yml中相关配置 用于从服务端获取配置
String name = nacosConfigProperties.getName();
String dataIdPrefix = nacosConfigProperties.getPrefix();
if (StringUtils.isEmpty(dataIdPrefix)) {
dataIdPrefix = name;
}
if (StringUtils.isEmpty(dataIdPrefix)) {
dataIdPrefix = env.getProperty("spring.application.name");
}
CompositePropertySource composite = new CompositePropertySource(
NACOS_PROPERTY_SOURCE_NAME);
// 获得公用配置
loadSharedConfiguration(composite);
// 获得扩展配置
loadExtConfiguration(composite);
// 获得默认配置
loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);
return composite;
}
com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosPropertySource中通过nacosPropertySourceBuilder的build或得NacosPropertySource
private NacosPropertySource loadNacosPropertySource(final String dataId,
final String group, String fileExtension, boolean isRefreshable) {
if (NacosContextRefresher.getRefreshCount() != 0) {
if (!isRefreshable) {
return NacosPropertySourceRepository.getNacosPropertySource(dataId,
group);
}
}
return nacosPropertySourceBuilder.build(dataId, group, fileExtension,
isRefreshable);
}
com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder#build中通過loadNacosData()中的configService远程拉取配置
com.alibaba.nacos.client.config.NacosConfigService#getConfigInner
三 总结
- PropertySourceBootstrapConfiguration中实现了ApplicationContextInitializer在容器刷新前调用initialize方法在该方法中通过PropertySourceLocator接口的实现locate()方法获得用于environment的装载
- 在NacosPropertySourceLocator回会依次调用loadSharedConfiguration加载公用配置loadExtConfiguration加载扩展配置loadApplicationConfiguration加载默认配置
- 配置的加载主要依靠NacosPropertySourceBuilder的build方法他会通过nacosConfigService去向nacos服务端拉取配置
- nacos服务端在获取配置时会先从本地读取配置读取到相应的配置后直接返回,没有再从数据库读取相应的配置返回给客户端