两种实现方式:
- NacosConfigEnvironmentProcessor:负责在应用程序启动前加载远程配置
- NacosConfigAutoConfiguration:负责完成Nacos配置管理相关功能的配置加载与初始化
1、@NacosConfigurationProperties
1.1@NacosConfigurationProperties怎么被识别的
Nacos提供了NacosConfigurationPropertiesBindingPostProcessor
- 扫描类上的是否有@NacosConfigurationProperties注解
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
NacosConfigurationProperties nacosConfigurationProperties = findAnnotation(
bean.getClass(), NacosConfigurationProperties.class);
if (nacosConfigurationProperties != null) {
bind(bean, beanName, nacosConfigurationProperties);
}
return bean;
}
- 获取@NacosConfigurationProperties构造器实例
private void bind(Object bean, String beanName,
NacosConfigurationProperties nacosConfigurationProperties) {
NacosConfigurationPropertiesBinder binder;
try {
binder = applicationContext.getBean(
NacosConfigurationPropertiesBinder.BEAN_NAME,
NacosConfigurationPropertiesBinder.class);
if (binder == null) {
binder = new NacosConfigurationPropertiesBinder(applicationContext);
}
}
catch (Exception e) {
binder = new NacosConfigurationPropertiesBinder(applicationContext);
}
binder.bind(bean, beanName, nacosConfigurationProperties);
}
- 获取NacosConfigService服务
- 创建监听,并将监听器添加到NacosConfigService服务中
protected void bind(final Object bean, final String beanName,
final NacosConfigurationProperties properties) {
Assert.notNull(bean, "Bean must not be null!");
Assert.notNull(properties, "NacosConfigurationProperties must not be null!");
// support read data-id and group-id from spring environment
final String dataId = NacosUtils.readFromEnvironment(properties.dataId(),
environment);
final String groupId = NacosUtils.readFromEnvironment(properties.groupId(),
environment);
final String type;
ConfigType typeEunm = properties.yaml() ? ConfigType.YAML : properties.type();
if (ConfigType.UNSET.equals(typeEunm)) {
type = NacosUtils.readFileExtension(dataId);
}
else {
type = typeEunm.getType();
}
final ConfigService configService = configServiceBeanBuilder
.build(properties.properties());
// Add a Listener if auto-refreshed
if (properties.autoRefreshed()) {
String content = getContent(configService, dataId, groupId);
if (hasText(content)) {
doBind(bean, beanName, dataId, groupId, type, properties, content,
configService);
}
Listener listener = new AbstractListener() {
@Override
public void receiveConfigInfo(String config) {
doBind(bean, beanName, dataId, groupId, type, properties, config,
configService);
}
};
try {//
if (configService instanceof EventPublishingConfigService) {
((EventPublishingConfigService) configService).addListener(dataId,
groupId, type, listener);
}
else {
configService.addListener(dataId, groupId, listener);
}
}
catch (NacosException e) {
if (logger.isErrorEnabled()) {
logger.error(e.getMessage(), e);
}
}
}
}
2、更新数据
当在配置更新时,回调listener监听器,执行NacosBootConfigurationPropertiesBinder.doBind方法
- 注解配置的配置文件临时加入到默认的StandardEnvironment中
- 通过SpringBoot Binder将StandardEnvironment配置项绑定(注入)到bean
- 解析完成后再移除注入
protected void doBind(Object bean, String beanName, String dataId, String groupId,
String configType, NacosConfigurationProperties properties, String content,
ConfigService configService) {
synchronized (this) {
String name = "nacos-bootstrap-" + beanName;
NacosPropertySource propertySource = new NacosPropertySource(name, dataId, groupId, content, configType);
environment.getPropertySources().addLast(propertySource);
Binder binder = Binder.get(environment);
ResolvableType type = getBeanType(bean, beanName);
Bindable<?> target = Bindable.of(type).withExistingValue(bean);
binder.bind(properties.prefix(), target);
publishBoundEvent(bean, beanName, dataId, groupId, properties, content, configService);
publishMetadataEvent(bean, beanName, dataId, groupId, properties);
environment.getPropertySources().remove(name);
}
}