sc-config:如何通过组合方式获取环境配置

这是我参与更文挑战的第 9 天,活动详情查看: 更文挑战

《配置中心 Spring Cloud Config 详解》系列文章更新,一起在技术的路上精进!本系列文章将会介绍Spring Cloud 中提供了分布式配置中心Spring Cloud Config。应用服务中除了实现系统功能的代码,还需要连接资源和其它应用,经常有很多需要在外部配置的数据去调整应用的行为,如切换不同的数据库,设置功能开关等。随着微服务的不断增加,需要系统具备可伸缩和可扩展性,除此之外就是管理相当多的服务实例的配置数据。在应用的开发阶段由各个服务自治,但是到了生产环境之后会给运维带来很大的麻烦,特别是微服务的规模比较大,配置的更新更为麻烦。为此,系统需要建立一个统一的配置管理中心。

在前面的文章,我们进一步介绍了多个 repos 的匹配规则,这也是多 JGit 仓库实现的一个关键步骤。本文将会介绍如何通过组合方式获取配置

如何通过组合方式获取环境配置

CompositeConfiguration负责配置多个有优先级的EnvironmentRepository。在有些场景下,我们可能需要从多个环境仓库中拉取配置数据。通过在config server中的application.properties或application.yml激活多个 profile,比如同时从Git和SVN仓库拉取配置数据,可以配置如下的属性:

spring:
  profiles:
    active: git, svn
  cloud:
    config:
      server:
        svn:
          uri: file:///path/to/svn/repo
          order: 2
        git:
          uri: file:///path/to/git/repo
          order: 1
复制代码

除了可以指定一个仓库的URI,还可以指定优先级order属性。order属性允许你为所有的仓库设置优先级。order属性的数值越小,优先级越高。仓库之间如果包含相同的属性,优先级属性帮助解决了其潜在的任何冲突。

@Configuration
@ConditionalOnMissingBean(CompositeEnvironmentRepository.class)
public class CompositeConfiguration {
	@Bean
	@Primary
	@ConditionalOnBean(SearchPathLocator.class)
	public SearchPathCompositeEnvironmentRepository searchPathCompositeEnvironmentRepository() {
		return new SearchPathCompositeEnvironmentRepository(environmentRepos);
	}

	@Bean
	@Primary
	@ConditionalOnMissingBean(SearchPathLocator.class)
	public CompositeEnvironmentRepository compositeEnvironmentRepository() {
		return new CompositeEnvironmentRepository(environmentRepos);
	}
	//...

}
复制代码

如上为CompositeConfiguration的实现,将SearchPathCompositeEnvironmentRepositoryCompositeEnvironmentRepository加入到Spring的上下文中,分别对应于之前讲的SearchPathLocatorEnvironmentRepository。下面看一下CompositeEnvironmentRepository中的主要实现。

	@Override
	public Environment findOne(String application, String profile, String label) {
		Environment env = new Environment(application, new String[]{profile}, label, null, null);
		if(environmentRepositories.size() == 1) {
			Environment envRepo = environmentRepositories.get(0).findOne(application, profile, label);
			env.addAll(envRepo.getPropertySources());
			env.setVersion(envRepo.getVersion());
			env.setState(envRepo.getState());
		} else {
			for (EnvironmentRepository repo : environmentRepositories) {
				env.addAll(repo.findOne(application, profile, label).getPropertySources());
			}
		}
		return env;
	}
复制代码

CompositeEnvironmentRepository实现了EnvironmentRepository接口,如上为findOne方法的实现。复合环境仓库的模式也比较简单,EnvironmentRepository的实现是一个数组的形式,首先判断环境仓库的数量,多个则需要遍历,最后调用每种环境仓库的findOne实现。

SearchPathCompositeEnvironmentRepository继承自CompositeEnvironmentRepository,实现了SearchPathLocator接口,用以获取config文件的路径。

	@Override
	public Locations getLocations(String application, String profile, String label) {
		List<String> locations = new ArrayList<>();
		for(EnvironmentRepository repo : this.environmentRepositories) {
			if(repo instanceof SearchPathLocator) {
				locations.addAll(Arrays.asList(((SearchPathLocator) repo).getLocations(application, profile, label).getLocations()));
			}
		}
		return new Locations(application, profile, label, null, locations.toArray(new String[locations.size()]));
	}
复制代码

实现在之前的基础上,加上了对多个EnvironmentRepository的遍历处理,整合了多个环境仓库的路径。

当使用复合环境仓库时,不同的仓库都应该包含相同的分支(label)。如果你有一个环境,当你请求Git仓库中label为master的配置数据时,然而SVN仓库并没有包含这样的一个叫做master的分支,就会导致整个请求的失败。另外需要注意的是,当从一个环境仓库获取数值失败时,都会导致复合环境仓库的失败。

除了使用 Spring Cloud 提供的环境仓库,还可以自定义EnvironmentRepository 作为复合仓库的一部分。只需要实现EnvironmentRepository 接口,至于环境仓库的优先级,可以通过Ordered 并覆写 getOrdered 方法,如果没有实现该接口,自定义的环境仓库的优先级默认为最低的。

小结

本文主要介绍了 Spring Cloud Config 服务端 Config Server 中多个 repos 的情况下,通过组合方式获取环境配置的实现。下面的文章将会重点介绍客户端如何获取指定服务的资源文件。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享