網站首頁 編程語言 正文
1、加載節點
SpringBoot啟動時,會執行這個方法:SpringApplication#run,這個方法中會調prepareContext來準備上下文,這個方法中調用了applyInitializers方法來執行實現了ApplicationContextInitializer接口的類的initialize方法。其中包括PropertySourceBootstrapConfiguration#initialize 來加載外部的配置。
@Autowired(required = false)
private List<PropertySourceLocator> propertySourceLocators = new ArrayList<>();
public void initialize(ConfigurableApplicationContext applicationContext) {
...
for (PropertySourceLocator locator : this.propertySourceLocators) {
//載入PropertySource
Collection<PropertySource<?>> source = locator.locateCollection(environment);
...
}
...
}
//org.springframework.cloud.bootstrap.config.PropertySourceLocator#locateCollection
default Collection<PropertySource<?>> locateCollection(Environment environment) {
return locateCollection(this, environment);
}
//org.springframework.cloud.bootstrap.config.PropertySourceLocator#locateCollection
static Collection<PropertySource<?>> locateCollection(PropertySourceLocator locator, Environment environment) {
//執行locate方法,將PropertySource加載進來
PropertySource<?> propertySource = locator.locate(environment);
...
}
這個類中會注入實現了PropertySourceLocator接口的類,在nacos中是NacosPropertySourceLocator。
在initialize方法中會執行NacosPropertySourceLocator的locate方法,將NacosPropertySource加載進來。
2、NacosPropertySourceLocator的注冊
NacosPropertySourceLocator在配置類NacosConfigBootstrapConfiguration中注冊。
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.nacos.config.enabled", matchIfMissing = true)
public class NacosConfigBootstrapConfiguration {
@Bean
@ConditionalOnMissingBean
public NacosConfigProperties nacosConfigProperties() {
return new NacosConfigProperties();
}
@Bean
@ConditionalOnMissingBean
public NacosConfigManager nacosConfigManager(
NacosConfigProperties nacosConfigProperties) {
return new NacosConfigManager(nacosConfigProperties);
}
@Bean
public NacosPropertySourceLocator nacosPropertySourceLocator(
NacosConfigManager nacosConfigManager) {
return new NacosPropertySourceLocator(nacosConfigManager);
}
}
在這里會依次注冊NacosConfigProperties,NacosConfigManager,NacosPropertySourceLocator。
3、加載
//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#locate
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();
//構建nacosPropertySourceBuilder
nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService,
timeout);
String name = nacosConfigProperties.getName();
//獲取dataIdPrefix,一次從prefix,name,spring.application.name中獲取
String dataIdPrefix = nacosConfigProperties.getPrefix();
if (StringUtils.isEmpty(dataIdPrefix)) {
dataIdPrefix = name;
}
if (StringUtils.isEmpty(dataIdPrefix)) {
dataIdPrefix = env.getProperty("spring.application.name");
}
//構建CompositePropertySource:NACOS
CompositePropertySource composite = new CompositePropertySource(
NACOS_PROPERTY_SOURCE_NAME);
//加載share 配置
loadSharedConfiguration(composite);
//加載extention 配置
loadExtConfiguration(composite);
//加載application配置
loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);
return composite;
}
3.1、加載share
private void loadSharedConfiguration(
CompositePropertySource compositePropertySource) {
//獲取share節點的配置信息
List<NacosConfigProperties.Config> sharedConfigs = nacosConfigProperties
.getSharedConfigs();
//如果不為空,加載
if (!CollectionUtils.isEmpty(sharedConfigs)) {
checkConfiguration(sharedConfigs, "shared-configs");
loadNacosConfiguration(compositePropertySource, sharedConfigs);
}
}
加載配置,公用方法
//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosConfiguration
private void loadNacosConfiguration(final CompositePropertySource composite,
List<NacosConfigProperties.Config> configs) {
for (NacosConfigProperties.Config config : configs) {
loadNacosDataIfPresent(composite, config.getDataId(), config.getGroup(),
NacosDataParserHandler.getInstance()
.getFileExtension(config.getDataId()),
config.isRefresh());
}
}
//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosDataIfPresent
private void loadNacosDataIfPresent(final CompositePropertySource composite,
final String dataId, final String group, String fileExtension,
boolean isRefreshable) {
if (null == dataId || dataId.trim().length() < 1) {
return;
}
if (null == group || group.trim().length() < 1) {
return;
}
//加載NacosPropertySource,后面也會用這個方法
NacosPropertySource propertySource = this.loadNacosPropertySource(dataId, group,
fileExtension, isRefreshable);
//將NacosPropertySource放入第一個
this.addFirstPropertySource(composite, propertySource, false);
}
3.1.1、加載NacosPropertySource
//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosPropertySource
private NacosPropertySource loadNacosPropertySource(final String dataId,
final String group, String fileExtension, boolean isRefreshable) {
//標注@RefreshScope的類的數量不為0,且不允許自動刷新,從緩存加載nacos的配置
if (NacosContextRefresher.getRefreshCount() != 0) {
if (!isRefreshable) {
return NacosPropertySourceRepository.getNacosPropertySource(dataId,
group);
}
}
return nacosPropertySourceBuilder.build(dataId, group, fileExtension,
isRefreshable);
}
3.1.1.1、從緩存中加載
//NacosPropertySourceRepository
private final static ConcurrentHashMap<String, NacosPropertySource> NACOS_PROPERTY_SOURCE_REPOSITORY = new ConcurrentHashMap<>();
public static NacosPropertySource getNacosPropertySource(String dataId,
String group) {
return NACOS_PROPERTY_SOURCE_REPOSITORY.get(getMapKey(dataId, group));
}
public static String getMapKey(String dataId, String group) {
return String.join(NacosConfigProperties.COMMAS, String.valueOf(dataId),
String.valueOf(group));
}
NacosPropertySourceRepository中緩存了NacosPropertySource
3.1.1.2、獲取配置并加入緩存
//com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder#build
NacosPropertySource build(String dataId, String group, String fileExtension,
boolean isRefreshable) {
//獲取配置
List<PropertySource<?>> propertySources = loadNacosData(dataId, group,
fileExtension);
//包裝成NacosPropertySource
NacosPropertySource nacosPropertySource = new NacosPropertySource(propertySources,
group, dataId, new Date(), isRefreshable);
//加入緩存
NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource);
return nacosPropertySource;
}
//com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder#loadNacosData
private List<PropertySource<?>> loadNacosData(String dataId, String group,
String fileExtension) {
String data = null;
try {
//獲取配置
data = configService.getConfig(dataId, group, timeout);
if (StringUtils.isEmpty(data)) {
log.warn(
"Ignore the empty nacos configuration and get it based on dataId[{}] & group[{}]",
dataId, group);
return Collections.emptyList();
}
if (log.isDebugEnabled()) {
log.debug(String.format(
"Loading nacos data, dataId: '%s', group: '%s', data: %s", dataId,
group, data));
}
return NacosDataParserHandler.getInstance().parseNacosData(dataId, data,
fileExtension);
}
catch (NacosException e) {
log.error("get data from Nacos error,dataId:{} ", dataId, e);
}
catch (Exception e) {
log.error("parse data from Nacos error,dataId:{},data:{}", dataId, data, e);
}
return Collections.emptyList();
}
//com.alibaba.nacos.client.config.NacosConfigService#getConfig
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {
return getConfigInner(namespace, dataId, group, timeoutMs);
}
//com.alibaba.nacos.client.config.NacosConfigService#getConfigInner
private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {
group = blank2defaultGroup(group);
ParamUtils.checkKeyParam(dataId, group);
//聲明響應
ConfigResponse cr = new ConfigResponse();
//設置dataId,tenant,group
cr.setDataId(dataId);
cr.setTenant(tenant);
cr.setGroup(group);
// use local config first
//先從本地緩存中加載
String content = LocalConfigInfoProcessor.getFailover(worker.getAgentName(), dataId, group, tenant);
if (content != null) {
LOGGER.warn("[{}] [get-config] get failover ok, dataId={}, group={}, tenant={}, config={}",
worker.getAgentName(), dataId, group, tenant, ContentUtils.truncateContent(content));
cr.setContent(content);
String encryptedDataKey = LocalEncryptedDataKeyProcessor
.getEncryptDataKeyFailover(agent.getName(), dataId, group, tenant);
cr.setEncryptedDataKey(encryptedDataKey);
configFilterChainManager.doFilter(null, cr);
content = cr.getContent();
return content;
}
try {
//從服務器獲取配置
ConfigResponse response = worker.getServerConfig(dataId, group, tenant, timeoutMs, false);
cr.setContent(response.getContent());
cr.setEncryptedDataKey(response.getEncryptedDataKey());
configFilterChainManager.doFilter(null, cr);
content = cr.getContent();
return content;
} catch (NacosException ioe) {
if (NacosException.NO_RIGHT == ioe.getErrCode()) {
throw ioe;
}
LOGGER.warn("[{}] [get-config] get from server error, dataId={}, group={}, tenant={}, msg={}",
worker.getAgentName(), dataId, group, tenant, ioe.toString());
}
LOGGER.warn("[{}] [get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}",
worker.getAgentName(), dataId, group, tenant, ContentUtils.truncateContent(content));
content = LocalConfigInfoProcessor.getSnapshot(worker.getAgentName(), dataId, group, tenant);
cr.setContent(content);
String encryptedDataKey = LocalEncryptedDataKeyProcessor
.getEncryptDataKeyFailover(agent.getName(), dataId, group, tenant);
cr.setEncryptedDataKey(encryptedDataKey);
configFilterChainManager.doFilter(null, cr);
content = cr.getContent();
return content;
}
3.1.2、將NacosPropertySource加入composite的第一個
//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#addFirstPropertySource
private void addFirstPropertySource(final CompositePropertySource composite,
NacosPropertySource nacosPropertySource, boolean ignoreEmpty) {
if (null == nacosPropertySource || null == composite) {
return;
}
if (ignoreEmpty && nacosPropertySource.getSource().isEmpty()) {
return;
}
composite.addFirstPropertySource(nacosPropertySource);
}
3.2、加載extention
private void loadExtConfiguration(CompositePropertySource compositePropertySource) {
//獲取extention節點的配置信息
List<NacosConfigProperties.Config> extConfigs = nacosConfigProperties
.getExtensionConfigs();
//如果不為空,加載
if (!CollectionUtils.isEmpty(extConfigs)) {
checkConfiguration(extConfigs, "extension-configs");
loadNacosConfiguration(compositePropertySource, extConfigs);
}
}
3.3、加載主配置文件
private void loadApplicationConfiguration(
CompositePropertySource compositePropertySource, String dataIdPrefix,
NacosConfigProperties properties, Environment environment) {
//獲取文件擴展名
String fileExtension = properties.getFileExtension();
//獲取group
String nacosGroup = properties.getGroup();
// load directly once by default
//加載nacos的配置
loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup,
fileExtension, true);
// load with suffix, which have a higher priority than the default
//加載帶后綴的配置,優先級高于上一個
loadNacosDataIfPresent(compositePropertySource,
dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true);
// Loaded with profile, which have a higher priority than the suffix
for (String profile : environment.getActiveProfiles()) {
String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension;
//加載帶profile,文件格式后綴的配置,優先級高于上一個
loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
fileExtension, true);
}
}
這里會加載至少三個nacos上面的配置文件,按優先級依次為application,application.yaml,application-dev.yaml。
原文鏈接:https://blog.csdn.net/xuwenjingrenca/article/details/125155368
相關推薦
- 2022-07-21 常見CSS樣式
- 2022-07-26 討論nginx?location?順序問題_nginx
- 2022-10-11 React - 判斷焦點是否在某個元素上
- 2022-08-22 Python利用字典和列表實現學生信息管理系統_python
- 2022-09-17 C++中stack的pop()函數返回值解析_C 語言
- 2022-09-08 Docker容器使用方法詳解_docker
- 2023-01-05 Kotlin?object的幾種用法示例詳解_Android
- 2022-07-15 go學習筆記讀取consul配置文件詳解_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支