如果你应用的是 spring-cloud-alibaba 微服务技术栈
单个服务独有配置文件
即去除应用程序的状态,配置对立内部化治理,不便进行程度的伸缩。
集成步骤:
如果我有一个利用 app-design;
1,引入依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
2, 配置文件;
spring.cloud.nacos.config.enabled=true
spring.cloud.nacos.config.refresh-enabled=true
spring.cloud.nacos.config.server-addr=${spring.cloud.nacos.discovery.server-addr}
spring.cloud.nacos.config.namespace=${spring.cloud.nacos.discovery.namespace}
阐明如下:
属性 | 阐明 |
---|---|
spring.cloud.nacos.config.server-addr=${spring.cloud.nacos.discovery.server-addr} | nacos 配置核心地址 |
spring.cloud.nacos.config.namespace=${spring.cloud.nacos.discovery.namespace} | nacos 的命名空间,这里跟服务发现的配置统一; |
3,应用配置的形式,同本地配置文件一样。
@Value @PropertyConfiguration 这些注解都是反对的;
4,确认形式,比方把之前的 application.properties 的配置放到了配置核心;
本地启动的时候,读取到了 8081 端口和数据库连接池的配置;
配置核心的连贯原理,前面独自整理出来,知其然并知其所以然。
服务之间共享配置文件
场景:多个后端微服务,在同一个集群中共用中间件的配置信息。
比方 缓存 redis, 音讯队列 kafka, 文件服务器,邮件服务器;
那么对应的配置文件没有必要在所有的后端微服务中独自存在,这些配置文件应该放在公共配置文件中,然而也能够被具体的后端微服务本人的独有配置文件笼罩,应用本人的公有配置;
可联合下图了解:
问题 | 答复 |
---|---|
where are we? 现状 | 中间件配置扩散在很多服务中,配置繁琐,不不便对立治理 |
where are we go? 目标 | 同一个集群的中间件只保护一份,各服务共享,也可依照须要笼罩共享的配置; |
how can we go there? 实现门路 | 基于 nacos 已有性能实现 |
上面是理论的 coding 过程和测试用例;
服务 app-file;
在服务对应的 nacos 的 namespace 中
1 引入共享配置
# 共享中间件的配置
spring.cloud.nacos.config.shared-configs[0].data-id=mid.properties
spring.cloud.nacos.config.shared-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.shared-configs[0].refresh=true
地位:模块 start 下的 src/main/resources/bootstrap.properties 文件中
自描述的配置信息,即引入的共享配置文件列表有哪些,能够依照须要,配置各种中间件的配置信息;
key | 阐明 |
---|---|
data-id | _the data id of extended configuration 配置文件名称,带上后缀;翻译:扩大配置文件的数据 id |
group | the group of extended configuration, the default value is DEFAULT_GROUP 集群名称,从名字来看,反对多集群的配置文件 翻译:扩大配置文件的集群,默认值是 _DEFAULT_GROUP |
refresh | _whether to support dynamic refresh, the default does not support 是否刷新 翻译:是否反对动静刷新,默认不反对 |
花括号 [0] , 外面的 0 是序号,如果有多个,依照数字自增程序进行配置;
2 在 nacos 中新增配置文件
依据理论场景在 nacos 的 test 命名空间中新增配置文件 mid.properties
3 获取配置用例测试
测试接口代码:
@ApiOperation("测试获取公共配置文件")
@GetMapping("/config/test")
public Response config(){String redisConfigServers = environment.getProperty("redis.config.servers","null");
return SingleResponse.of(redisConfigServers);
}
测试用例:
场景 | 冀望后果 | 理论后果 | 是否合乎预期 |
---|---|---|---|
获取共享配置文件中的配置 | r-wz9sp7dhxjnz16bs1jzhutj.redis.rds.aliyuncs.com:6379 | r-wz9sp7dhxjnz16bs1jzhutj.redis.rds.aliyuncs.com:6379 | 是 |
在服务独有 app-file.properties 配置中重写配置 redis.config.servers=r-wz9sp7dhxjnz16bs1jzhutj.redis.rds.aliyuncs.com:637905 | r-wz9sp7dhxjnz16bs1jzhutj.redis.rds.aliyuncs.com:637905 | r-wz9sp7dhxjnz16bs1jzhutj.redis.rds.aliyuncs.com:637905 | 是 |
截图如下:
源码剖析
把握用法之后,深入分析源码,知其然而知其所以然;
starter 调用封装
应用的 starter 封装;
https://github.com/alibaba/spring-cloud-alibaba/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config
版本:2.2.1.RELEASE
启动的时候主动拆卸的配置如下:
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.NacosConfigAutoConfiguration,\
com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer
合成一下 key,看一下用处:
key | 阐明 |
---|---|
org.springframework.cloud.bootstrap.BootstrapConfiguration | A marker interface used as a key in META-INF/spring.factories . Entries in* the factories file are used to create the bootstrap application context. |
翻译:一个标记注解用来作为 key 放在 META-INF/spring.factories 文件中,文件中的条目用来创立启动利用的上下文;
起源:spring-cloud-context-version.jar
value:
com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration |
| org.springframework.boot.autoconfigure.EnableAutoConfiguration | 正文太长了,不放这里. 放到附录中。
起源:spring-boot-autoconfigure-version.jar
com.alibaba.cloud.nacos.NacosConfigAutoConfiguration,\
com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration |
| org.springframework.boot.diagnostics.FailureAnalyzer | A {@code FailureAnalyzer} is used to analyze a failure and provide diagnostic* information that can be displayed to the user.
_
翻译:FailureAnalyzer 用来剖析谬误并提供诊断信息展现给到用户
起源:spring-boot-version.jar
com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer |
而后看看都主动拆卸了什么?以及主动拆卸的过程。
springboot 的形式调用;
1 NacosConfigBootstrapConfiguration
源码:
package com.alibaba.cloud.nacos;
import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaojing
*/
@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);
}
}
主动拆卸流程:
配置文件组装源码:
@Override
public PropertySource<?> locate(Environment env) {nacosConfigProperties.setEnvironment(env);
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 = new NacosPropertySourceBuilder(configService,
timeout);
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;
}
加载利用配置文件的程序源码:
private void loadApplicationConfiguration(
CompositePropertySource compositePropertySource, String dataIdPrefix,
NacosConfigProperties properties, Environment environment) {String fileExtension = properties.getFileExtension();
String nacosGroup = properties.getGroup();
// load directly once by default
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;
loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
fileExtension, true);
}
}
程序如下:
序号 | 阐明 |
---|---|
1 | 加载 dataIdPrefix 对应的配置文件 |
2 | 加载 dataIdPrefix.fileExtension 对应的配置文件 |
3 | 加载 dataIdPrefix-activeProfiles.fileExtension 对应的配置文件 |
2.1 NacosConfigAutoConfiguration
序号 | 阐明 |
---|---|
1 | NacosConfigProperties nacos 配置 |
2 | NacosRefreshProperties 曾经不倡议被应用 |
3 | NacosRefreshHistory 刷新历史 |
4 | NacosConfigManager 配置 |
5 | NacosContextRefresher 注册 nacos 的监听器到利用 |
2.2 NacosConfigEndpointAutoConfiguration
NacosConfigEndpoint
本地配置同步逻辑
@ReadOperation
public Map<String, Object> invoke() {Map<String, Object> result = new HashMap<>(16);
result.put("NacosConfigProperties", properties);
List<NacosPropertySource> all = NacosPropertySourceRepository.getAll();
List<Map<String, Object>> sources = new ArrayList<>();
for (NacosPropertySource ps : all) {Map<String, Object> source = new HashMap<>(16);
source.put("dataId", ps.getDataId());
source.put("lastSynced", dateFormat.get().format(ps.getTimestamp()));
sources.add(source);
}
result.put("Sources", sources);
result.put("RefreshHistory", refreshHistory.getRecords());
return result;
}
NacosConfigHealthIndicator
健康检查 UP,DOWN,UNKNOWN ;
3 NacosConnectionFailureAnalyzer
连贯不上 nacos 服务端抛出异样
@Override
protected FailureAnalysis analyze(Throwable rootFailure,
NacosConnectionFailureException cause) {
return new FailureAnalysis(
"Application failed to connect to Nacos server: \""
+ cause.getServerAddr() + "\"",
"Please check your Nacos server config", cause);
}
小结:服务通过集成该 starter,通过 http 申请从 nacos 的服务端拉取配置数据,并做了 配置刷新历史,注册监听器到 spring 容器中,本地缓存,和错误报告;
服务端封装
源码地位:https://github.com/alibaba/nacos/tree/develop/config
利用启动读取配置文件整体调用链:待后续实现;
小结
如果读完本篇文章你只能记住一句话:nacos 作为配置核心可为独自的服务提供内部化配置文件,也反对多利用共享配置文件。
从 nacos 的客户端源码剖析中可看到一些配置优先级的程序。
原创不易,关注诚可贵,转发价更高!转载请注明出处,让咱们互通有无,共同进步,欢送沟通交流。