spring cloud config server源码学习(一)

news2025/1/15 6:45:42

文章目录

  • 1. 注解EnableConfigServer
  • 2. ConfigServerAutoConfiguration
    • 2.1 @ConditionalOnBean和@ConditionalOnProperty
    • 2.2 @Import注解
      • 2.2.1. EnvironmentRepositoryConfiguration.class
      • 2.2.2. CompositeConfiguration.class
      • 2.2.3. ResourceRepositoryConfiguration.class
      • 2.2.4. ConfigServerEncryptionConfiguration.class
      • 2.2.5. ConfigServerMvcConfiguration.class
      • 2.2.6. ResourceEncryptorConfiguration.class
  • 3. EnvironmentRepository
  • 4. EnvironmentRepositoryConfiguration.class
  • 5. rest接口

spring cloud config server 作为一个spring boot工程,到底是如何运行起来的?似乎如上一篇文章中那样,引入了starter,启动了注解,配置了git的信息,就可以获取到数据了。那具体的原理是什么呢?

1. 注解EnableConfigServer

@EnableConfigServer
@SpringBootApplication
@EnableDiscoveryClient
public class ConfigServer {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServer.class, args);
    }
}

可以看到启动类上加入注解@EnableConfigServer。我们查看该注解的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ConfigServerConfiguration.class)
public @interface EnableConfigServer {

}

这个注解的定义当中,通过Import注解加载Bean ConfigServerConfiguration.class

@Configuration(proxyBeanMethods = false)
public class ConfigServerConfiguration {

	@Bean
	public Marker enableConfigServerMarker() {
		return new Marker();
	}

	class Marker {

	}

}

这个Configuration类只是加载了一个 Bean Marker。
这是spring加载Bean的一种常用方式。

2. ConfigServerAutoConfiguration

在spring cloud config Server的jar中,org.springframework.boot.autoconfigure.AutoConfiguration.imports文件内包含了多个自动配置的类,其中就包括ConfigServerAutoConfiguration类。

org.springframework.cloud.config.server.bootstrap.ConfigServerBootstrapOverridesAutoConfiguration
org.springframework.cloud.config.server.config.ConfigServerAutoConfiguration
org.springframework.cloud.config.server.config.RsaEncryptionAutoConfiguration
org.springframework.cloud.config.server.config.DefaultTextEncryptionAutoConfiguration
org.springframework.cloud.config.server.config.EncryptionAutoConfiguration
org.springframework.cloud.config.server.config.VaultEncryptionAutoConfiguration

根据命名,可以看到各个自动配置类的功能,是启用bootstrap配置还是启用RSA加密等等。这里暂时先关注
ConfigServerAutoConfiguration类:

@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(ConfigServerConfiguration.Marker.class)
@ConditionalOnProperty(name = ConfigServerProperties.PREFIX + ".enabled", matchIfMissing = true)
@EnableConfigurationProperties(ConfigServerProperties.class)
@Import({ EnvironmentRepositoryConfiguration.class, CompositeConfiguration.class, ResourceRepositoryConfiguration.class,
		ConfigServerEncryptionConfiguration.class, ConfigServerMvcConfiguration.class,
		ResourceEncryptorConfiguration.class })
public class ConfigServerAutoConfiguration {

}

这个类的注解包含了三个重要的注解@ConditionalOnBean、@ConditionalOnProperty和@Import。

2.1 @ConditionalOnBean和@ConditionalOnProperty

当这两个注解出现在同一个类上的时候,两个Conditional条件必须同时满足,即ConfigServerConfiguration.Marker.class这个Bean存在的同时,还要满足Spring环境属性中存在 ConfigServerProperties.PREFIX + “.enabled” 属性且其值为 true,或者该属性缺失(由于 matchIfMissing = true)。这个PREFIX是spring.cloud.config.server。
这里刚好好上面通过@EnableConfigServer加载的Bean Marker.class呼应上。

2.2 @Import注解

Import注解引入了六个类要加载到spring context中。

2.2.1. EnvironmentRepositoryConfiguration.class

EnvironmentRepositoryConfiguration 是Spring Cloud Config Server中配置存储库的核心配置类。它负责创建和配置EnvironmentRepository实例,EnvironmentRepository用于从各种后端(如Git、SVN、本地文件系统等)获取配置属性。

定义和配置不同类型的EnvironmentRepository(如GitEnvironmentRepository、NativeEnvironmentRepository)。
通过注入不同的配置属性,来灵活配置不同类型的存储库。

2.2.2. CompositeConfiguration.class

CompositeConfiguration 负责配置和管理CompositeEnvironmentRepository。CompositeEnvironmentRepository允许将多个EnvironmentRepository组合在一起,以便从多个源获取配置。

配置CompositeEnvironmentRepository,将多个EnvironmentRepository实例组合成一个逻辑上的存储库。
提供从多个配置源合并配置属性的功能,以实现更复杂的配置管理场景。

2.2.3. ResourceRepositoryConfiguration.class

ResourceRepositoryConfiguration 负责配置与管理资源存储库(ResourceRepository)。ResourceRepository用于访问和管理配置服务器上的静态资源,如配置文件、密钥等。

配置不同类型的ResourceRepository,如文件系统资源存储库或Git资源存储库。
通过REST接口提供资源访问和管理功能。

2.2.4. ConfigServerEncryptionConfiguration.class

ConfigServerEncryptionConfiguration 负责配置加密和解密功能。它提供加密和解密配置属性的能力,确保敏感数据在传输和存储时得到保护。

配置加密器(TextEncryptor),用于加密和解密敏感配置信息。
提供加密和解密端点,允许客户端通过API进行加密和解密操作。

2.2.5. ConfigServerMvcConfiguration.class

ConfigServerMvcConfiguration 配置Spring MVC相关的组件,为Spring Cloud Config Server提供RESTful API。它定义了Config Server的主要控制器和路由。

定义Config Server的REST API端点,处理配置属性的请求。
配置HTTP请求处理、路由和控制器。

2.2.6. ResourceEncryptorConfiguration.class

ResourceEncryptorConfiguration 负责配置与资源加密相关的功能。它确保资源存储库中的敏感数据在存储和访问时得到加密保护。

配置用于资源加密和解密的组件。
提供加密资源的支持,确保静态资源的安全性。

3. EnvironmentRepository

对于 Spring Cloud Config 而言,它把所有的配置信息抽象为一种 Environment(环境),而存储这些配置信息的地方就称为 EnvironmentRepository。

public interface EnvironmentRepository {

	Environment findOne(String application, String profile, String label);

	default Environment findOne(String application, String profile, String label, boolean includeOrigin) {
		return findOne(application, profile, label);
	}

}

spring cloud中把配置信息抽象为application,profile和label三个维度来管理,即哪一个应用application在什么样的环境profile下,使用哪一个label的配置数据。

4. EnvironmentRepositoryConfiguration.class

这个类里加载很多的内容,包括svn、git、jdbc等等的RepositoryConfiguration。其中有一个Configuration类是DefaultRepositoryConfiguration.class。这个是放在最后一个加载的配置,即默认的配置:

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(value = EnvironmentRepository.class, search = SearchStrategy.CURRENT)
class DefaultRepositoryConfiguration {

	@Bean
	public MultipleJGitEnvironmentRepository defaultEnvironmentRepository(
			MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory,
			MultipleJGitEnvironmentProperties environmentProperties) throws Exception {
		return gitEnvironmentRepositoryFactory.build(environmentProperties);
	}

}

这里是加载MultipleJGitEnvironmentRepository的Bean,由gitEnvironmentRepositoryFactory的build方法来构建:

public MultipleJGitEnvironmentRepository build(MultipleJGitEnvironmentProperties environmentProperties)
			throws Exception {
		if (this.connectionFactory.isPresent()) {
			HttpTransport.setConnectionFactory(this.connectionFactory.get());
			this.connectionFactory.get().addConfiguration(environmentProperties);
		}

		MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment,
				environmentProperties, ObservationRegistry.NOOP);
		repository.setTransportConfigCallback(transportConfigCallbackFactory.build(environmentProperties));
		if (this.server.getDefaultLabel() != null) {
			repository.setDefaultLabel(this.server.getDefaultLabel());
		}
		repository.setGitCredentialsProviderFactory(gitCredentialsProviderFactory);
		repository.getRepos()
				.forEach((name, repo) -> repo.setGitCredentialsProviderFactory(gitCredentialsProviderFactory));
		return repository;
	}

而DefaultRepositoryConfiguration这个类,被GitRepositoryConfiguration继承了。

@Configuration(proxyBeanMethods = false)
@Profile("git")
class GitRepositoryConfiguration extends DefaultRepositoryConfiguration {

}

也就是说 Spring Cloud Config 中默认使用 Git 作为配置仓库来完成配置信息的存储和管理,提供的 EnvironmentRepository 就是 MultipleJGitEnvironmentRepository,而 MultipleJGitEnvironmentRepository 则继承了抽象类 JGitEnvironmentRepository。

当服务器启动时,在 JGitEnvironmentRepository 中会决定是否调用 initClonedRepository() 方法来完成从远程 Git 仓库 Clone 代码。如果执行了这一操作,相当于会将配置文件从 Git 上 clone 到本地,然后再进行其他的操作。在 JGitEnvironmentRepository 抽象类中,提供了大量针对第三方 Git 仓库的操作代码,无论采用诸如 Git、SVN 等具体某一种配置仓库的实现方式,最终我们处理的对象都是位于本地文件系统中的配置文件。

请添加图片描述
在AbstractScmEnvironmentRepository类中

@Override
	public synchronized Environment findOne(String application, String profile, String label) {
		return findOne(application, profile, label, false);
	}

	@Override
	public synchronized Environment findOne(String application, String profile, String label, boolean includeOrigin) {
		NativeEnvironmentRepository delegate = new NativeEnvironmentRepository(getEnvironment(),
				new NativeEnvironmentProperties(), this.observationRegistry);
		Locations locations = getLocations(application, profile, label);
		delegate.setSearchLocations(locations.getLocations());
		Environment result = delegate.findOne(application, profile, "", includeOrigin);
		result.setVersion(locations.getVersion());
		result.setLabel(label);
		return this.cleaner.clean(result, getWorkingDirectory().toURI().toString(), getUri());
	}

在上面的findOne方法中,调用了NativeEnvironmentRepository类的findOne方法:

@Override
	public Environment findOne(String config, String profile, String label, boolean includeOrigin) {

		try {
			ConfigurableEnvironment environment = getEnvironment(config, profile, label);
			DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
			Map<org.springframework.core.env.PropertySource<?>, PropertySourceConfigData> propertySourceToConfigData = new HashMap<>();
			ConfigDataEnvironmentPostProcessor.applyTo(environment, resourceLoader, null,
					StringUtils.commaDelimitedListToSet(profile), new ConfigDataEnvironmentUpdateListener() {
						@Override
						public void onPropertySourceAdded(org.springframework.core.env.PropertySource<?> propertySource,
								ConfigDataLocation location, ConfigDataResource resource) {
							propertySourceToConfigData.put(propertySource,
									new PropertySourceConfigData(location, resource));
						}
					});

			environment.getPropertySources().remove("config-data-setup");
			return clean(ObservationEnvironmentRepositoryWrapper
					.wrap(this.observationRegistry, new PassthruEnvironmentRepository(environment))
					.findOne(config, profile, label, includeOrigin), propertySourceToConfigData);
		}
		catch (Exception e) {
			String msg = String.format("Could not construct context for config=%s profile=%s label=%s includeOrigin=%b",
					config, profile, label, includeOrigin);
			String completeMessage = NestedExceptionUtils.buildMessage(msg,
					NestedExceptionUtils.getMostSpecificCause(e));
			throw new FailedToConstructEnvironmentException(completeMessage, e);
		}
	}

我们看到最终委托 PassthruEnvironmentRepository 完成配置文件的读取,然后通过 clean 方法完成本地文件地址与远程仓库之间地址的转换。ConfigDataEnvironmentUpdateListener用于监听Environment的更新。

5. rest接口

Server端获取到了数据,是通过rest接口来提供给client的。这里EnvironmentController提供了rest接口:

@GetMapping(path = "/{name}/{profiles:(?!.*\\b\\.(?:ya?ml|properties|json)\\b).*}",
			produces = MediaType.APPLICATION_JSON_VALUE)
	public Environment defaultLabel(@PathVariable String name, @PathVariable String profiles) {
		return getEnvironment(name, profiles, null, false);
	}

	@GetMapping(path = "/{name}/{profiles:(?!.*\\b\\.(?:ya?ml|properties|json)\\b).*}",
			produces = EnvironmentMediaType.V2_JSON)
	public Environment defaultLabelIncludeOrigin(@PathVariable String name, @PathVariable String profiles) {
		return getEnvironment(name, profiles, null, true);
	}

	@GetMapping(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);
	}

	@GetMapping(path = "/{name}/{profiles}/{label:.*}", produces = EnvironmentMediaType.V2_JSON)
	public Environment labelledIncludeOrigin(@PathVariable String name, @PathVariable String profiles,
			@PathVariable String label) {
		return getEnvironment(name, profiles, label, true);
	}

这里要注意path路径的配置,在类注解上有@RequestMapping(method = RequestMethod.GET, path = “${spring.cloud.config.server.prefix:}”)可以配置前缀,不配置的话就是默认值“”。
在方法上的路径,是/name/profile/label。这个正是配置文件中配置的内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1691251.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

最新可用GPT-4o模型4大方法免费使用

探索GPT-4o&#xff1a;一次界限突破的AI体验&#xff01; 在AI世界的最前沿&#xff0c;GPT-4o的亮相已经掀起了一场技术革命的风暴&#xff01;它的问世不仅在行业内部引起了剧烈的震动&#xff0c;更是激起了一波波全球性的讨论和热烈追捧。 既然你在这里&#xff0c;我知…

Prometheus监控平台配置--监控mysql

上一篇中讲述了怎么安装Prometheus&#xff0c;然后对服务器集群资源信息进行监控并通过grafana展示监控信息&#xff0c;在这一篇中我们只讲和mysql相关的监控&#xff0c;关于prometheus的监控原理以及安装可以看下上一篇。 1.上传 通过rz命令将安装包上传到任意目录&#xf…

JVM1.8分代的理论基础和简单测试

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

Redhat7.4部署MySQL-5.7.17搭建双主互为主从

一、准备工作 需要先准备已经搭建好的两台数据库&#xff0c;并且保证服务器之间网络是通的&#xff0c;3306端口可以相互访问。 二、修改两台数据库my.cnf 配置文件&#xff0c;将下列内容添加进去&#xff0c;放在 [mysqld] 下 我们暂定两台服务器为A服务和B服务&#xff…

分享一个用AI降本的思路,不懂代码也能上手

如何用AI解决实际的业务问题&#xff1f; 生财圈友我来利用ChatGPT做算法建模&#xff0c;每年为公司省下6万元。 今天他将分享通过ChatGPT进行数据分析的思路&#xff0c;从最开始定义问题到最终数据论证。 上手的实操过程门槛并不高&#xff0c;但可以实现把官方电商平台的…

ts 字符串不能做索引异常提示 type because expression of type ‘string‘

Element implicitly has an any type because expression of type string cant be used to index type 例子 let a{b:"1",c:"1" } var b"b"; let ca[b] let ca[b]就会爆这个错误&#xff0c;因为在编译器看来b是一个未知的东西&#xff0c;它不…

生物识别技术存在的问题及需要考虑的关键事项

微信关注公众号网络研究观获取更多。 对数字身份验证不太了解的人通常认为生物识别技术是我们所有身份验证问题的答案。 许多人认为身份验证的终极是面部识别&#xff0c;甚至可能是 DNA 分析。 生物识别技术&#xff08;例如指纹、面部、虹膜、视网膜、静脉、几何、语音、…

148.【Windows DOS命令脚本文件】

Window待处理脚本 (一)、批处理编程初步体验1.什么是批处理程序&#xff1f;(1).批处理程序的定义(2).如何编辑批处理程序 2.批处理程序可以做什么&#xff1f;(1).匹配规则删除文件(2).新建文件&#xff0c;日志等(3).创建计算机病毒等 3.一个基本的批处理文件(1).带盘符的输出…

Java_多线程

有了多线程&#xff0c;我们就可以让程序同时做多件事情 作用&#xff1a; 提高效率 应用场景&#xff1a; 只要想让多个事情同时运行就需要用到多线程 比如&#xff1a;软件中的耗时操作、所有的聊天软件、所有的服务器... 并发和并行 并发&#xff1a;在同一时刻&#xff0…

一文详解逻辑越权漏洞

1. 逻辑越权 1.1. 漏洞原理 逻辑越权漏洞就是当用户跳过自己的权限限制&#xff0c;去操作同等级用户或者上级用户。正常的情况下&#xff0c;当一个用户去访问某个资源的时候&#xff0c;首先需要去登录验证自己的权限&#xff0c;其次是对数据的查询&#xff0c;最后返回数…

2024年学浪视频怎么下载到手机相册

随着2024年的到来&#xff0c;学浪平台继续为广大学习者提供优质的在线教育资源。然而&#xff0c;如何将这些宝贵的视频内容下载到手机相册&#xff0c;方便随时离线观看呢&#xff1f;无论您是想在旅途中学习&#xff0c;还是希望在没有网络的情况下复习课程&#xff0c;本文…

Linux之单机项目部署

1、虚拟机&#xff08;VMware&#xff09;创建Linux系统 1.1、创建虚拟机 1.2、配置虚拟机IOS映射文件 1.3、虚拟机内部相关配置 等待加载即可&#xff0c;加载完后会弹出图形化界面&#xff0c;如图&#xff1a; 注意&#xff1a;一般我们做为管理员使用ROOT账号来操作&#x…

Java之SpringSecurity使用心得

文章目录 一、内存身份认证二、jdbc身份认证三、自定义登录页 一、内存身份认证 添加pom依赖 <!-- Spring Security提供的安全管理依赖启动器 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-s…

串口服务器在工业控制领域的应用:深度解析与前沿实践

在工业控制领域&#xff0c;随着技术的不断发展&#xff0c;传统的串口通信方式已经难以满足现代工业系统对高效、稳定、安全通信的需求。此时&#xff0c;串口服务器作为一种先进的通信技术解决方案&#xff0c;正在逐步改变工业控制领域的通信格局。本文将深度解析串口服务器…

第十届水利、土木工程国际学术会议暨工程安全与防灾论坛 (ICHCE ESDP 2024)

文章目录 一、会议详情二、重要信息三、会议简介四、组织单位五、出席嘉宾六、大会议程七、咨询 一、会议详情 二、重要信息 会议官网&#xff1a;www.ichce.org 大会时间&#xff1a;2024年8月9-11日 最后一轮截稿时间&#xff1a;2024年6月30日 报名截止时间&#xff1a;2…

得物小程序逆向+qt可视化(不含sku)

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872 本文章未…

linux-配置服务器之间 ssh免密登录

前言 在管理多台Linux服务器时,为了方便操作和自动化任务,实现服务器之间的SSH免密登录是非常有必要的。SSH免密登录可以避免每次远程连接时输入密码,大大提高效率。本文将详细介绍SSH免密登录的原理和实现步骤。 一、原理解释 SSH免密登录的实现依赖于SSH密钥对,主要是利用…

为什么手机冬天续航短 – 锂电池的温度特性曲线

原文出自微信公众号【小小的电子之路】 相信大家都有这样的经历&#xff1a;手机的续航能力在寒冷的冬天会有一定程度的降低&#xff0c;有些手机甚至充不进去电。在这种情况下&#xff0c;有些人可能会在手机上贴一个暖宝宝。其实这个问题不止出现在手机上&#xff0c;大家如果…

Mybatis Cache(一)MybatisCache+Redis

前面提到了&#xff0c;使用mybatis cache&#xff0c;一般是结合redis使用。 一、demo 1、数据表 create table demo.t_address (id int auto_incrementprimary key,address_name varchar(200) null,address_code varchar(20) null,address_type int n…

Java进阶学习笔记4——Static应用知识:代码块

代码块&#xff1a; 代码块是类的五大成员之一&#xff08;成员变量、构造器、方法、代码块、内部类&#xff09;。 Java类生命周期&#xff1a;加载、验证、准备、初始化、卸载。 代码块分为两种&#xff1a; 静态代码块&#xff1a; 格式&#xff1a;static {} 特点&…