在网上有许多文章可能会提到高优先级覆盖低优先级,这里我认为这种说话是一个误区,Spring Boot的配置属性获取实质是通过匹配,从高优先级开始查找,查到即返回属性值。也就是说Spring Boot中同一配置属性在内存中可能会存在多份,但我们获取的是优先级最高的那份。相关源码逻辑,请查看后面 7 Spring Boot获取属性值逻辑
java -jar *.jar --server.port=8181
内部实现Random的api
配置文件的加载顺序会从左到右从上到下的加载,默认情况下加载文件名为:application,后缀名分别为properties、xml、yml、yaml的方式依次查找加载。
Map<String, Object> defaultProperties=new HashMap<>();
defaultProperties.put("person.lastname6", "8085");
defaultProperties.put("server.port", "8085");
application.setDefaultProperties(defaultProperties);
public SpringApplication(Object... sources) {
initialize(sources);
}
private void initialize(Object[] sources) {
...
//设置Spring Boot默认监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
...
}
读取所有META-INF/spring.factories文件,找出所有key为org.springframework.boot.ApplicationListener的监听类,并且实例化添加进入当前监听类集合中。
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//通过type的全类名为key去spring.factories查找对应的value
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//实例化value对应的监听类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
这里真实对应的其实是spring-boot-*.jar下的META-INF/spring.factories
# Application Listeners
org.springframework.context.ApplicationListener=\
...
org.springframework.boot.context.config.ConfigFileApplicationListener,\
...
ConfigFileApplicationListener
负责后面的加载在路径[file:./config/, file:./, classpath:/config/, classpath:/]下,并且后缀为[properties, xml, yml, yaml] 的配置文件
public ConfigurableApplicationContext run(String... args) {
...
// 启动发送监听封装,内部实际发送事件的是EventPublishingRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
try {
//命令行参数解析
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//为启动Spring Boot应用初始化环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
...
}
catch (Throwable ex) {
...
}
}
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
//1 获取配置环境,加载系统属性和系统环境变量
ConfigurableEnvironment environment = getOrCreateEnvironment();
//2 设置命令行参数配置
configureEnvironment(environment, applicationArguments.getSourceArgs());
//3 发送加载配置文件信息事件
listeners.environmentPrepared(environment);
...
return environment;
}
private ConfigurableEnvironment getOrCreateEnvironment() {
...
if (this.webEnvironment) {
return new StandardServletEnvironment();
}
...
}
Spring Boot环境创建关系类图
Spring Boot 环境类图对应源码解析
public abstract class AbstractEnvironment implements ConfigurableEnvironment {
protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";
//这里默认添加配置default
private final Set<String> defaultProfiles = new LinkedHashSet<String>(getReservedDefaultProfiles());
public AbstractEnvironment() {
customizePropertySources(this.propertySources);
...
}
protected Set<String> getReservedDefaultProfiles() {
return Collections.singleton(RESERVED_DEFAULT_PROFILE_NAME);
}
}
public class StandardEnvironment extends AbstractEnvironment {
//系统环境变量 可以通过{@value}获取
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
//JVM 系统属性 可以通过{@value}获取
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
protected void customizePropertySources(MutablePropertySources propertySources) {
//添加JVM系统属性
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
//添加系统环境变量
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
}
protected void configureEnvironment(ConfigurableEnvironment environment,String[] args) {
//2.1 命令行属性配置
configurePropertySources(environment, args);
//2.2 profile配置
configureProfiles(environment, args);
}
protected void configurePropertySources(ConfigurableEnvironment environment,
String[] args) {
MutablePropertySources sources = environment.getPropertySources();
//如果在Spring Boot应用启动之前application.setDefaultProperties(defaultProperties)设置了
//默认属性,将不会去加载命令行解析属性
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
sources.addLast(
new MapPropertySource("defaultProperties", this.defaultProperties));
}
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(
name + "-" + args.hashCode(), args));
composite.addPropertySource(source);
sources.replace(name, composite);
} else {
//如果加载命令行配置属性,优先级将会是最高
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
...
// this.additionalProfiles通过application.setAdditionalProfiles("dev")添加
Set<String> profiles = new LinkedHashSet<String>(this.additionalProfiles);
// 这里的profile 通过代码application.setAdditionalProfiles()添加的优先级最高
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
}
class SpringApplicationRunListeners {
public void environmentPrepared(ConfigurableEnvironment environment) {
//listeners 中是EventPublishingRunListener
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
}
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
//发送ApplicationEnvironmentPreparedEvent event
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
}
public class ConfigFileApplicationListener
implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
...
}
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());
}
}
List<EnvironmentPostProcessor> loadPostProcessors() {
//通过EnvironmentPostProcessor.className查找EnvironmentPostProcessor列表
return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class,
getClass().getClassLoader());
}
// 这里才是真正对Spring Boot配置文件解析的处理
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
//1 添加配置文件属性
addPropertySources(environment, application.getResourceLoader());
configureIgnoreBeanInfo(environment);
bindToSpringApplication(environment, application);
}
}
spring.factories中EnvironmentPostProcessor.className对应(这里不关spring boot配置文件解析事)
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor
protected void addPropertySources(ConfigurableEnvironment environment,
ResourceLoader resourceLoader) {
//1 随机数属性配置
RandomValuePropertySource.addToEnvironment(environment);
//2 配置文件加载
new Loader(environment, resourceLoader).load();
}
public class RandomValuePropertySource extends PropertySource<Random> {
public static void addToEnvironment(ConfigurableEnvironment environment) {
//这里主要添加随机数属性 例如@Value("${random.int}") 真实调用的是random.nextInt()
environment.getPropertySources().addAfter(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
new RandomValuePropertySource(RANDOM_PROPERTY_SOURCE_NAME));
}
}
private class Loader {
public void load() {
//4.1.2.1 创建属性文件加载器
this.propertiesLoader = new PropertySourcesLoader();
this.activatedProfiles = false;
this.profiles = Collections.asLifoQueue(new LinkedList<Profile>());
this.processedProfiles = new LinkedList<Profile>();
//以上四个变量默认状态为空集合或false,用于在下边迭代的过程中收集数据
/*4.1.2.2 设置预先存在的活动配置文件环境.setActiveProfiles()是附加的配置文件,如果需要,配置文件可以添加更多,因此不要在此处调用addActiveProfiles()。如果存在active的profile,会将activatedProfiles变量设置为true
* 例如:在启动Spring Boot应用时,手动指定environment
* StandardEnvironment environment=new StandardServletEnvironment();
* environment.setActiveProfiles("dev");
* application.setEnvironment(environment);
*/
Set<Profile> initialActiveProfiles = initializeActiveProfiles();
//返回还未处理的profile配置,如果spring.profiles.active和addActiveProfile(String)同时指定当前profile,spring.profiles.active占先
this.profiles.addAll(getUnprocessedActiveProfiles(initialActiveProfiles));
//(1)当没有指定当前profile时,添加AbstractEnvironment默认添加的default profile(配置)
if (this.profiles.isEmpty()) {
for (String defaultProfileName : this.environment.getDefaultProfiles()) {
Profile defaultProfile = new Profile(defaultProfileName, true);
if (!this.profiles.contains(defaultProfile)) {
this.profiles.add(defaultProfile);
}
}
}
//(2) null为默认配置占位解析,profiles是Queue队列,调用poll()后进先出,即最开始解析的是默认配置,后面才解析
this.profiles.add(null);
//正常情况下执行(1)(2)后this.profiles中存在[default,null]两个值
while (!this.profiles.isEmpty()) {
Profile profile = this.profiles.poll();
//4.1.2.3 遍历配置文件并且加载配置
for (String location : getSearchLocations()) {
if (!location.endsWith("/")) {
//5 如果location是文件,就不需要在指定路径下搜索更多文件
load(location, null, profile);
}
else {
for (String name : getSearchNames()) {
//5 加载指定配置文件
load(location, name, profile);
}
}
}
this.processedProfiles.add(profile);
}
//6 添加所有配置文件属性进入environment
addConfigurationProperties(this.propertiesLoader.getPropertySources());
}
}
public class PropertySourcesLoader{
public PropertySourcesLoader() {
this(new MutablePropertySources());
}
public PropertySourcesLoader(MutablePropertySources propertySources) {
...
//初始化属性文件加载器(在spring.factories中查找PropertySourceLoader.class对应加载器,并且创建添加),对properties, xml, yml, yaml文件处理
this.loaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
getClass().getClassLoader());
}
}
spring.factories
# PropertySource Loaders
# PropertiesPropertySourceLoader 加载properties, xml文件信息
# YamlPropertySourceLoader 加载yml, yaml文件信息
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
private Set<Profile> initializeActiveProfiles() {
//如果既没有指定ACTIVE_PROFILES_PROPERTY也没有指定INCLUDE_PROFILES_PROPERTY返回空集合
if (!this.environment.containsProperty(ACTIVE_PROFILES_PROPERTY)
&& !this.environment.containsProperty(INCLUDE_PROFILES_PROPERTY)) {
return Collections.emptySet();
}
//(1)通过属性源(如系统属性)设置的任何预先存在的活动配置文件优先于配置文件中添加的配置文件
SpringProfiles springProfiles = bindSpringProfiles(
this.environment.getPropertySources());
Set<Profile> activeProfiles = new LinkedHashSet<Profile>(
springProfiles.getActiveProfiles());
activeProfiles.addAll(springProfiles.getIncludeProfiles());
//(2) 添加profiles进environment,即environment.getActiveProfiles()中
maybeActivateProfiles(activeProfiles);
return activeProfiles;
}
(1) 绑定profile
private SpringProfiles bindSpringProfiles(PropertySources propertySources) {
SpringProfiles springProfiles = new SpringProfiles();
//指定参数名前缀是spring.profiles的数据绑定器
RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles,
"spring.profiles");
//将给定的属性值绑定到此绑定器的目标上,即springProfiles上
dataBinder.bind(new PropertySourcesPropertyValues(propertySources, false));
//解析给定active,include 实例:在classpath:/application.yml中spring:profiles:active: prod,则springProfiles.getActive()为prod
springProfiles.setActive(resolvePlaceholders(springProfiles.getActive()));
springProfiles.setInclude(resolvePlaceholders(springProfiles.getInclude()));
return springProfiles;
}
(2) 添加profiles进environment,即environment.getActiveProfiles()中
private void maybeActivateProfiles(Set<Profile> profiles) {
if (this.activatedProfiles) {
if (!profiles.isEmpty()) {
this.logger.debug("Profiles already activated, '" + profiles
+ "' will not be applied");
}
return;
}
//如果配置中存在activeProfiles
if (!profiles.isEmpty()) {
//添加profiles
addProfiles(profiles);
this.logger.debug("Activated profiles "
+ StringUtils.collectionToCommaDelimitedString(profiles));
//存在spring.profiles.active配置
this.activatedProfiles = true;
//当activatedProfiles=true时,移除default的profile
removeUnprocessedDefaultProfiles();
}
}
private void addProfiles(Set<Profile> profiles) {
for (Profile profile : profiles) {
this.profiles.add(profile);
//如果this.environment.getActiveProfiles()中不存在profile.getName()
if (!environmentHasActiveProfile(profile.getName())) {
//添加active profile
prependProfile(this.environment, profile);
}
}
}
private void prependProfile(ConfigurableEnvironment environment,
Profile profile) {
Set<String> profiles = new LinkedHashSet<String>();
environment.getActiveProfiles();
profiles.add(profile.getName());
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
}
//移除default配置
private void removeUnprocessedDefaultProfiles() {
for (Iterator<Profile> iterator = this.profiles.iterator(); iterator
.hasNext();) {
if (iterator.next().isDefaultProfile()) {
iterator.remove();
}
}
}
private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
//配置文件搜索路径
private Set<String> getSearchLocations() {
Set<String> locations = new LinkedHashSet<String>();
// 如果开发者设置了config的路径,会优先加载
if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {
for (String path : asResolvedSet(
this.environment.getProperty(CONFIG_LOCATION_PROPERTY), null)) {
if (!path.contains("$")) {
path = StringUtils.cleanPath(path);
if (!ResourceUtils.isUrl(path)) {
path = ResourceUtils.FILE_URL_PREFIX + path;
}
}
locations.add(path);
}
}
//DEFAULT_SEARCH_LOCATIONS的路径倒叙添加进入locations
locations.addAll(
asResolvedSet(ConfigFileApplicationListener.this.searchLocations,
DEFAULT_SEARCH_LOCATIONS));
return locations;
}
private void load(String location, String name, Profile profile) {
String group = "profile=" + (profile == null ? "" : profile);
if (!StringUtils.hasText(name)) {
// 直接从location作为文件加载配置
loadIntoGroup(group, location, profile);
}
else {
//5.1 遍历所有后缀名文件
for (String ext : this.propertiesLoader.getAllFileExtensions()) {
if (profile != null) {
// 加载 profile-specific 文件
loadIntoGroup(group, location + name + "-" + profile + "." + ext,
null);
for (Profile processedProfile : this.processedProfiles) {
if (processedProfile != null) {
loadIntoGroup(group, location + name + "-"
+ processedProfile + "." + ext, profile);
}
}
//容错处理。例如在application-dev.yml中出现了不应该出现的"spring.profiles: dev",因此需要带入profile进行配置加载
loadIntoGroup(group, location + name + "-" + profile + "." + ext,
profile);
}
// 5.2 加载指定配置文件
loadIntoGroup(group, location + name + "." + ext, profile);
}
}
}
public class PropertySourcesLoader {
//loaders中包含org.springframework.boot.env.PropertiesPropertySourceLoader,org.springframework.boot.env.YamlPropertySourceLoader两种属性加载器
private final List<PropertySourceLoader> loaders;
public Set<String> getAllFileExtensions() {
Set<String> fileExtensions = new LinkedHashSet<String>();
for (PropertySourceLoader loader : this.loaders) {
fileExtensions.addAll(Arrays.asList(loader.getFileExtensions()));
}
return fileExtensions;
}
}
public class PropertiesPropertySourceLoader implements PropertySourceLoader {
@Override
public String[] getFileExtensions() {
return new String[] { "properties", "xml" };
}
}
public class YamlPropertySourceLoader implements PropertySourceLoader {
@Override
public String[] getFileExtensions() {
return new String[] { "yml", "yaml" };
}
}
private PropertySource<?> loadIntoGroup(String identifier, String location,
Profile profile) {
...
return doLoadIntoGroup(identifier, location, profile);
...
}
private PropertySource<?> doLoadIntoGroup(String identifier, String location,
Profile profile) throws IOException {
Resource resource = this.resourceLoader.getResource(location);
PropertySource<?> propertySource = null;
StringBuilder msg = new StringBuilder();
if (resource != null && resource.exists()) {
String name = "applicationConfig: [" + location + "]";
//默认组applicationConfig: [profile=],
//实例:spring.profiles.active:dev,则组=applicationConfig: [profile=dev]
String group = "applicationConfig: [" + identifier + "]";
//5.2.1 加载器加载配置文件
propertySource = this.propertiesLoader.load(resource, group, name,
(profile == null ? null : profile.getName()));
if (propertySource != null) {
msg.append("Loaded ");
//5.2.2 处理profile属性
handleProfileProperties(propertySource);
}
else {
msg.append("Skipped (empty) ");
}
}else {
msg.append("Skipped ");
}
...
return propertySource;
}
public class PropertySourcesLoader {
public PropertySource<?> load(Resource resource, String group, String name,
String profile) throws IOException {
if (isFile(resource)) {
String sourceName = generatePropertySourceName(name, profile);
for (PropertySourceLoader loader : this.loaders) {
//是否支持加载文件类型,通过后缀名判断
if (canLoadFileExtension(loader, resource)) {
//加载配置文件,并且返回加载结果
PropertySource<?> specific = loader.load(sourceName, resource,
profile);
// 5.2.1.1 添加属性资源进入资源配置列表
addPropertySource(group, specific, profile);
return specific;
}
}
}
return null;
}
//构建属性资源名
private String generatePropertySourceName(String name, String profile) {
return (profile == null ? name : name + "#" + profile);
}
}
这里解释了为什么spring.profiles.active配置属性会优先默认配置文件属性
/**
*basename:group
*/
private void addPropertySource(String basename, PropertySource<?> source,
String profile) {
if (source == null) {
return;
}
if (basename == null) {
this.propertySources.addLast(source);
return;
}
//获取复合属性源
EnumerableCompositePropertySource group = getGeneric(basename);
group.add(source);
if (this.propertySources.contains(group.getName())) {
this.propertySources.replace(group.getName(), group);
}else {
//添加配置属性进入this.propertySources,倒叙添加,这里解释了为什么spring.profiles.active配置属性会优先默认配置文件属性
this.propertySources.addFirst(group);
}
}
private EnumerableCompositePropertySource getGeneric(String name) {
PropertySource<?> source = this.propertySources.get(name);
if (source instanceof EnumerableCompositePropertySource) {
return (EnumerableCompositePropertySource) source;
}
EnumerableCompositePropertySource composite = new EnumerableCompositePropertySource(
name);
return composite;
}
private void handleProfileProperties(PropertySource<?> propertySource) {
//获取SpringProfiles 4.1.2.2 (1)
SpringProfiles springProfiles =bindSpringProfiles(propertySource);
//4.1.2.2(2) 添加profiles进environment,即environment.getActiveProfiles()中
maybeActivateProfiles(springProfiles.getActiveProfiles());
addProfiles(springProfiles.getIncludeProfiles());
}
applicationConfig: [profile=prod]
private void addConfigurationProperties(MutablePropertySources sources) {
List<PropertySource<?>> reorderedSources = new ArrayList<PropertySource<?>>();
for (PropertySource<?> item : sources) {
reorderedSources.add(item);
}
addConfigurationProperties(
new ConfigurationPropertySources(reorderedSources));
}
private void addConfigurationProperties(
ConfigurationPropertySources configurationSources) {
MutablePropertySources existingSources = this.environment
.getPropertySources();
//DEFAULT_PROPERTIES <=> application.setDefaultProperties(defaultProperties)
if (existingSources.contains(DEFAULT_PROPERTIES)) {
existingSources.addBefore(DEFAULT_PROPERTIES, configurationSources);
}else {
existingSources.addLast(configurationSources);
}
}
public abstract class AbstractEnvironment implements ConfigurableEnvironment {
private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);
private final ConfigurablePropertyResolver propertyResolver =
new PropertySourcesPropertyResolver(this.propertySources);
@Override
public String getProperty(String key) {
return this.propertyResolver.getProperty(key);
}
}
此处为MutablePropertySources的属性解析器,属性优先级为MutablePropertySources的index
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
private final PropertySources propertySources;
public PropertySourcesPropertyResolver(PropertySources propertySources) {
this.propertySources = propertySources;
}
@Override
public String getProperty(String key) {
return getProperty(key, String.class, true);
}
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
...
Object value = propertySource.getProperty(key);
//这里是配置有效优先级的关键,优先级取决于this.propertySources中的index
if (value != null) {
if (resolveNestedPlaceholders && value instanceof String) {
value = resolveNestedPlaceholders((String) value);
}
logKeyFound(key, propertySource, value);
return convertValueIfNecessary(value, targetValueType);
}
}
}
...
return null;
}
}
@SpringBootApplication
public class SpringBoot02ConfigApplication {
public static void main(String[] args) {
// SpringApplication.run(SpringBoot02ConfigApplication.class, args);
SpringApplication application=new SpringApplication(new Object[]{SpringBoot02ConfigApplication.class});
/* 手动指定environment
* StandardEnvironment environment=new StandardServletEnvironment();
* environment.setActiveProfiles("dev");
* application.setEnvironment(environment);
*/
Map<String, Object> defaultProperties=new HashMap<>();
defaultProperties.put("person1.username", "张三");
application.setDefaultProperties(defaultProperties);
application.setAdditionalProfiles("dev");
application.run(args);
}
}
内存字符串信息
[SimpleCommandLinePropertySource {name='commandLineArgs'},
StubPropertySource {name='servletConfigInitParams'},
StubPropertySource {name='servletContextInitParams'},
MapPropertySource {name='systemProperties'},
SystemEnvironmentPropertySource {name='systemEnvironment'},
RandomValuePropertySource {name='random'},
ConfigurationPropertySources {name='applicationConfigurationProperties'},
MapPropertySource {name='defaultProperties'}]
命令行对应属性配置
Servlet初始参数
ServletContext初始化参数
JVM系统属性
操作系统环境变量
随机生成的带random.*前缀的属性
配置文件(例如:classpath:/application.yml)属性
默认属性