跟我一起阅读SpringBoot源码(十一)——EnvironmentPostProcessor

前言

百度了下EnvironmentPostProcessor没看到什么注释叫什么,那我在本文就称之为环境处理器好了。
在SpringBoot启动准备好环境后,将发布一个ApplicationEnvironmentPreparedEvent事件,而ConfigFileApplicationListener侦听器就是这个事件的侦听者之一。当侦听者收到该事件时将执行对应的响应操作。

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

下面就将加载配置好的环境处理器来工作。接着我们就来看看这些环境处理器吧:
在这里插入图片描述
在这里插入图片描述
这里可以看到配置文件中已经配置了4个环境处理器,然后看代码里面再讲当前侦听者加到了处理器集合中。接着用AnnotationAwareOrderComparator排了个序。

简单看下AnnotationAwareOrderComparator:
在这里插入图片描述
排完序后的样子:
在这里插入图片描述
紧接着这5个处理器开始处理上下文。

SystemEnvironmentPropertySourceEnvironmentPostProcessor

/**
 * EnvironmentPostProcessor 提供一个可以跟踪每一个系统环境属性的SystemEnvironmentOrigin的OriginAwareSystemEnvironmentPropertySource来取代系统环境的SystemEnvironmentPropertySource。
 * An {@link EnvironmentPostProcessor} that replaces the systemEnvironment
 * {@link SystemEnvironmentPropertySource} with an
 * {@link OriginAwareSystemEnvironmentPropertySource} that can track the
 * {@link SystemEnvironmentOrigin} for every system environment property.
 *
 * @author Madhura Bhave
 * @since 2.0.0
 */
public class SystemEnvironmentPropertySourceEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {

翻译起来感觉好绕口,然后有抛出好多问号????。但是看了下这几个类的注释,感觉不好解释,目前也没多大的研究价值,所以暂时不贴了。有兴趣自己去看看注释。
继续看他的postProcessEnvironment方法:

	/** System environment property source name: {@value}. */
	public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
	
	@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		String sourceName = StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME;
		PropertySource<?> propertySource = environment.getPropertySources().get(sourceName);
		if (propertySource != null) {
			replacePropertySource(environment, sourceName, propertySource);
		}
	}

从环境中获取属性源集合,并获取系统环境属性(systemEnvironment),然后替换掉环境 中的systemEnvironment。
wath???脱了裤子然后又穿回去?难道更漂亮了???
看先看脱的时候怎么脱的:

	public MutablePropertySources getPropertySources() {
		return this.propertySources;
	}
	
	public PropertySource<?> get(String name) {
		int index = this.propertySourceList.indexOf(PropertySource.named(name));
		return (index != -1 ? this.propertySourceList.get(index) : null);
	}

脱的时候没啥花把式啊,就是从propertySourceList里面拿出来啊。
再看下穿回去干了啥:

	private void replacePropertySource(ConfigurableEnvironment environment, String sourceName,
			PropertySource<?> propertySource) {
		Map<String, Object> originalSource = (Map<String, Object>) propertySource.getSource();
		SystemEnvironmentPropertySource source = new OriginAwareSystemEnvironmentPropertySource(sourceName,
				originalSource);
		environment.getPropertySources().replace(sourceName, source);
	}
	public void replace(String name, PropertySource<?> propertySource) {
		int index = assertPresentAndGetIndex(name);
		this.propertySourceList.set(index, propertySource);
	}

好像就换了个SystemEnvironmentPropertySource,看看原来的SystemEnvironmentPropertySource 是什么:
也没干啥啊,出了换了个OriginAwareSystemEnvironmentPropertySource
哦~~,原来是换了条裤儿穿哦。
在这里插入图片描述
好了这个处理器看完了,就是换个带OriginLookup的裤子。

SpringApplicationJsonEnvironmentPostProcessor

/**
 * An {@link EnvironmentPostProcessor} that parses JSON from
 * {@code spring.application.json} or equivalently {@code SPRING_APPLICATION_JSON} and
 * adds it as a map property source to the {@link Environment}. The new properties are
 * added with higher priority than the system properties.
 *
 * @author Dave Syer
 * @author Phillip Webb
 * @author Madhura Bhave
 * @author Artsiom Yudovin
 * @since 1.3.0
 */
public class SpringApplicationJsonEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {

感觉不太好翻译,就不翻译了,反正就是用来配置解析JSON的东西。
看下postProcessEnvironment方法:

	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		MutablePropertySources propertySources = environment.getPropertySources();
		propertySources.stream().map(JsonPropertyValue::get).filter(Objects::nonNull).findFirst()
				.ifPresent((v) -> processJson(environment, v));
	}
	static JsonPropertyValue get(PropertySource<?> propertySource) {
		for (String candidate : CANDIDATES) {
			Object value = propertySource.getProperty(candidate);
			if (value instanceof String && StringUtils.hasLength((String) value)) {
				return new JsonPropertyValue(propertySource, candidate, (String) value);
			}
		}
		return null;
	}
	private static final String[] CANDIDATES = { SPRING_APPLICATION_JSON_PROPERTY,
				SPRING_APPLICATION_JSON_ENVIRONMENT_VARIABLE };
	/**
	 * Name of the {@code spring.application.json} property.
	 */
	public static final String SPRING_APPLICATION_JSON_PROPERTY = "spring.application.json";`/**
	 * Name of the {@code SPRING_APPLICATION_JSON} environment variable.
	 */
	public static final String SPRING_APPLICATION_JSON_ENVIRONMENT_VARIABLE = "SPRING_APPLICATION_JSON";

从环境中获取配置的源里面获取spring.application.json和SPRING_APPLICATION_JSON属性配置,然后取第一个执行下面这个方法:

private void processJson(ConfigurableEnvironment environment, JsonPropertyValue propertyValue) {
		JsonParser parser = JsonParserFactory.getJsonParser();
		Map<String, Object> map = parser.parseMap(propertyValue.getJson());
		if (!map.isEmpty()) {
			addJsonPropertySource(environment, new JsonPropertySource(propertyValue, flatten(map)));
		}
	}

这个有点没理解到,百度了下,看了些文章大概理解了下,也就是说我们可以在环境变量里面通过设置spring.application.json来配置属性值。
牛刀小试:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
还真可以,再回去看刚才的注释,貌似懂了点了,而且这个不一定配置再启动项上面,还可以配置再系统环境里面。一般人估计不会用到,用得到的不是一般人。我就是一般人,所以就先过了。

CloudFoundryVcapEnvironmentPostProcessor

/**
 * An {@link EnvironmentPostProcessor} that knows where to find VCAP (a.k.a. Cloud
 * Foundry) meta data in the existing environment. It parses out the VCAP_APPLICATION and
 * VCAP_SERVICES meta data and dumps it in a form that is easily consumed by
 * {@link Environment} users. If the app is running in Cloud Foundry then both meta data
 * items are JSON objects encoded in OS environment variables. VCAP_APPLICATION is a
 * shallow hash with basic information about the application (name, instance id, instance
 * index, etc.), and VCAP_SERVICES is a hash of lists where the keys are service labels
 * and the values are lists of hashes of service instance meta data. Examples are:
 *
 * <pre class="code">
 * VCAP_APPLICATION: {"instance_id":"2ce0ac627a6c8e47e936d829a3a47b5b","instance_index":0,
 *   "version":"0138c4a6-2a73-416b-aca0-572c09f7ca53","name":"foo",
 *   "uris":["foo.cfapps.io"], ...}
 * VCAP_SERVICES: {"rds-mysql-1.0":[{"name":"mysql","label":"rds-mysql-1.0","plan":"10mb",
 *   "credentials":{"name":"d04fb13d27d964c62b267bbba1cffb9da","hostname":"mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com",
 *   "host":"mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com","port":3306,"user":"urpRuqTf8Cpe6",
 *   "username":"urpRuqTf8Cpe6","password":"pxLsGVpsC9A5S"}
 * }]}
 * </pre>
 *
 * These objects are flattened into properties. The VCAP_APPLICATION object goes straight
 * to {@code vcap.application.*} in a fairly obvious way, and the VCAP_SERVICES object is
 * unwrapped so that it is a hash of objects with key equal to the service instance name
 * (e.g. "mysql" in the example above), and value equal to that instances properties, and
 * then flattened in the same way. E.g.
 *
 * <pre class="code">
 * vcap.application.instance_id: 2ce0ac627a6c8e47e936d829a3a47b5b
 * vcap.application.version: 0138c4a6-2a73-416b-aca0-572c09f7ca53
 * vcap.application.name: foo
 * vcap.application.uris[0]: foo.cfapps.io
 *
 * vcap.services.mysql.name: mysql
 * vcap.services.mysql.label: rds-mysql-1.0
 * vcap.services.mysql.credentials.name: d04fb13d27d964c62b267bbba1cffb9da
 * vcap.services.mysql.credentials.port: 3306
 * vcap.services.mysql.credentials.host: mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com
 * vcap.services.mysql.credentials.username: urpRuqTf8Cpe6
 * vcap.services.mysql.credentials.password: pxLsGVpsC9A5S
 * ...
 * </pre>
 *
 * N.B. this initializer is mainly intended for informational use (the application and
 * instance ids are particularly useful). For service binding you might find that Spring
 * Cloud is more convenient and more robust against potential changes in Cloud Foundry.
 *
 * @author Dave Syer
 * @author Andy Wilkinson
 * @author Madhura Bhave
 * @since 1.3.0
 */
public class CloudFoundryVcapEnvironmentPostProcessor
		implements EnvironmentPostProcessor, Ordered, ApplicationListener<ApplicationPreparedEvent> {
		

这么多注释看起来头都大了。还提及到了上面VCAP,闻所未闻。先看下postProcessEnvironment方法:

	@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		if (CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) {
			Properties properties = new Properties();
			JsonParser jsonParser = JsonParserFactory.getJsonParser();
			addWithPrefix(properties, getPropertiesFromApplication(environment, jsonParser), "vcap.application.");
			addWithPrefix(properties, getPropertiesFromServices(environment, jsonParser), "vcap.services.");
			MutablePropertySources propertySources = environment.getPropertySources();
			if (propertySources.contains(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {
				propertySources.addAfter(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
						new PropertiesPropertySource("vcap", properties));
			}
			else {
				propertySources.addFirst(new PropertiesPropertySource("vcap", properties));
			}
		}
	}

只有isActive为true才会执行,看下判断依据:

	/**
	 * Cloud Foundry platform.
	 */
	CLOUD_FOUNDRY {

		@Override
		public boolean isActive(Environment environment) {
			return environment.containsProperty("VCAP_APPLICATION") || environment.containsProperty("VCAP_SERVICES");
		}

	},

需要再环境变量里面配置VCAP_APPLICATIONVCAP_SERVICES,我很清楚,没遇见过,超纲内容,先跳过。

ConfigFileApplicationListener

这个就是我们的侦听者,不过他同时是一个处理器罢了,直接看postProcessEnvironment方法:

	@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		addPropertySources(environment, application.getResourceLoader());
	}
	/**
		添加配置文件属性源到指定的环境
	 * @param environment the environment to add source to
	 * @param resourceLoader the resource loader
	 * @see #addPostProcessors(ConfigurableApplicationContext)
	 */
	protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
		RandomValuePropertySource.addToEnvironment(environment);
		new Loader(environment, resourceLoader).load();
	}
/**
 * {@link PropertySource} that returns a random value for any property that starts with
 * {@literal "random."}. Where the "unqualified property name" is the portion of the
 * requested property name beyond the "random." prefix, this {@link PropertySource}
 * returns:
 * <ul>
 * <li>When {@literal "int"}, a random {@link Integer} value, restricted by an optionally
 * specified range.</li>
 * <li>When {@literal "long"}, a random {@link Long} value, restricted by an optionally
 * specified range.</li>
 * <li>Otherwise, a {@code byte[]}.</li>
 * </ul>
 * The {@literal "random.int"} and {@literal "random.long"} properties supports a range
 * suffix whose syntax is:
 * <p>
 * {@code OPEN value (,max) CLOSE} where the {@code OPEN,CLOSE} are any character and
 * {@code value,max} are integers. If {@code max} is provided then {@code value} is the
 * minimum value and {@code max} is the maximum (exclusive).
 *
 * @author Dave Syer
 * @author Matt Benson
 * @since 1.0.0
 */
public class RandomValuePropertySource extends PropertySource<Random> {
public static void addToEnvironment(ConfigurableEnvironment environment) {
		environment.getPropertySources().addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
				new RandomValuePropertySource(RANDOM_PROPERTY_SOURCE_NAME));
		logger.trace("RandomValuePropertySource add to Environment");
	}
/**
	 * Add the given property source object with precedence immediately lower
	 * than the named relative property source.
	 */
	public void addAfter(String relativePropertySourceName, PropertySource<?> propertySource) {
		assertLegalRelativeAddition(relativePropertySourceName, propertySource);
		removeIfPresent(propertySource);
		int index = assertPresentAndGetIndex(relativePropertySourceName);
		addAtIndex(index + 1, propertySource);
	}

貌似就是把原有的systemEnvironment搞一个随机后缀,然后放到其后,然后重新加载一下,不是很明白这个操作在干嘛。

	new Loader(environment, resourceLoader).load();

在生成随机前缀的环境变量后,执行了一个load操作,这行代码很不起眼,我都给漏掉了,还是我带着‘spring是何时指定application加载配置属性的’这个疑问来找才看到的。接下来看下load操作干什么:

	private static final String DEFAULT_PROPERTIES = "defaultProperties";
	private static final Set<String> LOAD_FILTERED_PROPERTY;

	static {
		Set<String> filteredProperties = new HashSet<>();
		filteredProperties.add("spring.profiles.active");
		filteredProperties.add("spring.profiles.include");
		LOAD_FILTERED_PROPERTY = Collections.unmodifiableSet(filteredProperties);
	}

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);
					});
		}
	static void apply(ConfigurableEnvironment environment, String propertySourceName, Set<String> filteredProperties,
			Consumer<PropertySource<?>> operation) {
		MutablePropertySources propertySources = environment.getPropertySources();
		PropertySource<?> original = propertySources.get(propertySourceName);
		if (original == null) {
			operation.accept(null);
			return;
		}
		propertySources.replace(propertySourceName, new FilteredPropertySource(original, filteredProperties));
		try {
			operation.accept(original);
		}
		finally {
			propertySources.replace(propertySourceName, original);
		}
	}

先前准备的环境中取出defaultProperties配置,如果没有获取到,则消费上面定义的方法。
这里记忆中并没有配置defaultProperties环境,debug也显示确实没有,所以先看看上面那个处理过程:

initializeProfiles

		/**
		 * Initialize profile information from both the {@link Environment} active
		 * profiles and any {@code spring.profiles.active}/{@code spring.profiles.include}
		 * properties that are already set.
		 */
		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);
			Set<Profile> activatedViaProperty = getProfilesFromProperty(ACTIVE_PROFILES_PROPERTY);
			Set<Profile> includedViaProperty = getProfilesFromProperty(INCLUDE_PROFILES_PROPERTY);
			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
				for (String defaultProfileName : this.environment.getDefaultProfiles()) {
					Profile defaultProfile = new Profile(defaultProfileName, true);
					this.profiles.add(defaultProfile);
				}
			}
		}
		private Set<Profile> getProfilesFromProperty(String profilesProperty) {
			if (!this.environment.containsProperty(profilesProperty)) {
				return Collections.emptySet();
			}
			Binder binder = Binder.get(this.environment);
			Set<Profile> profiles = getProfiles(binder, profilesProperty);
			return new LinkedHashSet<>(profiles);
		}
		private Set<Profile> getProfiles(Binder binder, String name) {
			return binder.bind(name, STRING_ARRAY).map(this::asProfileSet).orElse(Collections.emptySet());
		}
		
		private List<Profile> getOtherActiveProfiles(Set<Profile> activatedViaProperty,
				Set<Profile> includedViaProperty) {
			return Arrays.stream(this.environment.getActiveProfiles()).map(Profile::new).filter(
					(profile) -> !activatedViaProperty.contains(profile) && !includedViaProperty.contains(profile))
					.collect(Collectors.toList());
		}

先根据spring.profiles.active配置和spring.profiles.include获取配置的激活配置文件,然后再从环境中获取别的配置文件,最终将三者全部追加到profiles中。如果最终profiles中都只有null节点,那么就获取默认的配置文件。

我们一般把spring.profiles.active配置在application.yml或application.properties里面,这个时候都还没加载这两个配置文件,拿着地方指的是我们可通过配置spring.profiles.activespring.profiles.include来修改激活文件位置,而不用去application里面配置??

	/**
	 * Return the set of default profiles explicitly set via
	 * {@link #setDefaultProfiles(String...)} or if the current set of default profiles
	 * consists only of {@linkplain #getReservedDefaultProfiles() reserved default
	 * profiles}, then check for the presence of the
	 * {@value #DEFAULT_PROFILES_PROPERTY_NAME} property and assign its value (if any)
	 * to the set of default profiles.
	 * @see #AbstractEnvironment()
	 * @see #getDefaultProfiles()
	 * @see #DEFAULT_PROFILES_PROPERTY_NAME
	 * @see #getReservedDefaultProfiles()
	 */
	protected Set<String> doGetDefaultProfiles() {
		synchronized (this.defaultProfiles) {
			if (this.defaultProfiles.equals(getReservedDefaultProfiles())) {
				String profiles = getProperty(DEFAULT_PROFILES_PROPERTY_NAME);
				if (StringUtils.hasText(profiles)) {
					setDefaultProfiles(StringUtils.commaDelimitedListToStringArray(
							StringUtils.trimAllWhitespace(profiles)));
				}
			}
			return this.defaultProfiles;
		}
	}

这里是引用
这里地方实属看不懂为什么。

profiles加载完后,紧接着就是去找配置文件的位置,看下private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer)方法:

		private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
			getSearchLocations().forEach((location) -> {
				boolean isFolder = location.endsWith("/");
				Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
				names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
			});
		}
		/**
		 * The "config location" property name.
		 */
		public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
		//这里貌似可以通过配置spring.config.location来修改配置文件的搜索路径?
		private Set<String> getSearchLocations() {
			if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {
				return getSearchLocations(CONFIG_LOCATION_PROPERTY);
			}
			Set<String> locations = getSearchLocations(CONFIG_ADDITIONAL_LOCATION_PROPERTY);
			locations.addAll(
					asResolvedSet(ConfigFileApplicationListener.this.searchLocations, DEFAULT_SEARCH_LOCATIONS));
			return locations;
		}

		private Set<String> getSearchLocations(String propertyName) {
			Set<String> locations = new LinkedHashSet<>();
			if (this.environment.containsProperty(propertyName)) {
				for (String path : asResolvedSet(this.environment.getProperty(propertyName), null)) {
					if (!path.contains("$")) {
						path = StringUtils.cleanPath(path);
						if (!ResourceUtils.isUrl(path)) {
							path = ResourceUtils.FILE_URL_PREFIX + path;
						}
					}
					locations.add(path);
				}
			}
			return locations;
		}

这个地方得到4个路径如下,接着在这4个路径下去找配置的spring.config.name对应的配置文件,如果没有则返回默认的配置文件名称application
在这里插入图片描述

			private static final String DEFAULT_NAMES = "application";
			/**
			 * The "config name" property name.
			 */
			public static final String CONFIG_NAME_PROPERTY = "spring.config.name";
		private Set<String> getSearchNames() {
			if (this.environment.containsProperty(CONFIG_NAME_PROPERTY)) {
				String property = this.environment.getProperty(CONFIG_NAME_PROPERTY);
				return asResolvedSet(property, null);
			}
			return asResolvedSet(ConfigFileApplicationListener.this.names, DEFAULT_NAMES);
		}

spring.config.location这个属性说好像是对运维的支撑,有兴趣可以自行百度

紧接着执行private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) 方法加载:

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,刚好可以加载application.properties和application.yml两个配置文件。实际上properties可以加载properties和xml两种,application可以加载yml和yaml两种配置文件。
在这里插入图片描述

addLoadedPropertySources

经过上面一系列操作,反正是把配置文件加载完了,现在看看addLoadedPropertySources这个方法高了上面,没注释,从名字大概猜是把刚才加载的属性源文件加到哪里去。

private void addLoadedPropertySources() {
	//	目标是ConfigurableEnvironment的属性源
	MutablePropertySources destination = this.environment.getPropertySources();
	//拷贝对象是刚才加载的一些MutablePropertySources
	List<MutablePropertySources> loaded = new ArrayList<>(this.loaded.values());
	//把属性源排个序
	Collections.reverse(loaded);
	String lastAdded = null;
	Set<String> added = new HashSet<>();
	for (MutablePropertySources sources : loaded) {
		for (PropertySource<?> source : sources) {
			if (added.add(source.getName())) {
				//从配置文件中读取属性以此往ConfigurableEnvironment里面扔
				addLoadedPropertySource(destination, lastAdded, source);
				lastAdded = source.getName();
			}
		}
	}
}


private void addLoadedPropertySource(MutablePropertySources destination, String lastAdded,
		PropertySource<?> source) {
	if (lastAdded == null) {
		if (destination.contains(DEFAULT_PROPERTIES)) {
			//设置当前属性优先级高于defaultProperties
			destination.addBefore(DEFAULT_PROPERTIES, source);
		}
		else {
			//设置当前属性级别最低
			destination.addLast(source);
		}
	}
	else {
		//级别低于上一个属性
		destination.addAfter(lastAdded, source);
	}
}

这里的感觉就是能看懂每行代码,但是看起还是有点晕乎乎的了,先这样吧,根据debug来看,这个地方已经把我们配置的两个配置文件加进去了。
在这里插入图片描述

applyActiveProfiles

看名字的意思是应用激活的配置文件:

private void applyActiveProfiles(PropertySource<?> defaultProperties) {
	List<String> activeProfiles = new ArrayList<>();
	if (defaultProperties != null) {
		Binder binder = new Binder(ConfigurationPropertySources.from(defaultProperties),
				new PropertySourcesPlaceholdersResolver(this.environment));
		activeProfiles.addAll(getDefaultProfiles(binder, "spring.profiles.include"));
		if (!this.activatedProfiles) {
			activeProfiles.addAll(getDefaultProfiles(binder, "spring.profiles.active"));
		}
	}
	this.processedProfiles.stream().filter(this::isDefaultProfile).map(Profile::getName)
			.forEach(activeProfiles::add);
	this.environment.setActiveProfiles(activeProfiles.toArray(new String[0]));
}

至此,ConfigFileApplicationListener的操作完成了。

DebugAgentEnvironmentPostProcessor

/**
 * {@link EnvironmentPostProcessor} to enable the Reactor Debug Agent if available.
 * <p>
 * The debug agent is enabled by default, unless the
 * {@code "spring.reactor.debug-agent.enabled"} configuration property is set to false. We
 * are using here an {@link EnvironmentPostProcessor} instead of an auto-configuration
 * class to enable the agent as soon as possible during the startup process.
 *
 * @author Brian Clozel
 * @since 2.2.0
 */
public class DebugAgentEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {

在这里插入图片描述
调试代理???先看看postProcessEnvironment方法:

	@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		if (ClassUtils.isPresent(REACTOR_DEBUGAGENT_CLASS, null)) {
			Boolean agentEnabled = environment.getProperty(DEBUGAGENT_ENABLED_CONFIG_KEY, Boolean.class);
			if (agentEnabled != Boolean.FALSE) {
				try {
					Class<?> debugAgent = Class.forName(REACTOR_DEBUGAGENT_CLASS);
					debugAgent.getMethod("init").invoke(null);
				}
				catch (Exception ex) {
					throw new RuntimeException("Failed to init Reactor's debug agent");
				}
			}
		}
	}

在这里插入图片描述
这里貌似涉及到其他领域了,Reactor?这个先留个钩子,后面再来补。
至此,所有的环境处理器执行完成。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值