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;
}





相关文章
|
JSON Java Nacos
SpringCloud 应用 Nacos 配置中心注解
在 Spring Cloud 应用中可以非常低成本地集成 Nacos 实现配置动态刷新,在应用程序代码中通过 Spring 官方的注解 @Value 和 @ConfigurationProperties,引用 Spring enviroment 上下文中的属性值,这种用法的最大优点是无代码层面侵入性,但也存在诸多限制,为了解决问题,提升应用接入 Nacos 配置中心的易用性,Spring Cloud Alibaba 发布一套全新的 Nacos 配置中心的注解。
1449 141
|
算法 安全 Java
微服务(四)-config配置中心的配置加解密
微服务(四)-config配置中心的配置加解密
|
12月前
|
Cloud Native Java Nacos
springcloud/springboot集成NACOS 做注册和配置中心以及nacos源码分析
通过本文,我们详细介绍了如何在 Spring Cloud 和 Spring Boot 中集成 Nacos 进行服务注册和配置管理,并对 Nacos 的源码进行了初步分析。Nacos 作为一个强大的服务注册和配置管理平台,为微服务架构提供
4571 14
|
JavaScript
Vue3基础(19)___vite.config.js中配置路径别名
本文介绍了如何在Vue 3的Vite配置文件`vite.config.js`中设置路径别名,以及如何在页面中使用这些别名导入模块。
742 0
Vue3基础(19)___vite.config.js中配置路径别名
|
负载均衡 Java Nacos
SpringCloud基础2——Nacos配置、Feign、Gateway
nacos配置管理、Feign远程调用、Gateway服务网关
SpringCloud基础2——Nacos配置、Feign、Gateway
|
Java 开发工具 对象存储
简化配置管理:Spring Cloud Config与Netflix OSS中的动态配置解决方案
简化配置管理:Spring Cloud Config与Netflix OSS中的动态配置解决方案
271 2
|
Java 微服务 Spring
Spring Cloud全解析:配置中心之解决configserver单点问题
但是如果该configserver挂掉了,那就无法获取最新的配置了,微服务就出现了configserver的单点问题,那么如何避免configserver单点呢?
240 1
|
JavaScript 前端开发 应用服务中间件
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
819 0
|
前端开发 JavaScript
vite vue3 config配置
【10月更文挑战第5天】
743 0
|
负载均衡 Java API
【Spring Cloud生态】Spring Cloud Gateway基本配置
【Spring Cloud生态】Spring Cloud Gateway基本配置
1355 0

热门文章

最新文章