SpringCloud配置中心-Config

简介: 从源码的角度讨论SpringCload Config的原理。

     本文主要讨论原理,不涉及使用示例。

 搭建Config Server

SpringCloud Config支持通过git、svn等搭建配置中心。因为目前使用git管理代码比较常见,所以接下来介绍通过git搭建配置中心。

1  配置示例

以下git相关的是一些常用的配置:

spring.cloud.config.server.git.uri= Git仓库地址

spring.cloud.config.server.git.searchPaths=仓库中配置文件所在路径

spring.cloud.config.server.git.username= Git账号

spring.cloud.config.server.git.password= Git密码

配置后,可以通过一下url模式访问指定的配置文件的内容,例如:

http://localhost:7001/{application}/{profile}[/{label}]

http://localhost:7001/{application}-{profile}.yml

http://localhost:7001/{label}/{application}-{profile}.yml

http://localhost:7001/{application}-{profile}.properties

http://localhost:7001/{label}/{application}-{profile}.properties

2  整体结构

8b323c0de18e4f6ae67b49c750ea9974a4fa4dd7

远程git仓库:用来存储配置文件的地方,多环境配置文件使用 {application}-{profile}.yml、{application}-{profile}.propreties

本地git仓库:缓存从远程git仓库中获取的配置信息,即便是远程git不能用,也可以从本地仓库中加载配置内容。

Config Server:分布式配置中心,指定了git仓库uri、搜索路径、访问账号和密码等。

微服务应用:配置客户端(Config Client),指定应用名、配置中心url、环境名、分支名等。

3  启动流程

微服务应用启动,根据微服务系统中配置的应用名(application)、环境名(profile)、分支名(label),向Config Server请求配置信息。

Config Server根据配置的Git(或SVN)仓库信息加上客户端传来的配置定位信息去查配置信息的路径。

Config Server执行git clone命令,将配置信息下载到本地Git仓库中,将配置信息加载到Spring的ApplicationContext读取内容返回给客户端(微服务应用)

客户端将内容加载到ApplicationContext,配置内容的优先级大于客户端内部的配置内容,进行忽略

注意:Config Server从Git上拉取配置项以后,会缓存在本地。

 

4  源码分析

1)   EnvironmentRepository

在前面「整体结构」部分中,我们看到ConfigServer从仓库中获取配置信息,然后给到其他微服务,这里ConfigServer与仓库的操作都是通过EnvironmentRepository来实现的。EnvironmentRepository有一下几种:

NativeEnvironmentRepository

spring.profiles.active=native时使用,从应用的配置文件中加载

EnvironmentEncryptorEnvironmentRepository

加密场景

PassthruEnvironmentRepository

Native时其实使用的是这个类来处理的

SvnKitEnvironmentRepository

通过svn来管理配置项时

JGitEnvironmentRepository

通过git来管理配置项时。

参考EnvironmentRepositoryConfiguration类中的代码,如下所示:

@Configuration
@Profile("native")
protected static class NativeRepositoryConfiguration {
   //
代码略去

   @Bean
   public EnvironmentRepository environmentRepository() {
      return new NativeEnvironmentRepository(this.environment);
   }
}

@Configuration
@ConditionalOnMissingBean(EnvironmentRepository.class)
protected static class GitRepositoryConfiguration {
   //
代码略去

   @Bean
   public EnvironmentRepository environmentRepository() {
      MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment);
      if (this.server.getDefaultLabel()!=null) {
        repository.setDefaultLabel(this.server.getDefaultLabel());
      }
      return repository;
   }
}

@Configuration
@Profile("subversion")
protected static class SvnRepositoryConfiguration {
   //
代码略去

   @Bean
   public EnvironmentRepository environmentRepository() {
      SvnKitEnvironmentRepository repository = new SvnKitEnvironmentRepository(this.environment);
      if (this.server.getDefaultLabel()!=null) {
        repository.setDefaultLabel(this.server.getDefaultLabel());
      }
      return repository;
   }
}

上面的所有类都实现了EnvironmentRepository接口,这个接口之定义了一个方法,用来从Repository中查找需要的数据项。

public interface EnvironmentRepository {

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

}

 

2)   以git为例,简单介绍仓库代码管理过程

服务器启动时,属性设置完以后就会根据cloneOnStart的值决定是否从远程git仓库clone代码,如下JGitEnvironmentRepository#afterPropertiesSet方法所示:

public void afterPropertiesSet() throws Exception {
   Assert.state(getUri() != null,
         "You need to configure a uri for the git repository");
   if (this.cloneOnStart) {
      initClonedRepository();
   }
}

 

/**
 * Clones the remote repository and then opens a connection to it.
 * @throws GitAPIException
 * @throws IOException
 */
private void initClonedRepository() throws GitAPIException, IOException {
   if (!getUri().startsWith(FILE_URI_PREFIX)) {
      deleteBaseDirIfExists();
      Git git = cloneToBasedir();
      if (git != null) {
         git.close();
      }
      git = openGitRepository();
      if (git != null) {
         git.close();
      }
   }

}

从源码中我们看到,首先会将配置从git上clone到本地,然后再进行其他的操作。接着就本地的git仓库中获取指定的数据了,见AbstractScmEnvironmentRepository#findOne代码,如下所示:

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

注意代码中使用的是NativeEnvironmentRepository,这个是以本地的文件作为EnvironmentRepository的。

 

 搭建Client

1  配置说明

在大家server部分我们提到了application、profile、label,他们分别是通过一下配置项配置的。

spring.application.name:对应配置文件规则中的{application}部分

spring.cloud.config.profile:对应配置文件规则中的{profile}部分

spring.cloud.config.label:对应配置文件规则中的{label}部分

spring.cloud.config.uri:配置中心config-server的地址

示例如下:

spring.application.name=demo

spring.cloud.config.profile=dev

spring.cloud.config.label=master

那么可以通过以下url访问:http://localhost:7001/demo/dev

 

2  源码分析

ConfigClientProperties#override方法中,我们可以看到通过客户端配置的spring.application.name、spring.cloud.config.profile、spring.cloud.config.label、spring.cloud.config.uri来生成ConfigClientProperties对象,而ConfigClientProperties中包含了要获取那个应用、分支、环境的配置信息。如下所示:

public static final String ConfigClientProperties

.PREFIX = "spring.cloud.config"

 

public ConfigClientProperties override(
     org.springframework.core.env.Environment environment) {
   ConfigClientProperties override = new ConfigClientProperties();
   BeanUtils.copyProperties(this, override);
  override.setName(environment.resolvePlaceholders("${" + ConfigClientProperties.PREFIX + ".name:${spring.application.name:application}}"));
   if (environment.containsProperty(ConfigClientProperties.PREFIX + ".profile")) {
      override.setProfile(environment.getProperty(ConfigClientProperties.PREFIX + ".profile"));
   }
   if (environment.containsProperty(ConfigClientProperties.PREFIX + ".label")) {
      override.setLabel(
           environment.getProperty(ConfigClientProperties.PREFIX + ".label"));
   }
   return override;
}





相关文章
|
3月前
|
算法 安全 Java
微服务(四)-config配置中心的配置加解密
微服务(四)-config配置中心的配置加解密
|
1天前
|
JSON Java Nacos
SpringCloud 应用 Nacos 配置中心注解
在 Spring Cloud 应用中可以非常低成本地集成 Nacos 实现配置动态刷新,在应用程序代码中通过 Spring 官方的注解 @Value 和 @ConfigurationProperties,引用 Spring enviroment 上下文中的属性值,这种用法的最大优点是无代码层面侵入性,但也存在诸多限制,为了解决问题,提升应用接入 Nacos 配置中心的易用性,Spring Cloud Alibaba 发布一套全新的 Nacos 配置中心的注解。
|
3月前
|
负载均衡 Java Nacos
SpringCloud基础2——Nacos配置、Feign、Gateway
nacos配置管理、Feign远程调用、Gateway服务网关
SpringCloud基础2——Nacos配置、Feign、Gateway
|
2月前
|
JavaScript 前端开发 应用服务中间件
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
170 0
|
3月前
|
Java 开发工具 对象存储
简化配置管理:Spring Cloud Config与Netflix OSS中的动态配置解决方案
简化配置管理:Spring Cloud Config与Netflix OSS中的动态配置解决方案
52 2
|
3月前
|
JavaScript
Vue3基础(19)___vite.config.js中配置路径别名
本文介绍了如何在Vue 3的Vite配置文件`vite.config.js`中设置路径别名,以及如何在页面中使用这些别名导入模块。
122 0
Vue3基础(19)___vite.config.js中配置路径别名
|
4月前
|
移动开发 JavaScript 前端开发
UniApp H5 跨域代理配置并使用(配置manifest.json、vue.config.js)
这篇文章介绍了在UniApp H5项目中处理跨域问题的两种方法:通过修改manifest.json文件配置h5设置,或在项目根目录创建vue.config.js文件进行代理配置,并提供了具体的配置代码示例。
UniApp H5 跨域代理配置并使用(配置manifest.json、vue.config.js)
|
2月前
|
前端开发 JavaScript
vite vue3 config配置
【10月更文挑战第5天】
64 0
|
2月前
|
负载均衡 Java API
【Spring Cloud生态】Spring Cloud Gateway基本配置
【Spring Cloud生态】Spring Cloud Gateway基本配置
44 0
|
4月前
|
Java 微服务 Spring
Spring Cloud全解析:配置中心之解决configserver单点问题
但是如果该configserver挂掉了,那就无法获取最新的配置了,微服务就出现了configserver的单点问题,那么如何避免configserver单点呢?