Spring Cloud Config配置中心

本文详细介绍了Spring Cloud Config的Environment环境加载过程,包括环境初始化、Config Server如何从Git获取配置,以及Config Client如何获取配置。Config Server通过EnvironmentController从远程Git仓库同步配置到本地,而Config Client利用PropertySourceBootstrapConfiguration初始化时从Config Server获取远程配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Environment环境加载

Environment就是指Spring应用运行的环境信息,例如从系统变量、命令行、配置文件application.yml等文件中的信息加载之后都会保存到Environment中。

Environment的初始化

org.springframework.boot.SpringApplication#run(java.lang.String...)

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

准备环境的过程中,主要就是创建和配置Spring容器的环境信息:

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
        //按照应用的类型创建标准的环境
		ConfigurableEnvironment environment = getOrCreateEnvironment();
        //配置环境的PropertySource,设置profiles
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		ConfigurationPropertySources.attach(environment);
        //事件驱动加载环境配置
		listeners.environmentPrepared(environment);
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
}

1. 创建一个标准的环境

private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		switch (this.webApplicationType) {
		case SERVLET:
            //若是Servlet应用则创建Servlet环境
			return new StandardServletEnvironment();
		case REACTIVE:
            //若是reactive应用则创建Servlet环境
			return new StandardReactiveWebEnvironment();
		default:
            //否则创建标准环境
			return new StandardEnvironment();
		}
}

获取webApplicationType: org.springframework.boot.WebApplicationType#deduceFromClasspath

static WebApplicationType deduceFromClasspath() {
        //org.springframework.web.reactive.DispatcherHandler类存在,
        //且org.springframework.web.servlet.DispatcherServlet类不存在
        //且org.glassfish.jersey.servlet.ServletContainer类不存在,则为REACTIVE应用
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
        //javax.servlet.Servlet类    
        //或org.springframework.web.context.ConfigurableWebApplicationContext类不存在则为普通的应用
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
        //否则为Servlet应用
		return WebApplicationType.SERVLET;
	}

这里以Servlet应用为例,看下环境的类结构图:

StandardServletEnvironment初始化

由于AbstractEnvironment类初始化调用了customizePropertySource方法,而customizePropertySource在StandardServletEnvironment和StandardEnvironment都有重写,所以会优先执行他们的方法:

org.springframework.web.context.support.StandardServletEnvironment#customizePropertySources

protected void customizePropertySources(MutablePropertySources propertySources) {
        //将Servlet的配置封装成一个标准的属性源添加到动态可变的属性源列表中
		propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
        //将Servlet的上下文封装成一个标准的属性源添加到动态可变的属性源列表中
		propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
        //添加JNDI的属性源
		if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
			propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
		}
		super.customizePropertySources(propertySources);
}

org.springframework.core.env.StandardEnvironment#customizePropertySources

protected void customizePropertySources(MutablePropertySources propertySources) {
        将系统属性源System.getProperties()添加到动态可变的属性源列表中
		propertySources.addLast(
				new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
        //将系统环境属性System.getenv()添加到动态可变的属性源列表中
		propertySources.addLast(
				new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}

2.配置Environment和配置profiles

org.springframework.boot.SpringApplication#configureEnvironment

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
	//添加类型转化的服务	
    if (this.addConversionService) {
			ConversionService conversionService = ApplicationConversionService.getSharedInstance();
			environment.setConversionService((ConfigurableConversionService) conversionService);
		}
        //配置Environment中的propertysources
		configurePropertySources(environment, args);
        //配置profiles
		configureProfiles(environment, args);
	}

org.springframework.boot.SpringApplication#configurePropertySources

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
        //若默认配置不为空,则将默认配置添加到MutablePropertySources,这个defaultProperties可以在SpringApplication中设置
		if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
			sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
		}
        //若设置了命令行属性,则设置成SimpleCommandLinePropertySource添加到MutablePropertySources的最前面
		if (this.addCommandLineProperties && args.length > 0) {
			String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
			if (sources.contains(name)) {
				PropertySource<?> source = sources.get(name);
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(
						new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}

org.springframework.boot.SpringApplication#configureProfiles

protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
        //若设置了activeProfiles则加入到环境中
		Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
		profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
		environment.setActiveProfiles(StringUtils.toStringArray(profiles));
	}

3.发送环境准备的事件

listeners.environmentPrepared(environment)

void environmentPrepared(ConfigurableEnvironment environment) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.environmentPrepared(environment);
		}
	}

当所有实现了SpringApplicationRunListener的监听器,都会执行environmentPrepared的方法,在spring.factories配置了EventPublishingRunListener类:

org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

org.springframework.boot.context.event.EventPublishingRunListener#environmentPrepared

发送了一个ApplicationEnvironmentPreparedEvent事件

public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster
				.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
	}

而ConfigFileApplicationListener这个监听器正是来监听并处理ApplicationEnvironmentPreparedEvent事件的。

org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEvent

public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
		}
		if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent(event);
		}
	}

接着处理环境准备就绪的事件,配置加载过程

org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEnvironmentPreparedEvent

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
		List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
		postProcessors.add(this);
		AnnotationAwareOrderComparator.sort(postProcessors);
		for (EnvironmentPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
		}
	}

ConfigFileApplicationListener同样实现了EnvironmentPostProcessor接口,所以最后达到postProcessEnvironment的方法

public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		addPropertySources(environment, application.getResourceLoader());
}

protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
        //添加一个RandomValuePropertySource到Environment的MutablePropertySources中
		RandomValuePropertySource.addToEnvironment(environment);
        //加载spring boot中的配置信息,比如application.yml或者application.properties
		new Loader(environment, resourceLoader).load();
}

new Loader(environment, resourceLoader).load()

这里是调用了FilteredPropertySource的apply方法,判断是否有设置defaultProperties,如果有则将默认配置设置一个FilteredPropertySource,然后再调用最后一个参数定义的匿名类(lambda表达式)

void load() {
		FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
					(defaultProperties) -> {
						this.profiles = new LinkedList<>();
						this.processedProfiles = new LinkedList<>();
						this.activatedProfiles = false;
						this.loaded = new LinkedHashMap<>();
						initializeProfiles();
						while (!this.profiles.isEmpty()) {
							Profile profile = this.profiles.poll();
							if (isDefaultProfile(profile)) {
								addProfileToEnvironment(profile.getName());
							}
							load(profile, this::getPositiveProfileFilter,
									addToLoaded(MutablePropertySources::addLast, false));
							this.processedProfiles.add(profile);
						}
						load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
						addLoadedPropertySources();
						applyActiveProfiles(defaultProperties);
					});
}

匿名类主要逻辑:

调用initializeProfiles初始化默认的Profile,没有设置的话就用默认,初始化之后保存到 private Deque<Profile> profiles; 中,它是一个LIFO队列。 因为 profiles 采用了 LIFO 队列,后进先出。所以会先加载profile为null的配置文件 ,也就是匹配 application.properties、application.yml 。
如果profiles不为空,则循环遍历每一个profiles,调用 load方法进行加载。

org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#initializeProfiles

该方法的作用是加载存在已经激活的 profiles,有自己设置的则加载自己设置的profiles,没有的话则使用默认的profiles

private void initializeProfiles() {
			// The default profile for these purposes is represented as null. We add it
			// first so that it is processed first and has lowest priority.
			this.profiles.add(null);
			Binder binder = Binder.get(this.environment);
            //获取spring.profiles.active的Profiles
			Set<Profile> activatedViaProperty = getProfiles(binder, ACTIVE_PROFILES_PROPERTY);
             //获取spring.profiles.incloud的Profiles
			Set<Profile> includedViaProperty = getProfiles(binder, INCLUDE_PROFILES_PROPERTY);
             //获取其他的Profiles
			List<Profile> otherActiveProfiles = getOtherActiveProfiles(activatedViaProperty, includedViaProperty);
			this.profiles.addAll(otherActiveProfiles);
			// Any pre-existing active profiles set via property sources (e.g.
			// System properties) take precedence over those added in config files.
			this.profiles.addAll(includedViaProperty);
			addActiveProfiles(activatedViaProperty);
			if (this.profiles.size() == 1) { // only has null profile
                //如果没有设置司机的profiles,则使用默认的profiles
				for (String defaultProfileName : this.environment.getDefaultProfiles()) {
					Profile defaultProfile = new Profile(defaultProfileName, true);
					this.profiles.add(defaultProfile);
				}
			}
		}

接下来就是具体加载每个Profile

org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load

搜索约定配置文件的位置,循环每个位置,获取每个位置下的文件名称再进行加载

private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
			getSearchLocations().forEach((location) -> {
				boolean isDirectory = location.endsWith("/");
				Set<String> names = isDirectory ? getSearchNames() : NO_SEARCH_NAMES;
                //按照每个名称进行加载
				names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
			});
		}

org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load(java.lang.String, java.lang.String, org.springframework.boot.context.config.ConfigFileApplicationListener.Profile, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentFilterFactory, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentConsumer)

按照文件名称的后缀,获取具体的资源加载器,进行具体文件的加载过程

private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,
				DocumentConsumer consumer) {
			if (!StringUtils.hasText(name)) {
				for (PropertySourceLoader loader : this.propertySourceLoaders) {
					if (canLoadFileExtension(loader, location)) {
						load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
						return;
					}
				}
				throw new IllegalStateException("File extension of config file location '" + location
						+ "' is not known to any PropertySourceLoader. If the location is meant to reference "
						+ "a directory, it must end in '/'");
			}
			Set<String> processed = new HashSet<>();
			for (PropertySourceLoader loader : this.propertySourceLoaders) {
				for (String fileExtension : loader.getFileExtensions()) {
					if (processed.add(fileExtension)) {
						loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory,
								consumer);
					}
				}
			}
		}

资源加载器目前自带的有两种,一种是properties文件加载器,一种是yaml/yml文件加载器:

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

至此,springBoot中的资源文件加载完毕,解析顺序从上到下。

 

Config Server获取配置

Spring Cloud Config Server提供了EnvironmentController,这样通过在浏览器访问即可从git中获取配置信息

EnvironmentController

@RequestMapping(path = "/{name}/{profiles:.*[^-].*}",
			produces = MediaType.APPLICATION_JSON_VALUE)
	public Environment defaultLabel(@PathVariable String name,
			@PathVariable String profiles) {
		return getEnvironment(name, profiles, null, false);
	}

	@RequestMapping(path = "/{name}/{profiles:.*[^-].*}",
			produces = EnvironmentMediaType.V2_JSON)
	public Environment defaultLabelIncludeOrigin(@PathVariable String name,
			@PathVariable String profiles) {
		return getEnvironment(name, profiles, null, true);
	}

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

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

我们可以按照application、profiles、label三要素的配置方式来获取远程地址的配置信息,调用的都是getEnvironment方法:

public Environment getEnvironment(String name, String profiles, String label,
			boolean includeOrigin) {
		name = normalize(name);
		label = normalize(label);
		Environment environment = this.repository.findOne(name, profiles, label,
				includeOrigin);
		if (!this.acceptEmpty
				&& (environment == null || environment.getPropertySources().isEmpty())) {
			throw new EnvironmentNotFoundException("Profile Not found");
		}
		return environment;
	}

org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepository#findOne

以git远程地址为例,调用findOne获取Environment,其实git地址可以配置多个地址,从每个地址中拿到符合application、profiles、label三要素的配置信息

public Environment findOne(String application, String profile, String label,
			boolean includeOrigin) {
		for (PatternMatchingJGitEnvironmentRepository repository : this.repos.values()) {
			if (repository.matches(application, profile, label)) {
				for (JGitEnvironmentRepository candidate : getRepositories(repository,
						application, profile, label)) {
					try {
						if (label == null) {
							label = candidate.getDefaultLabel();
						}
						Environment source = candidate.findOne(application, profile,
								label, includeOrigin);
						if (source != null) {
							return source;
						}
					}
					catch (Exception e) {
						if (this.logger.isDebugEnabled()) {
							this.logger.debug(
									"Cannot load configuration from " + candidate.getUri()
											+ ", cause: (" + e.getClass().getSimpleName()
											+ ") " + e.getMessage(),
									e);
						}
						continue;
					}
				}
			}
		}
		JGitEnvironmentRepository candidate = getRepository(this, application, profile,
				label);
		if (label == null) {
			label = candidate.getDefaultLabel();
		}
		if (candidate == this) {
			return super.findOne(application, profile, label, includeOrigin);
		}
		return candidate.findOne(application, profile, label, includeOrigin);
	}

org.springframework.cloud.config.server.environment.AbstractScmEnvironmentRepository#findOne(java.lang.String, java.lang.String, java.lang.String, boolean)

调用抽象类的findOne方法,主要有两个核心逻辑
    调用getLocations从GIT远程仓库同步到本地
    使用 NativeEnvironmentRepository 委托来读取本地文件内容

public synchronized Environment findOne(String application, String profile,
			String label, boolean includeOrigin) {
		NativeEnvironmentRepository delegate = new NativeEnvironmentRepository(
				getEnvironment(), new NativeEnvironmentProperties());
		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());
	}

至此,服务端获取远程git地址的配置信息完成。

 

ConfigClient获取配置

在spring boot项目启动时,有一个prepareContext的方法,它会回调所有实现了ApplicationContextInitializer 的实例,来做一些初始化工作。

org.springframework.boot.SpringApplication#prepareContext

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[0]));
		listeners.contextLoaded(context);
	}

org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration#initialize

获取所有PropertySourceLocator, 遍历每个PropertySourceLocator,调用locateCollection获取属性源列表加入到Spring的MutablePropertySources 中

public void initialize(ConfigurableApplicationContext applicationContext) {
		List<PropertySource<?>> composite = new ArrayList<>();
		AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
		boolean empty = true;
		ConfigurableEnvironment environment = applicationContext.getEnvironment();
        //遍历每个PropertySourceLocator 
		for (PropertySourceLocator locator : this.propertySourceLocators) {
			Collection<PropertySource<?>> source = locator.locateCollection(environment);
			if (source == null || source.size() == 0) {
				continue;
			}
			List<PropertySource<?>> sourceList = new ArrayList<>();
			for (PropertySource<?> p : source) {
                //加入到sourceList中
				if (p instanceof EnumerablePropertySource) {
					EnumerablePropertySource<?> enumerable = (EnumerablePropertySource<?>) p;
					sourceList.add(new BootstrapPropertySource<>(enumerable));
				}
				else {
					sourceList.add(new SimpleBootstrapPropertySource(p));
				}
			}
			logger.info("Located property source: " + sourceList);
			composite.addAll(sourceList);
			empty = false;
		}
        //若获取的属性源不为空的情况下,加入到MutablePropertySources中
		if (!empty) {
			MutablePropertySources propertySources = environment.getPropertySources();
			String logConfig = environment.resolvePlaceholders("${logging.config:}");
			LogFile logFile = LogFile.get(environment);
			for (PropertySource<?> p : environment.getPropertySources()) {
				if (p.getName().startsWith(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
					propertySources.remove(p.getName());
				}
			}
			insertPropertySources(propertySources, composite);
			reinitializeLoggingSystem(environment, logConfig, logFile);
			setLogLevels(applicationContext, environment);
			handleIncludedProfiles(environment);
		}
	}

org.springframework.cloud.bootstrap.config.PropertySourceLocator#locateCollection(org.springframework.core.env.Environment)

PropertySource<?> locate(Environment environment);

default Collection<PropertySource<?>> locateCollection(Environment environment) {
		return locateCollection(this, environment);
	}

	static Collection<PropertySource<?>> locateCollection(PropertySourceLocator locator,
			Environment environment) {
		PropertySource<?> propertySource = locator.locate(environment);
		if (propertySource == null) {
			return Collections.emptyList();
		}
		if (CompositePropertySource.class.isInstance(propertySource)) {
			Collection<PropertySource<?>> sources = ((CompositePropertySource) propertySource)
					.getPropertySources();
			List<PropertySource<?>> filteredSources = new ArrayList<>();
			for (PropertySource<?> p : sources) {
				if (p != null) {
					filteredSources.add(p);
				}
			}
			return filteredSources;
		}
		else {
			return Arrays.asList(propertySource);
		}
	}

locateCollection获取属性源时,调用了locate方法,而locate方法是抽象方法,由其子类实现,Config Client提供了一个ConfigServicePropertySourceLocator:

org.springframework.cloud.config.client.ConfigServicePropertySourceLocator#locate

通过RestTemplate调用一个Config Server服务获得远程配置信息,然后将信息包装成OriginTrackedMapPropertySource,保存到 CompositePropertySource 中

@Retryable(interceptor = "configServerRetryInterceptor")
	public org.springframework.core.env.PropertySource<?> locate(
			org.springframework.core.env.Environment environment) {
		ConfigClientProperties properties = this.defaultProperties.override(environment);
		CompositePropertySource composite = new OriginTrackedCompositePropertySource(
				"configService");
		RestTemplate restTemplate = this.restTemplate == null
				? getSecureRestTemplate(properties) : this.restTemplate;
		Exception error = null;
		String errorBody = null;
		try {
			String[] labels = new String[] { "" };
			if (StringUtils.hasText(properties.getLabel())) {
				labels = StringUtils
						.commaDelimitedListToStringArray(properties.getLabel());
			}
			String state = ConfigClientStateHolder.getState();
			// Try all the labels until one works
			for (String label : labels) {
				Environment result = getRemoteEnvironment(restTemplate, properties,
						label.trim(), state);
				if (result != null) {
					log(result);

					// result.getPropertySources() can be null if using xml
					if (result.getPropertySources() != null) {
						for (PropertySource source : result.getPropertySources()) {
							@SuppressWarnings("unchecked")
							Map<String, Object> map = translateOrigins(source.getName(),
									(Map<String, Object>) source.getSource());
							composite.addPropertySource(
									new OriginTrackedMapPropertySource(source.getName(),
											map));
						}
					}

					if (StringUtils.hasText(result.getState())
							|| StringUtils.hasText(result.getVersion())) {
						HashMap<String, Object> map = new HashMap<>();
						putValue(map, "config.client.state", result.getState());
						putValue(map, "config.client.version", result.getVersion());
						composite.addFirstPropertySource(
								new MapPropertySource("configClient", map));
					}
					return composite;
				}
			}
			errorBody = String.format("None of labels %s found", Arrays.toString(labels));
		}
		catch (HttpServerErrorException e) {
			error = e;
			if (MediaType.APPLICATION_JSON
					.includes(e.getResponseHeaders().getContentType())) {
				errorBody = e.getResponseBodyAsString();
			}
		}
		catch (Exception e) {
			error = e;
		}
		if (properties.isFailFast()) {
			throw new IllegalStateException(
					"Could not locate PropertySource and the fail fast property is set, failing"
							+ (errorBody == null ? "" : ": " + errorBody),
					error);
		}
		logger.warn("Could not locate PropertySource: "
				+ (error != null ? error.getMessage() : errorBody));
		return null;

	}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值