Spring Cloud全解析:配置中心之springCloudConfig获取远程配置

server/2024/11/15 6:16:33/

springCloudConfig获取远程配置

client端获取配置

springCloudConfig核心其实在于实现了一个PropertySourceLocator接口来进行获取远程配置的

java">@Order(0)
public class ConfigServicePropertySourceLocator implements PropertySourceLocator {@Override@Retryable(interceptor = "configServerRetryInterceptor")public org.springframework.core.env.PropertySource<?> locate(org.springframework.core.env.Environment environment) {ConfigClientProperties properties = this.defaultProperties.override(environment);CompositePropertySource composite = new OriginTrackedCompositePropertySource("configService");RestTemplate restTemplate = this.restTemplate == null? getSecureRestTemplate(properties) : this.restTemplate;Exception error = null;String errorBody = null;try {String[] labels = new String[] { "" };if (StringUtils.hasText(properties.getLabel())) {labels = StringUtils.commaDelimitedListToStringArray(properties.getLabel());}String state = ConfigClientStateHolder.getState();// Try all the labels until one worksfor (String label : labels) {// 获取远程配置,这里就是使用restTemplate访问spring.cloud.config.uri对应的配置中心server地址/{name}/{profile}/{label}Environment result = getRemoteEnvironment(restTemplate, properties,label.trim(), state);if (result != null) {log(result);// result.getPropertySources() can be null if using xmlif (result.getPropertySources() != null) {for (PropertySource source : result.getPropertySources()) {@SuppressWarnings("unchecked")Map<String, Object> map = translateOrigins(source.getName(),(Map<String, Object>) source.getSource());composite.addPropertySource(new OriginTrackedMapPropertySource(source.getName(),map));}}if (StringUtils.hasText(result.getState())|| StringUtils.hasText(result.getVersion())) {HashMap<String, Object> map = new HashMap<>();putValue(map, "config.client.state", result.getState());putValue(map, "config.client.version", result.getVersion());composite.addFirstPropertySource(new MapPropertySource("configClient", map));}return composite;}}errorBody = String.format("None of labels %s found", Arrays.toString(labels));}catch (HttpServerErrorException e) {error = e;if (MediaType.APPLICATION_JSON.includes(e.getResponseHeaders().getContentType())) {errorBody = e.getResponseBodyAsString();}}catch (Exception e) {error = e;}if (properties.isFailFast()) {throw new IllegalStateException("Could not locate PropertySource and the fail fast property is set, failing"+ (errorBody == null ? "" : ": " + errorBody),error);}return null;}}

那么PropertySourceLocator接口是何时被调用的呢?

在springBoot启动的时候执行SpringApplication构造器的时候设置了ApplicationListener监听器

java">public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath();setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 设置ApplicationListener监听器setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = deduceMainApplicationClass();
}

其中监听器中有BootstrapApplicationListener,在该监听器中会加入一个ApplicationContextInitializer初始化器的实现类PropertySourceBootstrapConfiguration

java">Set target = new LinkedHashSet<>(application.getInitializers());
target.addAll(getOrderedBeansOfType(context, ApplicationContextInitializer.class));

而在applyInitializers(context)中会遍历initializers初始化器集合,调用initialize方法

java">for (ApplicationContextInitializer initializer : getInitializers()) {Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),ApplicationContextInitializer.class);Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");initializer.initialize(context);
}

在PropertySourceBootstrapConfiguration的initialize方法中会遍历propertySourceLocators集合,来执行PropertySourceLocator的locateCollection方法,这样就和springCloudConfig获取配置接上了,使用ConfigServicePropertySourceLocator类

server端获取配置

根据上边的代码可以看到已经请求到server端了,那么server端如何拿到配置呢?先找一下访问地址对应的controller,果然在EnvironmentController中找到了对应的地址

java">@RequestMapping(path = "/{name}/{profiles}/{label:.*}",produces = MediaType.APPLICATION_JSON_VALUE)
public Environment labelled(@PathVariable String name, @PathVariable String profiles,@PathVariable String label) {return getEnvironment(name, profiles, label, false);
}

这里会调用

java">Environment environment = this.repository.findOne(name, profiles, label,includeOrigin);

我们以git为例,也就是使用MultipleJGitEnvironmentRepository来进行获取

java">public Environment findOne(String application, String profile, String label,boolean includeOrigin) {for (PatternMatchingJGitEnvironmentRepository repository : this.repos.values()) {if (repository.matches(application, profile, label)) {for (JGitEnvironmentRepository candidate : getRepositories(repository,application, profile, label)) {try {if (label == null) {label = candidate.getDefaultLabel();}Environment source = candidate.findOne(application, profile,label, includeOrigin);if (source != null) {return source;}}catch (Exception e) {if (this.logger.isDebugEnabled()) {this.logger.debug("Cannot load configuration from " + candidate.getUri()+ ", cause: (" + e.getClass().getSimpleName()+ ") " + e.getMessage(),e);}continue;}}}}JGitEnvironmentRepository candidate = getRepository(this, application, profile,label);if (label == null) {label = candidate.getDefaultLabel();}if (candidate == this) {return super.findOne(application, profile, label, includeOrigin);}return candidate.findOne(application, profile, label, includeOrigin);
}

就简单点,假如是第一次进来,就不用看上边的遍历了,直接去获取

java">super.findOne(application, profile, label, includeOrigin);

这里调用的是AbstractScmEnvironmentRepository的方法,

java">public synchronized Environment findOne(String application, String profile,String label, boolean includeOrigin) {NativeEnvironmentRepository delegate = new NativeEnvironmentRepository(getEnvironment(), new NativeEnvironmentProperties());// 创建本地git仓库,从对应git上进行clone,pull等操作Locations locations = getLocations(application, profile, label);delegate.setSearchLocations(locations.getLocations());// 之后就可以从本地git仓库进行读取了Environment result = delegate.findOne(application, profile, "", includeOrigin);result.setVersion(locations.getVersion());result.setLabel(label);return this.cleaner.clean(result, getWorkingDirectory().toURI().toString(),getUri());
}

https://zhhll.icu/2021/框架/微服务/springcloud/配置中心/springCloudConfig/源码分析/1.springCloudConfig获取远程配置/


http://www.ppmy.cn/server/105356.html

相关文章

【Nginx】快速入门

概述 Nginx(engine x)是一个高性能的HTTP和反向代理web服务器。 特点是占有内存小&#xff0c;并发能力强&#xff0c;简单易配置&#xff0c;支持高达 50000 个并发连接数的响应。 作用 代理 正向代理&#xff1a; 反向代理&#xff1a; 负载均衡 Nginx提供的负载均衡策…

学习大数据DAY44 帆软 report 配置

目录 Linux 系统独立部署 Tomcat 服务器设置 上机练习 Linux 系统独立部署 ## 题目要求 在 LINUX 系统&#xff0c; Tomcat 服务器容器下&#xff0c;完成 FineReport 报表工程的独立部 署&#xff0c;并设置服务器开机自启动&#xff0c;并请实操演示 得分点&#xf…

AI 功能上新!用 Einstein Copilot for Tableau 加速商业数据分析全过程

从数据准备、可视化到目录管理&#xff0c;你可以尽情利用 Tableau AI 的强大能力&#xff0c;加速企业的分析洞察过程&#xff01; 在 Tableau 2024.2 发布时&#xff0c;产品团队宣布 Einstein Copilot for Tableau 将于 8 月上线。今天&#xff0c;我们发现这项 AI 新功能如…

Linux:CentOS配置

一&#xff0c;安装VMware 这个可以通过官网获取 vmware下载 也可以联系我&#xff0c;我发给你 二&#xff0c;安装CentOS Centos官网找要下载的版本&#xff1a; https://vault.centos.org/ 阿里云镜像&#xff1a;https://mirrors.aliyun.com/centos-vault/?spma2c6h.13…

MySQL连接类型

MySQL连接类型 1、连接 1.1 数据构造 CREATE TABLE departments ( department_id INT PRIMARY KEY, department_name VARCHAR(255) ); CREATE TABLE employees ( employee_id INT PRIMARY KEY, employee_name VARCHAR(255), department_id INT );INSERT INTO depart…

RPC 调用对比其他通信方式

RPC 调用能够实现进程间通信的原因在于其设计和实现方式&#xff0c;使其适合于跨进程、跨网络的函数调用。其他的通信机制如 HTTP、消息队列等也可以用于进程间通信&#xff0c;但它们的实现方式和特点与 RPC 不尽相同。以下是 RPC 调用及其与其他通信机制的比较&#xff1a; …

【人工智能】Python融合机器学习、深度学习和微服务的创新之路

目录 一、引言 1.1 背景概述 1.2 研究意义 1.3 研究方法与内容 二、Python在机器学习中的应用 2.1 机器学习概述 2.2 Python在机器学习中的优势 2.3 代码示例 三、Python在深度学习中的应用 3.1 深度学习概述 3.2 Python在深度学习中的创新应用 3.3 代码示例 四、P…

动态规划-打家劫舍Ⅱ

该题是打家劫舍Ⅰ的升级版并与其相关&#xff0c;如果对其感兴趣的话可以先看看打家劫舍Ⅰ 题目描述 一个专业的小偷&#xff0c;计划偷窃一个环形街道上沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈 &#xff0c;这意味着第一个房屋和最后…