博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring boot 源码分析(四) 配置文件加载4 之 ConfigFileApplicationListener
阅读量:6437 次
发布时间:2019-06-23

本文共 28170 字,大约阅读时间需要 93 分钟。

hot3.png

一、前言

上章我们通过调试,找到了spring加载application.xml application.yml等配置文件的类,即本章要聊的

ConfigFileApplicationListener

二、看源码

首先我们看一下spring boot 的源码

package org.springframework.boot.context.config;import java.io.IOException;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.LinkedHashSet;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Set;import java.util.function.BiConsumer;import java.util.stream.Collectors;import org.apache.commons.logging.Log;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;import org.springframework.boot.SpringApplication;import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;import org.springframework.boot.context.event.ApplicationPreparedEvent;import org.springframework.boot.context.properties.bind.Bindable;import org.springframework.boot.context.properties.bind.Binder;import org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver;import org.springframework.boot.context.properties.source.ConfigurationPropertySources;import org.springframework.boot.env.EnvironmentPostProcessor;import org.springframework.boot.env.PropertySourceLoader;import org.springframework.boot.env.RandomValuePropertySource;import org.springframework.boot.logging.DeferredLog;import org.springframework.context.ApplicationEvent;import org.springframework.context.ConfigurableApplicationContext;import org.springframework.context.annotation.ConfigurationClassPostProcessor;import org.springframework.context.event.SmartApplicationListener;import org.springframework.core.Ordered;import org.springframework.core.annotation.AnnotationAwareOrderComparator;import org.springframework.core.env.ConfigurableEnvironment;import org.springframework.core.env.Environment;import org.springframework.core.env.MutablePropertySources;import org.springframework.core.env.PropertySource;import org.springframework.core.io.DefaultResourceLoader;import org.springframework.core.io.Resource;import org.springframework.core.io.ResourceLoader;import org.springframework.core.io.support.SpringFactoriesLoader;import org.springframework.util.Assert;import org.springframework.util.CollectionUtils;import org.springframework.util.ObjectUtils;import org.springframework.util.ResourceUtils;import org.springframework.util.StringUtils;/** * {@link EnvironmentPostProcessor} that configures the context environment by loading * properties from well known file locations. By default properties will be loaded from * 'application.properties' and/or 'application.yml' files in the following locations: * 
    *
  • classpath:
  • *
  • file:./
  • *
  • classpath:config/
  • *
  • file:./config/:
  • *
*

* Alternative search locations and names can be specified using * {@link #setSearchLocations(String)} and {@link #setSearchNames(String)}. *

* Additional files will also be loaded based on active profiles. For example if a 'web' * profile is active 'application-web.properties' and 'application-web.yml' will be * considered. *

* The 'spring.config.name' property can be used to specify an alternative name to load * and the 'spring.config.location' property can be used to specify alternative search * locations or specific files. *

* * @author Dave Syer * @author Phillip Webb * @author Stephane Nicoll * @author Andy Wilkinson * @author Eddú Meléndez * @author Madhura Bhave */public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered { private static final String DEFAULT_PROPERTIES = "defaultProperties"; // Note the order is from least to most specific (last one wins) private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/"; private static final String DEFAULT_NAMES = "application"; private static final Set

NO_SEARCH_NAMES = Collections.singleton(null); /** * The "active profiles" property name. */ public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active"; /** * The "includes profiles" property name. */ public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include"; /** * The "config name" property name. */ public static final String CONFIG_NAME_PROPERTY = "spring.config.name"; /** * The "config location" property name. */ public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location"; /** * The "config additional location" property name. */ public static final String CONFIG_ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location"; /** * The default order for the processor. */ public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10; /** * Name of the application configuration {@link PropertySource}. */ public static final String APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME = "applicationConfigurationProperties"; private final DeferredLog logger = new DeferredLog(); private String searchLocations; private String names; private int order = DEFAULT_ORDER; @Override public boolean supportsEventType(Class
eventType) { return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType) || ApplicationPreparedEvent.class.isAssignableFrom(eventType); } @Override public boolean supportsSourceType(Class
aClass) { return true; } @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationEnvironmentPreparedEvent) { onApplicationEnvironmentPreparedEvent( (ApplicationEnvironmentPreparedEvent) event); } if (event instanceof ApplicationPreparedEvent) { onApplicationPreparedEvent(event); } } private void onApplicationEnvironmentPreparedEvent( ApplicationEnvironmentPreparedEvent event) { List
postProcessors = loadPostProcessors(); postProcessors.add(this); AnnotationAwareOrderComparator.sort(postProcessors); for (EnvironmentPostProcessor postProcessor : postProcessors) { postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication()); } } List
loadPostProcessors() { return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, getClass().getClassLoader()); } @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { addPropertySources(environment, application.getResourceLoader()); } private void onApplicationPreparedEvent(ApplicationEvent event) { this.logger.replayTo(ConfigFileApplicationListener.class); addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext()); } /** * Add config file property sources to the specified environment. * @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(); } /** * Add appropriate post-processors to post-configure the property-sources. * @param context the context to configure */ protected void addPostProcessors(ConfigurableApplicationContext context) { context.addBeanFactoryPostProcessor( new PropertySourceOrderingPostProcessor(context)); } public void setOrder(int order) { this.order = order; } @Override public int getOrder() { return this.order; } /** * Set the search locations that will be considered as a comma-separated list. Each * search location should be a directory path (ending in "/") and it will be prefixed * by the file names constructed from {@link #setSearchNames(String) search names} and * profiles (if any) plus file extensions supported by the properties loaders. * Locations are considered in the order specified, with later items taking precedence * (like a map merge). * @param locations the search locations */ public void setSearchLocations(String locations) { Assert.hasLength(locations, "Locations must not be empty"); this.searchLocations = locations; } /** * Sets the names of the files that should be loaded (excluding file extension) as a * comma-separated list. * @param names the names to load */ public void setSearchNames(String names) { Assert.hasLength(names, "Names must not be empty"); this.names = names; } /** * {@link BeanFactoryPostProcessor} to re-order our property sources below any * {@code @PropertySource} items added by the {@link ConfigurationClassPostProcessor}. */ private class PropertySourceOrderingPostProcessor implements BeanFactoryPostProcessor, Ordered { private ConfigurableApplicationContext context; PropertySourceOrderingPostProcessor(ConfigurableApplicationContext context) { this.context = context; } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { reorderSources(this.context.getEnvironment()); } private void reorderSources(ConfigurableEnvironment environment) { PropertySource
defaultProperties = environment.getPropertySources() .remove(DEFAULT_PROPERTIES); if (defaultProperties != null) { environment.getPropertySources().addLast(defaultProperties); } } } /** * Loads candidate property sources and configures the active profiles. */ private class Loader { private final Log logger = ConfigFileApplicationListener.this.logger; private final ConfigurableEnvironment environment; private final ResourceLoader resourceLoader; private final List
propertySourceLoaders; private LinkedList
profiles; private List
processedProfiles; private boolean activatedProfiles; private Map
loaded; private Map
> loadDocumentsCache = new HashMap<>(); Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { this.environment = environment; this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); this.propertySourceLoaders = SpringFactoriesLoader.loadFactories( PropertySourceLoader.class, getClass().getClassLoader()); } public void load() { 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(); load(profile, this::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false)); this.processedProfiles.add(profile); } load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true)); addLoadedPropertySources(); } /** * 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
activatedViaProperty = getProfilesActivatedViaActiveProfileProperty(); processOtherActiveProfiles(activatedViaProperty); // Any pre-existing active activeProfiles set via property sources (e.g. // System // properties) take precedence over those added in config files. addActiveProfiles(activatedViaProperty); if (this.profiles.size() == 1) { // only has null profile for (String defaultProfileName : this.environment.getDefaultProfiles()) { ConfigFileApplicationListener.Profile defaultProfile = new ConfigFileApplicationListener.Profile( defaultProfileName, true); this.profiles.add(defaultProfile); } } } private Set
getProfilesActivatedViaActiveProfileProperty() { if (!this.environment.containsProperty(ACTIVE_PROFILES_PROPERTY) && !this.environment.containsProperty(INCLUDE_PROFILES_PROPERTY)) { return Collections.emptySet(); } Binder binder = Binder.get(this.environment); Set
activeProfiles = new LinkedHashSet<>(); activeProfiles.addAll(getProfiles(binder, ACTIVE_PROFILES_PROPERTY)); activeProfiles.addAll(getProfiles(binder, INCLUDE_PROFILES_PROPERTY)); return activeProfiles; } private void processOtherActiveProfiles(Set
activatedViaProperty) { List
otherActiveProfiles = Arrays .stream(this.environment.getActiveProfiles()).map(Profile::new) .filter((o) -> !activatedViaProperty.contains(o)) .collect(Collectors.toList()); this.profiles.addAll(otherActiveProfiles); } void addActiveProfiles(Set
profiles) { if (this.activatedProfiles || profiles.isEmpty()) { return; } addProfiles(profiles); this.logger.debug("Activated activeProfiles " + StringUtils.collectionToCommaDelimitedString(profiles)); this.activatedProfiles = true; removeUnprocessedDefaultProfiles(); } void addProfiles(Set
profiles) { for (Profile profile : profiles) { this.profiles.add(profile); addProfileToEnvironment(profile.getName()); } } private void removeUnprocessedDefaultProfiles() { this.profiles.removeIf( (profile) -> (profile != null && profile.isDefaultProfile())); } private DocumentFilter getPositiveProfileFilter(Profile profile) { return (Document document) -> { if (profile == null) { return ObjectUtils.isEmpty(document.getProfiles()); } return ObjectUtils.containsElement(document.getProfiles(), profile.getName()) && this.environment.acceptsProfiles(document.getProfiles()); }; } private DocumentFilter getNegativeProfileFilter(Profile profile) { return (Document document) -> (profile == null && !ObjectUtils.isEmpty(document.getProfiles()) && this.environment.acceptsProfiles(document.getProfiles())); } private DocumentConsumer addToLoaded( BiConsumer
> addMethod, boolean checkForExisting) { return (profile, document) -> { if (checkForExisting) { for (MutablePropertySources merged : this.loaded.values()) { if (merged.contains(document.getPropertySource().getName())) { return; } } } MutablePropertySources merged = this.loaded.computeIfAbsent(profile, (k) -> new MutablePropertySources()); addMethod.accept(merged, document.getPropertySource()); }; } private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) { getSearchLocations().forEach((location) -> { boolean isFolder = location.endsWith("/"); Set
names = (isFolder ? getSearchNames() : NO_SEARCH_NAMES); names.forEach( (name) -> load(location, name, profile, filterFactory, 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); } } } for (PropertySourceLoader loader : this.propertySourceLoaders) { for (String fileExtension : loader.getFileExtensions()) { String prefix = location + name; fileExtension = "." + fileExtension; loadForFileExtension(loader, prefix, fileExtension, profile, filterFactory, consumer); } } } private boolean canLoadFileExtension(PropertySourceLoader loader, String name) { return Arrays.stream(loader.getFileExtensions()) .anyMatch((fileExtension) -> StringUtils.endsWithIgnoreCase(name, fileExtension)); } private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension, Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) { DocumentFilter defaultFilter = filterFactory.getDocumentFilter(null); DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile); if (profile != null) { // Try profile-specific file & profile section in profile file (gh-340) String profileSpecificFile = prefix + "-" + profile + fileExtension; load(loader, profileSpecificFile, profile, defaultFilter, consumer); load(loader, profileSpecificFile, profile, profileFilter, consumer); // Try profile specific sections in files we've already processed for (Profile processedProfile : this.processedProfiles) { if (processedProfile != null) { String previouslyLoaded = prefix + "-" + processedProfile + fileExtension; load(loader, previouslyLoaded, profile, profileFilter, consumer); } } } // Also try the profile-specific section (if any) of the normal file load(loader, prefix + fileExtension, profile, profileFilter, consumer); } private void load(PropertySourceLoader loader, String location, Profile profile, DocumentFilter filter, DocumentConsumer consumer) { try { Resource resource = this.resourceLoader.getResource(location); String description = getDescription(location, resource); if (profile != null) { description = description + " for profile " + profile; } if (resource == null || !resource.exists()) { this.logger.trace("Skipped missing config " + description); return; } if (!StringUtils.hasText( StringUtils.getFilenameExtension(resource.getFilename()))) { this.logger.trace("Skipped empty config extension " + description); return; } String name = "applicationConfig: [" + location + "]"; List
documents = loadDocuments(loader, name, resource); if (CollectionUtils.isEmpty(documents)) { this.logger.trace("Skipped unloaded config " + description); return; } List
loaded = new ArrayList<>(); for (Document document : documents) { if (filter.match(document)) { addActiveProfiles(document.getActiveProfiles()); addProfiles(document.getIncludeProfiles()); loaded.add(document); } } Collections.reverse(loaded); if (!loaded.isEmpty()) { loaded.forEach((document) -> consumer.accept(profile, document)); this.logger.debug("Loaded config file " + description); } } catch (Exception ex) { throw new IllegalStateException("Failed to load property " + "source from location '" + location + "'", ex); } } private List
loadDocuments(PropertySourceLoader loader, String name, Resource resource) throws IOException { DocumentsCacheKey cacheKey = new DocumentsCacheKey(loader, resource); List
documents = this.loadDocumentsCache.get(cacheKey); if (documents == null) { List
> loaded = loader.load(name, resource); documents = asDocuments(loaded); this.loadDocumentsCache.put(cacheKey, documents); } return documents; } private List
asDocuments(List
> loaded) { if (loaded == null) { return Collections.emptyList(); } return loaded.stream().map((propertySource) -> { Binder binder = new Binder( ConfigurationPropertySources.from(propertySource), new PropertySourcesPlaceholdersResolver(this.environment)); return new Document(propertySource, binder.bind("spring.profiles", Bindable.of(String[].class)) .orElse(null), getProfiles(binder, ACTIVE_PROFILES_PROPERTY), getProfiles(binder, INCLUDE_PROFILES_PROPERTY)); }).collect(Collectors.toList()); } private String getDescription(String location, Resource resource) { try { if (resource != null) { String uri = resource.getURI().toASCIIString(); return String.format("'%s' (%s)", uri, location); } } catch (IOException ex) { } return String.format("'%s'", location); } private Set
getProfiles(Binder binder, String name) { return binder.bind(name, String[].class).map(this::asProfileSet) .orElse(Collections.emptySet()); } private Set
asProfileSet(String[] profileNames) { List
profiles = new ArrayList<>(); for (String profileName : profileNames) { profiles.add(new Profile(profileName)); } return new LinkedHashSet<>(profiles); } private void addProfileToEnvironment(String profile) { for (String activeProfile : this.environment.getActiveProfiles()) { if (activeProfile.equals(profile)) { return; } } this.environment.addActiveProfile(profile); } private Set
getSearchLocations() { if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) { return getSearchLocations(CONFIG_LOCATION_PROPERTY); } Set
locations = getSearchLocations( CONFIG_ADDITIONAL_LOCATION_PROPERTY); locations.addAll( asResolvedSet(ConfigFileApplicationListener.this.searchLocations, DEFAULT_SEARCH_LOCATIONS)); return locations; } private Set
getSearchLocations(String propertyName) { Set
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; } private Set
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); } private Set
asResolvedSet(String value, String fallback) { List
list = Arrays.asList(StringUtils.trimArrayElements( StringUtils.commaDelimitedListToStringArray(value != null ? this.environment.resolvePlaceholders(value) : fallback))); Collections.reverse(list); return new LinkedHashSet<>(list); } private void addLoadedPropertySources() { MutablePropertySources destination = this.environment.getPropertySources(); String lastAdded = null; List
loaded = new ArrayList<>(this.loaded.values()); Collections.reverse(loaded); for (MutablePropertySources sources : loaded) { for (PropertySource
source : sources) { if (lastAdded == null) { if (destination.contains(DEFAULT_PROPERTIES)) { destination.addBefore(DEFAULT_PROPERTIES, source); } else { destination.addLast(source); } } else { destination.addAfter(lastAdded, source); } lastAdded = source.getName(); } } } } /** * A Spring Profile that can be loaded. */ private static class Profile { private final String name; private final boolean defaultProfile; Profile(String name) { this(name, false); } Profile(String name, boolean defaultProfile) { Assert.notNull(name, "Name must not be null"); this.name = name; this.defaultProfile = defaultProfile; } public String getName() { return this.name; } public boolean isDefaultProfile() { return this.defaultProfile; } @Override public String toString() { return this.name; } @Override public int hashCode() { return this.name.hashCode(); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj == null || obj.getClass() != getClass()) { return false; } return ((Profile) obj).name.equals(this.name); } } /** * Cache key used to save loading the same document multiple times. */ private static class DocumentsCacheKey { private final PropertySourceLoader loader; private final Resource resource; DocumentsCacheKey(PropertySourceLoader loader, Resource resource) { this.loader = loader; this.resource = resource; } @Override public int hashCode() { return this.loader.hashCode() * 31 + this.resource.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } DocumentsCacheKey other = (DocumentsCacheKey) obj; return this.loader.equals(other.loader) && this.resource.equals(other.resource); } } /** * A single document loaded by a {@link PropertySourceLoader}. */ private static class Document { private final PropertySource
propertySource; private String[] profiles; private final Set
activeProfiles; private final Set
includeProfiles; Document(PropertySource
propertySource, String[] profiles, Set
activeProfiles, Set
includeProfiles) { this.propertySource = propertySource; this.profiles = profiles; this.activeProfiles = activeProfiles; this.includeProfiles = includeProfiles; } public PropertySource
getPropertySource() { return this.propertySource; } public String[] getProfiles() { return this.profiles; } public Set
getActiveProfiles() { return this.activeProfiles; } public Set
getIncludeProfiles() { return this.includeProfiles; } @Override public String toString() { return this.propertySource.toString(); } } /** * Factory used to create a {@link DocumentFilter}. */ @FunctionalInterface private interface DocumentFilterFactory { /** * Create a filter for the given profile. * @param profile the profile or {@code null} * @return the filter */ DocumentFilter getDocumentFilter(Profile profile); } /** * Filter used to restrict when a {@link Document} is loaded. */ @FunctionalInterface private interface DocumentFilter { boolean match(Document document); } /** * Consumer used to handle a loaded {@link Document}. */ @FunctionalInterface private interface DocumentConsumer { void accept(Profile profile, Document document); }}

三、读源码

    >类图

    我们通用idea自带的生成类图的工具 CTRL+ALT+SHIFT+U生成本类的类图

    221502_veHk_1178126.png

    ConfigFileApplicationListener 主要实现了以下接口

    EnvironmentPostProcessor:用于环境的后处理

    SmartApplicationListener:是ApplicationListener的扩展,进一步暴露事件类型。

    Ordered:用于将对象排序

>类的解释

    通过类上的注释,我们可以知道关于该类的一些信息,

    1.他默认会从classpath: 、file:./ 、classpath:config/ 、 file:./config/  加载'application.properties' 和/或 'application.yml'

    2.其他配置也会根据active profiles 进行 加载 , 如 active 此时被设置成 web, spring 加载的时候也会去加载 application-web.properties 和 application-web.yml

    3.spring.config.name 属性 可指定要加载的替代名称,spring.config.location 属性可指定替代的查找位置或文件

    >属性解析

     1.通过看源码可以得知,他有这些属性,这些属性大部分是一些常量,定义了属性名,配置文件查找的位置,顺序,日志等。

private static final String DEFAULT_PROPERTIES = "defaultProperties";	// Note the order is from least to most specific (last one wins)	private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";	private static final String DEFAULT_NAMES = "application";	private static final Set
NO_SEARCH_NAMES = Collections.singleton(null); /** * The "active profiles" property name. */ public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active"; /** * The "includes profiles" property name. */ public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include"; /** * The "config name" property name. */ public static final String CONFIG_NAME_PROPERTY = "spring.config.name"; /** * The "config location" property name. */ public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location"; /** * The "config additional location" property name. */ public static final String CONFIG_ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location"; /** * The default order for the processor. */ public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10; /** * Name of the application configuration {@link PropertySource}. */ public static final String APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME = "applicationConfigurationProperties"; private final DeferredLog logger = new DeferredLog(); private String searchLocations; private String names; private int order = DEFAULT_ORDER;

      >方法解析  

       首先我们看一下他的实现接口中的方法

EnvironmentPostProcessor

public interface EnvironmentPostProcessor {	//用于给定环境的后处理	void postProcessEnvironment(ConfigurableEnvironment environment,			SpringApplication application);}

 SmartApplicationListener

public interface SmartApplicationListener extends ApplicationListener
, Ordered { //确定这个监听器是否支持给定的事件类型 boolean supportsEventType(Class
eventType); //确定这个监听器是否支持给定的类型 boolean supportsSourceType(@Nullable Class
sourceType);}

Ordered     

public interface Ordered {	//作用于最高优先级	int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;	//作用于最低优先级	int LOWEST_PRECEDENCE = Integer.MAX_VALUE;    //获取排序的值    //高值会被执行为低优先级 , 因此 , 最高优先级的对象会拥有最低的值(有点像servlet的load-on-startup)    //相同的值会导致受影响对象任意位置排序	int getOrder();}

 

对比ConfigFileApplicationListener的继承接口 EnvironmentPostProcessor, SmartApplicationListener, Ordered,我们看以下ConfigFileApplicationListener对于这些接口的实现。

ConfigFileApplicationListener.java

@Overridepublic void postProcessEnvironment(ConfigurableEnvironment environment,			SpringApplication application) {	addPropertySources(environment, application.getResourceLoader());}//将配置文件属性添加到特定的environment环境	protected void addPropertySources(ConfigurableEnvironment environment,			ResourceLoader resourceLoader) {        //添加random的相关功能加入到environment环境		RandomValuePropertySource.addToEnvironment(environment);		new Loader(environment, resourceLoader).load();	}

 

未完待续

   
   
   

   

    

转载于:https://my.oschina.net/u/1178126/blog/1822846

你可能感兴趣的文章
全局方法
查看>>
DOM 获取、DOM动态创建节点
查看>>
do{...}while(0)的意义和用法
查看>>
【CJOJ】Contest4 - A+B Series
查看>>
Python中四种交换两个变量的值的方法
查看>>
ora-01033:oracle initialization or shutdown in progress 解决方法
查看>>
移动自动化相关名词解释
查看>>
微信开发者工具 快捷键
查看>>
monkey测试===修改adb的默认端口
查看>>
AsyncTask和Handler处理异步消息
查看>>
Scheme 中的 pair 和 list 简述
查看>>
iOS AVAssetExportSession 视频剪切、合并、压缩
查看>>
我收藏的技术知识图(每张都是大图)
查看>>
Spring Boot制作启动图案
查看>>
《Linux内核设计与实现》读书笔记(十一)- 定时器和时间管理
查看>>
hdu Oil Deposits
查看>>
彻底理解javascript中的this指针
查看>>
SAS去空格
查看>>
MySQL用户和权限管理
查看>>
Spring Cloud构建微服务架构(二)服务消费者
查看>>