springcloud情操陶冶-springcloud config server(一)
承接前文springcloud情操陶冶-springcloud context(二),本文将在前文基础上浅析下ConfigServer的工作原理
前话
根据前文得知,bootstrapContext引入了PropertySourceLocator接口供外部源加载配置,但作用是应用于子级ApplicationContext的环境变量Environment上,并不做更新维护操作。
具体的加载与维护更新外部源的配置信息,还是得有ConfigServer来完成,这也是本文分析的重点。
监听器
在这之前,笔者先查看此板块关联的监听器ConfigServerBootstrapApplicationListener,因为其比前文分析的BootstrapApplicationListener监听器优先级还高,不过内部代码很简单,笔者直接查看其复写的方法
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
if (!environment.resolvePlaceholders("${spring.cloud.config.enabled:false}")
.equalsIgnoreCase("true")) {
if (!environment.getPropertySources().contains(this.propertySource.getName())) {
environment.getPropertySources().addLast(this.propertySource);
}
}
}
代码意思很简单,针对环境变量中spring.cloud.config.enabled属性如果值不为true则设置为false。根据官方上的代码注释来看,是用于屏蔽HTTP方式的访问,默认是开启屏蔽功能的。也就是屏蔽了ConfigServer暴露Restful方式的接口访问,其中该属性可通过System系统变量或者SpringApplicationBuilder类来进行设置,具体读者可查阅其官方注释
这个影响小,我们直接去查看其如何去加载外部源的
BootstrapContext关联类
优先分析与bootstrapContext相关的类,通过查看其板块下的spring.factories文件对应的BootstrapConfiguration键值
# Bootstrap components
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.config.server.bootstrap.ConfigServerBootstrapConfiguration,\
org.springframework.cloud.config.server.config.EncryptionAutoConfiguration
笔者挑选ConfigServerBootstrapConfiguration类作为主要的分析源头,内部的源码比较简单,笔者则全部放出来
// 系统变量或者bootstrap.properties文件指定了spring.cloud.config.server.bootstrap属性则生效
@Configuration
@ConditionalOnProperty("spring.cloud.config.server.bootstrap")
public class ConfigServerBootstrapConfiguration {
@EnableConfigurationProperties(ConfigServerProperties.class)
@Import({ EnvironmentRepositoryConfiguration.class })
protected static class LocalPropertySourceLocatorConfiguration {
@Autowired
private EnvironmentRepository repository;
@Autowired
private ConfigClientProperties client;
@Autowired
private ConfigServerProperties server;
// 加载外部源入口
@Bean
public EnvironmentRepositoryPropertySourceLocator environmentRepositoryPropertySourceLocator() {
return new EnvironmentRepositoryPropertySourceLocator(this.repository, this.client.getName(),
this.client.getProfile(), getDefaultLabel());
}
private String getDefaultLabel() {
if (StringUtils.hasText(this.client.getLabel())) {
return this.client.getLabel();
} else if (StringUtils.hasText(this.server.getDefaultLabel())) {
return this.server.getDefaultLabel();
}
return null;
}
}
}
根据当前环境下是否存在spring.cloud.config.server.bootstrap属性来决定是否通过Git/SVN/Vault等方式(下文将提及)加载外部源至子级的ConfigurableEnvironment对象中,默认不开启,需要用户配置。
具体通过什么方式获取外部资源则交由EnvironmentRepository接口去实现,我们先看下此接口的方法
public interface EnvironmentRepository {
// 内部就一个方法,通过参数指定找寻对应的环境对象
Environment findOne(String application, String profile, String label);
}
看来其支持多仓库源的配置,但这里注意一下此处的Environment回参是springcloud config client板块中的类,应该是对我们常见的环境变量作些过滤的作用。
EnvironmentRepositoryConfiguration
除了上述的方式引入此多环境仓库的配置类,ConfigServer对应的ConfigServerAutoConfiguration默认也会引入。废话少说,首先看下头部
@Configuration
@EnableConfigurationProperties({ SvnKitEnvironmentProperties.class, CredhubEnvironmentProperties.class,
JdbcEnvironmentProperties.class, NativeEnvironmentProperties.class, VaultEnvironmentProperties.class })
@Import({ CompositeRepositoryConfiguration.class, JdbcRepositoryConfiguration.class, VaultRepositoryConfiguration.class,
CredhubConfiguration.class, CredhubRepositoryConfiguration.class, SvnRepositoryConfiguration.class,
NativeRepositoryConfiguration.class, GitRepositoryConfiguration.class, DefaultRepositoryConfiguration.class })
public class EnvironmentRepositoryConfiguration {
}
嗯,看起来很多,其实也就是针对不同源的资源进行相应的配置,比如常见的SVN/Jdbc/Git/Vault等方式。针对不同源,springcloud允许用户配置spring.profile.active属性来选择相应的源,即使不指定,springcloud也默认以Git方式获取仓库。本文以springcloud默认支持的Git方式作为分析的入口
GitRepositoryConfiguration
git方式的资源获取是通过配置GitRepositoryConfiguration类来实现的,笔者看下其代码
@Configuration
@Profile("git")
class GitRepositoryConfiguration extends DefaultRepositoryConfiguration {
}
直接去观察其继承的DefaultRepositoryConfiguration类,内部源码也很简单,顺便把其关联的一些bean也一同放上来,方便我们更清楚的了解
// 多Git环境仓库属性配置,以spring.cloud.config.server.git作为开头
@Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
public MultipleJGitEnvironmentProperties multipleJGitEnvironmentProperties() {
return new MultipleJGitEnvironmentProperties();
}
@Configuration
@ConditionalOnClass(TransportConfigCallback.class)
static class JGitFactoryConfig {
// 多Git环境仓库的工厂类
@Bean
public MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory(
ConfigurableEnvironment environment, ConfigServerProperties server,
Optional<ConfigurableHttpConnectionFactory> jgitHttpConnectionFactory,
Optional<TransportConfigCallback> customTransportConfigCallback) {
return new MultipleJGitEnvironmentRepositoryFactory(environment, server, jgitHttpConnectionFactory,
customTransportConfigCallback);
}
}
@Configuration
@ConditionalOnClass({ HttpClient.class, TransportConfigCallback.class })
static class JGitHttpClientConfig {
// HTTP连接工厂类
@Bean
public ConfigurableHttpConnectionFactory httpClientConnectionFactory() {
return new HttpClientConfigurableHttpConnectionFactory();
}
}
@Configuration
@ConditionalOnMissingBean(value = EnvironmentRepository.class, search = SearchStrategy.CURRENT)
class DefaultRepositoryConfiguration {
....
....
@Bean
public MultipleJGitEnvironmentRepository defaultEnvironmentRepository(
MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory,
MultipleJGitEnvironmentProperties environmentProperties) throws Exception {
return gitEnvironmentRepositoryFactory.build(environmentProperties);
}
}
这里注册的MultipleJGitEnvironmentRepository对象便是EnvironmentRepository接口的实现类,由其统一管理多Git仓库的资源。在分析此类之前,先对上述的代码作下分步骤的分析以免产生糊涂
1.多Git仓库属性配置MultipleJGitEnvironmentProperties,也就是配置Git仓库的地址以及访问方式等等。挑选比较重要的属性用于归纳(多仓库应用)
假设远程仓库地址为git@github.com:jtjsir/config_demo.git
spring.cloud.config.server.git.repos.A1.pattern=config* #A1仓库的匹配规则(匹配源{application}/{profile}),默认为下一点的name
spring.cloud.config.server.git.repos.A1.name=config_demo #A1仓库的别名
spring.cloud.config.server.git.repos.A1.uri=git@github.com:jtjsir/config_demo.git #远程git仓库地址
spring.cloud.config.server.git.repos.A1.username=nancoasky@gmail.com #git帐号
spring.cloud.config.server.git.repos.A1.password=nanco123 #git密码
spring.cloud.config.server.git.repos.A1.passphrase= #ssh密码短语,默认为空
spring.cloud.config.server.git.repos.A1.basedir=/data/demo/cloud #本地保存路径
spring.cloud.config.server.git.repos.A1.defaultLabel=master #标签,类似git的分支概念
具体的用户可查看MultipleJGitEnvironmentProperties类去详细的查看各个属性的含义,同时也可以了解SSH方式的校验
2.Http连接工厂类HttpClientConfigurableHttpConnectionFactory,主要是支持http/https的Git访问方式。具体就不讲解了,读者可自行分析
MultipleJGitEnvironmentRepository
顾名思义,其实就是JGitEnvironmentRepository类的集合类,我们只需要关注其复写的findOne()方法,附上真正去查找相应配置资源的AbstractScmEnvironmentRepository#findOne()方法
@Override
public synchronized Environment findOne(String application, String profile, String label) {
// 通过native方式去加载,也就是读取远程Git仓库的本地copy
NativeEnvironmentRepository delegate = new NativeEnvironmentRepository(getEnvironment(),
new NativeEnvironmentProperties());
// 1.获取本地git仓库的查找路径
Locations locations = getLocations(application, profile, label);
delegate.setSearchLocations(locations.getLocations());
// 2.获取属性集合
Environment result = delegate.findOne(application, profile, "");
result.setVersion(locations.getVersion());
result.setLabel(label);
// 过滤下
return this.cleaner.clean(result, getWorkingDirectory().toURI().toString(),
getUri());
}
笔者分析上述标注的两点,分步骤来
1.获取本地git仓库的查找路径,对应的是JGitEnvironmentRepository#getLocations()方法
@Override
public synchronized Locations getLocations(String application, String profile,
String label) {
// label代表git仓库的分支,默认为master
if (label == null) {
label = this.defaultLabel;
}
// 刷新本地git仓库,蕴含了拉取远程仓库、更新的操作。使用到了uri属性
String version = refresh(label);
// 使用到了basedir和searchPaths属性
return new Locations(application, profile, label, version,
getSearchLocations(getWorkingDirectory(), application, profile, label));
}
上述的搜寻路径格式如{basedir}/{searchPaths:/}。其中searchPaths的组合方式是{application}、{profile}、{label}的随意拼装,有很大的灵活性。比如
{basedir}/{application}/{profile}/{label:master}/
{basedir}/{application}-{profile}/{label:master}/
{basedir}/{label:master}/{application}/{profile}/
{basedir}/config_demo
其中{application}、{profile}、{label}属性都是非必须的。
备注:
如果用户有多层目录的要求,则只需要通过(_)来代替"/"即可。
比如searchPaths={application},如果有二级目录则使用application(_)profile
即可
2.获取属性集合,具体的如何去解析获取相应的配置信息且看NativeEnvironmentRepository#findOne()方法
// 此时的label为空字符串
@Override
public Environment findOne(String config, String profile, String label) {
// 专门解析${}符号
SpringApplicationBuilder builder = new SpringApplicationBuilder(
PropertyPlaceholderAutoConfiguration.class);
// 设置spring.profiles.active=profile
ConfigurableEnvironment environment = getEnvironment(profile);
builder.environment(environment);
builder.web(WebApplicationType.NONE).bannerMode(Mode.OFF);
/** 设置spring.config.name=config,application
** 设置spring.config.location={basedir}/{searchPaths:/}
**
*/
String[] args = getArgs(config, profile, label);
// Explicitly set the listeners (to exclude logging listener which would change
// log levels in the caller)
builder.application()
.setListeners(Arrays.asList(new ConfigFileApplicationListener()));
ConfigurableApplicationContext context = builder.run(args);
environment.getPropertySources().remove("profiles");
try {
// 过滤系统内部的通用变量并缩减source对应的key
return clean(new PassthruEnvironmentRepository(environment).findOne(config,
profile, label));
}
finally {
context.close();
}
}
其实很简单就是跟我们平常springboot启动时一样,读取相应的配置文件(此处只支持yml、properties、yaml方式),读取的格式例子如下
{basedir}/{searchPaths:/}application.properties
{basedir}/{searchPaths:/}application.yml
{basedir}/{searchPaths:/}{application}.properties
{basedir}/{searchPaths:/}{application}.yml
{basedir}/{searchPaths:/}{application}-{profile}.yml
{basedir}/{searchPaths:/}{application}-{profile}.properties
---
{basedir}/{application}/{profile}/{label:master}/application.[properties|yml]
{basedir}/{application}-{profile}/{label:master}/{application}.[properties|yml]
{basedir}/{label:master}/{application}/{profile}/{application}-{profile}.[properties|yml]
---
{basedir}/config_demo/{application}-{profile}.[properties|yml]
{basedir}/config_demo/application.[properties|yml]
其中{application}、{profile}、{label}属性都是非必须的。
小结
多仓库的外部源加载方式本文是以git为例的,当然springcloud config支持多种方式的加载,有兴趣的读者可自行分析。
本文主要讲解了ConfigServer如何去读取相应的远程Git文件的逻辑以及读取文件的格式,具体可查阅上文,灵活性还是很强的。既然知道外部资源如何被加载,那么如何被访问也必须得了解下,下文则针对此作详细的分析。
同时本文主要分析源码,具体的应用其实还是需要查阅官方文档,里面对应用讲的很仔细也很容易入门,就放个小入口,方便以后自己查阅!
springcloud情操陶冶-springcloud config server(一)的更多相关文章
- springcloud情操陶冶-springcloud config server(三)
承接前文springcloud情操陶冶-springcloud config server(二),本文就不讲述server了,就简单阐述下client的应用 前话 config server在引入的时 ...
- springcloud情操陶冶-springcloud config server(二)
承接前文springcloud情操陶冶-springcloud config server(一),本文将在前文的基础上讲解config server的涉外接口 前话 通过前文笔者得知,cloud co ...
- springcloud情操陶冶-初识springcloud
许久之前便听到了springcloud如雷贯耳的大名,但是不曾谋面,其主要应用于微服务的相关架构.笔者对微服务并不是很了解,但其既然比较出众,遂也稍微接触研究下 springcloud特性 sprin ...
- springcloud情操陶冶-bootstrapContext(二)
承接前文监听器对bootstrapContext创建的引导,笔者了解到其主要入口类为BootstrapImportSelectorConfiguration.本文将基于此类进行简单的分析 Bootst ...
- springcloud情操陶冶-bootstrapContext(一)
基于前文对springcloud的引导,本文则从源码角度查阅下cloud的context板块的运行逻辑 前言 springcloud是基于springboot开发的,所以读者在阅读此文前最好已经了解了 ...
- springcloud情操陶冶-bootstrapContext(三)
本文则将重点阐述context板块的自动配置类,观察其相关的特性并作相应的总结 自动配置类 直接查看cloudcontext板块下的spring.factories对应的EnableAutoConfi ...
- SpringCloud Config Bus webhook 只能刷新config server 不能刷新config client
在 https://github.com/spring-cloud/spring-cloud-bus/issues/124 中有提到 版本 SpringCloud:Greenwich.RC1 原因 由 ...
- 微服务SpringCloud—Config Server对称加密
配置内容的加解密在Git仓库中明文存储配置属性的.很多场景下,对于某些敏感的配置内容(例如数据库账号.密码等),应当加密存储. Config对称加解密1.安装JCE默认情况下我们的JRE自带了JCE, ...
- SpringCloud Config Server中{application}等占位符使用场景设置默认拉去分支
Spring Cloud Config服务器支持一个Git仓库URL,其中包含{application}和{profile}(以及{label})的占位符. 1.各个占位符所代表的含义 applica ...
随机推荐
- 最短路 BZOJ3694 树链剖分+线段树
分析: 树剖裸题,[Usaco2009 Jan]安全路经Travel 的简化版 剖开最短路树,遍历每一条没在最短路树上的边. 这种情况下,有且仅有u到v路径上,出来lca之外的点能够通过这条边到达,并 ...
- BZOJ_3365_[Usaco2004 Feb]Distance Statistics 路程统计&&POJ_1741_Tree_点分治
BZOJ_3365_[Usaco2004 Feb]Distance Statistics 路程统计&&POJ_1741_Tree_点分治 Description 在得知了自己农 ...
- Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构(源码可下载)
Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构(源码可下载) 说明:Java开源生鲜电商平台-性能优化以及服务器优化的设计与架构,我采用以下三种维度来讲解 1. 代码层面. 2. 数 ...
- 解决 'boost/iterator/iterator_adaptor.hpp' file not found’ 及控制台":CFBundleIdentifier", Does Not Exist
"react-native": "0.46.1" 这个问题产生原因: * /Users/Vanessa/.rncache 中 boost_1_63_0.tar. ...
- Postman-----将 A 请求中 response Body 中的参数值传入到下一个请求 B 的 request body 中作为参数发送请求
问题:将A接口中response body的"id"传入到B接口的request body中. 解决办法: 1.在A接口的test中设置环境变量. 代码:var data = JS ...
- C# 语言历史版本特性(C# 1.0到C# 8.0汇总)
历史版本 C#作为微软2000年以后.NET平台开发的当家语言,发展至今具有17年的历史,语言本身具有丰富的特性,微软对其更新支持也十分支持.微软将C#提交给标准组织ECMA,C# 5.0目前是ECM ...
- Spark学习之Spark Streaming
一.简介 许多应用需要即时处理收到的数据,例如用来实时追踪页面访问统计的应用.训练机器学习模型的应用,还有自动检测异常的应用.Spark Streaming 是 Spark 为这些应用而设计的模型.它 ...
- Netty实现高性能的HTTP服务器
浅谈HTTP Method 要通过netty实现HTTP服务器(或者客户端),首先你要了解HTTP协议. HTTP在客户端 - 服务器计算模型中用作请求 - 响应协议. 例如,web浏览器可以是客户端 ...
- Java语言编程 - Java第一个程序HelloWorld
3.1 新建Java文件 首先新建一个文件夹,用于存放写的Java程序,例如我存放Java程序的位置为” D:\Files\code\java”. 在该文件夹中,右键新建一个文本文档 将文件名重命名为 ...
- 5G+边缘计算,着眼可见的未来
在 2019 年 2 月巴塞罗那举办的 MWC(世界移动通讯大会)上,华为手机带来了一款超薄的 5G 折叠屏手机 Mate X.这款手机将折叠屏和 5G 结合在一起,引起了不少人的关注与舆论,而昂贵的 ...