前言
之前我们分析了SpringApplication#run⽅法的前3步.在这⾥我们分析第4步-->创建⼀个DefaultApplicationArguments对象,调⽤prepareEnvironment⽅法。
本篇涉及到的代码:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
......
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
......
}
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args)流程简述:
DefaultApplicationArguments有两个对象:
private final DefaultApplicationArguments.Source source; private final String[] args;
1、创建一个DefaultApplicationArguments对象,该构造方法,会调用
解析args入参,放到该对象的source属性中,这个source是一个DefaultApplicationArguments.Source对象。
this.source = new DefaultApplicationArguments.Source(args);
2、命令行参数会放到CommandLineArgs对象中(DefaultApplicationArguments.Source是CommandLineArgs的子类),以"--"开头的参数都会放到optionArgs属性,该属性是一个Hashmap;其他参数会放到nonOptionArgs属性中,该属性是一个ArrayList。
3、通知所有观察者。最终走到org.springframework.boot.env.EnvironmentPostProcessor,找到对应的SpringApplicationJsonEnvironmentPostProcessor类和CloudFoundryVcapEnvironmentPostProcessor类,执行他们的postProcessEnvironment方法。
DefaultApplicationArguments.Source继承结构图:
分析
1. 创建DefaultApplicationArguments.将启动时的参数传⼊到其构造器中.其构造器如下:
public DefaultApplicationArguments(String[] args) {
Assert.notNull(args, "Args must not be null");
this.source = new DefaultApplicationArguments.Source(args);
this.args = args;
}
Source类的定义:
private static class Source extends SimpleCommandLinePropertySource {
Source(String[] args) {
super(args);
}
public List<String> getNonOptionArgs() {
return super.getNonOptionArgs();
}
public List<String> getOptionValues(String name) {
return super.getOptionValues(name);
}
}
在Source的构造器中调⽤了⽗类的SimpleCommandLinePropertySource的构造器.如下:
public SimpleCommandLinePropertySource(String... args) {
super((new SimpleCommandLineArgsParser()).parse(args));
}
实例化了SimpleCommandLineArgsParser并调⽤其parse⽅法进⾏解析参数.代码如下:
public CommandLineArgs parse(String... args) {
//创建CommandLineArgs对象
CommandLineArgs commandLineArgs = new CommandLineArgs();
String[] var3 = args;
int var4 = args.length;
for(int var5 = 0; var5 < var4; ++var5) {
//进循环,判断是否以--开头
String arg = var3[var5];
if (arg.startsWith("--")) {
//如果是就截取,截取长度是参数长度,如果命令是--spring,那么就从s开始截取,包括s
String optionText = arg.substring(2, arg.length());
String optionValue = null;
String optionName;
//如果匹配到了=号,截取=号左边做optionName,右边做optionValue
if (optionText.contains("=")) {
optionName = optionText.substring(0, optionText.indexOf("="));
optionValue = optionText.substring(optionText.indexOf("=") + 1, optionText.length());
} else {
//如果没有=号,optionName 直接就是截取的optionText
optionName = optionText;
}
if (optionName.isEmpty() || optionValue != null && optionValue.isEmpty()) {
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
}
//这里将解析的参数添加到上面创建的CommandLineArgs对象中,该对象中有一个Map<String, List<String>>来存放
commandLineArgs.addOptionArg(optionName, optionValue);
} else {
//不是--开头就是直接添加到非选项参数
commandLineArgs.addNonOptionArg(arg);
}
}
return commandLineArgs;
}
逻辑很简单,⾸先初始化了CommandLineArgs.然后遍历args.如果args是--开头的,就加⼊OptionArg中,否
则加⼊到NonOptionArg中。
解析完毕后,接着调⽤CommandLinePropertySource的构造器,代码如下:
public static final String COMMAND_LINE_PROPERTY_SOURCE_NAME = "commandLineArgs";
public CommandLinePropertySource(T source) {
super(COMMAND_LINE_PROPERTY_SOURCE_NAME, source);
}
EnumerablePropertySource的构造器如下:
public EnumerablePropertySource(String name, T source) {
super(name, source);
}
PropertySource 构造器如下:
public PropertySource(String name, T source) {
Assert.hasText(name, "Property source name must contain at least one character");
Assert.notNull(source, "Property source must not be null");
this.name = name;
this.source = source;
}
⾄此DefaultApplicationArguments初始化完毕。
2. DefaultApplicationArguments初始化完毕后,调⽤SpringApplication#prepareEnvironment.代码如下:
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments)流程简述:
1、获取或创建environment,如果this.webEnvironment为true,则new StandardServletEnvironment()返回,否则new StandardEnvironment();
2、配置环境变量,分为两个部分,配置ProperSources和配置Profiles。
a.配置ProperSources
主要是配置environment.getPropertySources()的对象。如果addCommandLineProperties为true并且有命令参数,分两步骤⾛:第⼀步存在commandLineArgs则继续设置属性;第⼆步commandLineArgs不存在则在头部添加commandLineArgs。
b.配置Profiles判断this.activeProfiles是否为空,不为空获取''spring.profiles.active"的property参数,添加到activeProfiles属性中。
再调用environment#setActiveProfiles方法,这种激活的配置文件。
3、配置监听器。(做的事太多,还不了解)
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
//1、 Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 2. 配置环境的信息,applicationArguments.getSourceArgs()是命令行参数
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 3. 通知所有的观察者,环境已经准备好了
listeners.environmentPrepared(environment);
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
代码做了3件事:
1. 获取或者创建ConfigurableEnvironment
2. 配置ConfigurableEnvironment
3. 通知所有的观察者,发送ApplicationEnvironmentPreparedEvent事件.
3. 获取或者创建ConfigurableEnvironment调⽤的是getOrCreateEnvironment⽅法.代码如下:
private ConfigurableEnvironment getOrCreateEnvironment() {
// 1. 如果environment不为空则直接返回
if (this.environment != null) {
return this.environment;
}
// 2. 如果是web环境则直接实例化StandardServletEnvironment类
if (this.webEnvironment) {
return new StandardServletEnvironment();
}
// 3. 如果不是web环境则直接实例化StandardEnvironment类
return new StandardEnvironment();
}
⾸先判断environment是否为空,如果不为空直接返回,否则 如果是web环境则直接实例化StandardServletEnvironment,否则返回StandardEnvironment.
⼀般创建的是StandardServletEnvironment.
StandardServletEnvironment类的继承结构如下:
在StandardServletEnvironment实例化时,会触发AbstractEnvironment实例化.⽽在AbstractEnvironment的构造器中会调⽤customizePropertySources⽅法.代码如下:
public AbstractEnvironment() {
this.propertySources = new MutablePropertySources(this.logger);
this.propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
this.customizePropertySources(this.propertySources);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Initialized " + this.getClass().getSimpleName() + " with PropertySources " + this.propertySources);
}
}
⽽在StandardServletEnvironment中的customizePropertySources⽅法如下:
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
propertySources.addLast(new StubPropertySource("servletContextInitParams"));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource("jndiProperties"));
}
super.customizePropertySources(propertySources);
}
在该⽅法中添加了servletConfigInitParams,servletContextInitParams,jndiProperties对应的Source. 在笔者的demo环境中, jndiProperties没有添加进去.
然后调⽤其StandardEnvironment#customizePropertySources⽅法.添加MapPropertySource,SystemEnvironmentPropertySource.代码如下:
protected void customizePropertySources(MutablePropertySources propertySources
) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
4. 配置ConfigurableEnvironment,调⽤的是SpringApplication#configureEnvironment⽅法.代码如下:
protected void configureEnvironment(ConfigurableEnvironment environment,
String[] args) {
configurePropertySources(environment, args);
configureProfiles(environment, args);
}
做了2件事:
1. 配置PropertySources
2. 配置Profiles
configurePropertySources⽅法如下:
protected void configurePropertySources(ConfigurableEnvironment environment,
String[] args) {
MutablePropertySources sources = environment.getPropertySources();
// 1. 如果defaultProperties不为空,则继续添加defaultProperties
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
sources.addLast(
new MapPropertySource("defaultProperties", this.defaultProperties));
}
// 2. 如果addCommandLineProperties为true并且有命令参数,
// 分两步骤⾛:第⼀步存在commandLineArgs则继续设置属性;第⼆步commandLineArgs不存在则在头部添加commandLineArgs
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));
}
}
}
做了2件事:
1. 如果defaultProperties不为空,则继续添加defaultProperties
在当前环境下defaultProperties没有添加进去. 2. 如果addCommandLineProperties为true并且有命令参数, 分两步骤⾛:第⼀步存在commandLineArgs则继续设置属性;第⼆步commandLineArgs不存在则在头部添加commandLineArgs
那么该⽅法执⾏完毕后,MutablePropertySources类中propertySourceList已经存在的属性为:
commandLineArgs、 servletConfigInitParams、 servletContextInitParams、 jndiProperties(如果存在)、 systemProperties、 systemEnvironment、 defaultProperties(如果存在)
配置Profiles,调⽤的是SpringApplication#configureProfiles⽅法.代码如下:
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
environment.getActiveProfiles(); // ensure they are initialized
// But these ones should go first (last wins in a property key clash)
Set<String> profiles = new LinkedHashSet<String>(this.additionalProfiles);
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
}
做了3件事:
1. 调⽤AbstractEnvironment#getActiveProfiles获得Profile的配置.Profile配置项为spring.profiles.active
2. 调⽤AbstractEnvironment#getActiveProfiles⽅法获取激活的Profile添加到profiles中.
3. 设置AbstractEnvironment的activeProfiles。
AbstractEnvironment#getActiveProfiles代码如下:
public String[] getActiveProfiles() {
return StringUtils.toStringArray(doGetActiveProfiles());
}
调⽤了doGetActiveProfiles⽅法.代码如下:
protected Set<String> doGetActiveProfiles() {
synchronized(this.activeProfiles) {
if (this.activeProfiles.isEmpty()) {
String profiles = this.getProperty("spring.profiles.active");
if (StringUtils.hasText(profiles)) {
this.setActiveProfiles(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(profiles)));
}
}
return this.activeProfiles;
}
}
⾸先判断activeProfiles是否为空,如果不为空的话,就直接返回.否则调⽤PropertySourcesPropertyResolver#getProperty("spring.profiles.active") 进⾏查找.如果有配置的话,就加⼊到AbstractEnvironment的activeProfiles中
思考 为什么要这么做?
spring boot 有⼀个参数优先级的概念.外置的配置优先于代码级别的.这⾥就是⼀个实现
5. 通知所有的观察者,发送ApplicationEnvironmentPreparedEvent事件.调⽤的是SpringApplicationRunListeners#environmentPrepared⽅法.关于这⾥上篇⽂章有解释到.最终会调⽤
EventPublishingRunListener#environmentPrepared 发送ApplicationEnvironmentPreparedEvent事件.
对ApplicationEnvironmentPreparedEvent事件感兴趣的有:
org.springframework.boot.context.config.ConfigFileApplicationListener,
org.springframework.boot.context.config.AnsiOutputApplicationListener,
org.springframework.boot.logging.LoggingApplicationListener,
org.springframework.boot.logging.ClasspathLoggingApplicationListener,
org.springframework.boot.autoconfigure.BackgroundPreinitializer,
org.springframework.boot.context.config.DelegatingApplicationListener,
org.springframework.boot.context.FileEncodingApplicationListener
ConfigFileApplicationListener#onApplicationEvent代码如下:
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}
调⽤onApplicationEnvironmentPreparedEvent⽅法.代码如下:
rivate void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
Iterator var3 = postProcessors.iterator();
while(var3.hasNext()) {
EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
}
List<EnvironmentPostProcessor> loadPostProcessors() {
return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, this.getClass().getClassLoader());
}
实现逻辑如下:
⾸先调⽤SpringFactoriesLoader加载EnvironmentPostProcessor.同时也将⾃⼰加⼊到postProcessors.
排序后依次调⽤其postProcessEnvironment⽅法。
对于当前场景来说. EnvironmentPostProcessor如下:
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,
org.springframework.boot.context.config.ConfigFileApplicationListener
在spring-boot/META-INF/spring.factories中的配置如下:
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor
SpringApplicationJsonEnvironmentPostProcessor#postProcessEnvironment代码如下:
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
String json = environment.resolvePlaceholders("${spring.application.json:${SPRING_APPLICATION_JSON:}}");
if (StringUtils.hasText(json)) {
this.processJson(environment, json);
}
}
private void processJson(ConfigurableEnvironment environment, String json) {
try {
JsonParser parser = JsonParserFactory.getJsonParser();
Map<String, Object> map = parser.parseMap(json);
if (!map.isEmpty()) {
this.addJsonPropertySource(environment, new MapPropertySource("spring.application.json", this.flatten(map)));
}
} catch (Exception var5) {
logger.warn("Cannot parse JSON for spring.application.json: " + json, var5);
}
}
实现逻辑如下:
1. 依次获取spring.application.json,SPRINGAPPLICATIONJSON的值,如果没有配置的话,默认返回的空字符串。
2. 如果有配置的话,就调⽤processJson⽅法,在environment中添加MapPropertySource.name为spring.application.json。
CloudFoundryVcapEnvironmentPostProcessor#postProcessEnvironment代码如下:
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
if (CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) {
Properties properties = new Properties();
this.addWithPrefix(properties, this.getPropertiesFromApplication(environment), "vcap.application.");
this.addWithPrefix(properties, this.getPropertiesFromServices(environment), "vcap.services.");
MutablePropertySources propertySources = environment.getPropertySources();
if (propertySources.contains("commandLineArgs")) {
propertySources.addAfter("commandLineArgs", new PropertiesPropertySource("vcap", properties));
} else {
propertySources.addFirst(new PropertiesPropertySource("vcap", properties));
}
}
}
1. ⾸先调⽤CloudPlatform.CLOUDFOUNDRY#isActive进⾏判断是否在CloudFoundry中.判断的逻辑为environment是否有VCAPAPPLICATION或者VCAP_SERVICES的配置 如下:
public boolean isActive(Environment environment) {
return environment.containsProperty("VCAP_APPLICATION") || environment.containsProperty("VCAP_SERVICES");
}
2. 如果是在CloudFoundry的话.则将vcap.application.*, vcap.services.* 的配置加⼊到Properties中. 接
下来判断 environment中是否有commandLineArgs的Sources.如果有的话,则添加到
commandLineArgs中,否则添加名为vcap的PropertiesPropertySource.
⼀般情况下 CloudPlatform.CLOUD_FOUNDRY 返回的false.
ConfigFileApplicationListener#postProcessEnvironment代码如下:
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
this.addPropertySources(environment, application.getResourceLoader());
this.configureIgnoreBeanInfo(environment);
this.bindToSpringApplication(environment, application);
}
addPropertySources⽅法如下:
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
(new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
}
做了两件事:
1. 调⽤了RandomValuePropertySource#addToEnvironment⽅法,向environment中名为
systemEnvironment的添加了RandomValuePropertySource(名称为random)
代码如下:
/** System environment property source name: {@value} */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
public static final String RANDOM_PROPERTY_SOURCE_NAME = "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");
}
正是因此我们才能在配置⽂件中使⽤${random.int} ⽣成随机值.
2. 初始化了Loader并调⽤其load⽅法.代码如下:
public void load() {
this.propertiesLoader = new PropertySourcesLoader();
this.activatedProfiles = false;
this.profiles = Collections.asLifoQueue(new LinkedList());
this.processedProfiles = new LinkedList();
Set<ConfigFileApplicationListener.Profile> initialActiveProfiles = this.initializeActiveProfiles();
this.profiles.addAll(this.getUnprocessedActiveProfiles(initialActiveProfiles));
if (this.profiles.isEmpty()) {
String[] var2 = this.environment.getDefaultProfiles();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
String defaultProfileName = var2[var4];
ConfigFileApplicationListener.Profile defaultProfile = new ConfigFileApplicationListener.Profile(defaultProfileName, true);
if (!this.profiles.contains(defaultProfile)) {
this.profiles.add(defaultProfile);
}
}
}
this.profiles.add((Object)null);
ConfigFileApplicationListener.Profile profile;
label41:
for(; !this.profiles.isEmpty(); this.processedProfiles.add(profile)) {
profile = (ConfigFileApplicationListener.Profile)this.profiles.poll();
Iterator var8 = this.getSearchLocations().iterator();
while(true) {
while(true) {
if (!var8.hasNext()) {
continue label41;
}
String location = (String)var8.next();
if (!location.endsWith("/")) {
this.load(location, (String)null, profile);
} else {
Iterator var10 = this.getSearchNames().iterator();
while(var10.hasNext()) {
String name = (String)var10.next();
this.load(location, name, profile);
}
}
}
}
}
this.addConfigurationProperties(this.propertiesLoader.getPropertySources());
}
处理步骤如下:
1. 调⽤initializeActiveProfiles.获得ActiveProfiles.将未激活的Profiles加⼊到profiles中.如果
profiles为空的话,就将spring.profiles.default配置的profile添加到profiles中.
2. 依次遍历profiles中的profile.依次在classpath:/,classpath:/config/,file:./,file:./config/中加载
application的配置.调⽤ConfigFileApplicationListener$Loader#load进⾏加载.
3. 调⽤addConfigurationProperties,向environment中添加ConfigurationPropertySources.代码如
下:
private void addConfigurationProperties(MutablePropertySources sources) {
List<PropertySource<?>> reorderedSources = new ArrayList();
Iterator var3 = sources.iterator();
while(var3.hasNext()) {
PropertySource<?> item = (PropertySource)var3.next();
reorderedSources.add(item);
}
this.addConfigurationProperties(new ConfigFileApplicationListener.ConfigurationPropertySources(reorderedSources));
}
initializeActiveProfiles代码如下:
private Set<Profile> initializeActiveProfiles() {
// 1. 如果environment不含有spring.profiles.active和spring.profiles.inclu
de的配置话,返回空集合
if (!this.environment.containsProperty(ACTIVE_PROFILES_PROPERTY)
&& !this.environment.containsProperty(INCLUDE_PROFILES_PROPERTY)) {
return Collections.emptySet();
}
// Any pre-existing active profiles set via property sources (e.g. System
// properties) take precedence over those added in config files.
// 2. 调⽤bindSpringProfiles,⽣成SpringProfiles
SpringProfiles springProfiles = bindSpringProfiles(
this.environment.getPropertySources());
Set<Profile> activeProfiles = new LinkedHashSet<Profile>(
springProfiles.getActiveProfiles());
activeProfiles.addAll(springProfiles.getIncludeProfiles());
// 3. 调⽤maybeActivateProfiles.将activatedProfiles设为true
maybeActivateProfiles(activeProfiles);
return activeProfiles;
}
代码的逻辑如下:
1. 如果environment不含有spring.profiles.active和spring.profiles.include的配置话,返回空集合
注意: 当前的environment拥有的source有 commandLineArgs、servletConfigInitParams、 servletContextInitParams、 systemProperties、systemEnvironment, RandomValuePropertySource 如果想 不返回空的话,就需要在以上的source中有配置.最简单的⽅式是通过命令⾏的⽅式传⼊ --spring.profiles.active=youprofiles 即可
2. 调⽤bindSpringProfiles,⽣成SpringProfiles
3. 调⽤maybeActivateProfiles.将activatedProfiles设为true
bindSpringProfiles代码如下:
private SpringProfiles bindSpringProfiles(PropertySources propertySources){
SpringProfiles springProfiles = new SpringProfiles();
RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles,
"spring.profiles");
dataBinder.bind(new PropertySourcesPropertyValues(propertySources, false));
springProfiles.setActive(resolvePlaceholders(springProfiles.getActive(
)));
springProfiles.setInclude(resolvePlaceholders(springProfiles.getInclude()));
return springProfiles;
}
逻辑如下:
1. 初始化SpringProfiles和RelaxedDataBinder.RelaxedDataBinder读取的配置是前缀为spring.profiles的配置.
2. 实例化PropertySourcesPropertyValues,调⽤DataBinder#bind进⾏数据的绑定.
3. 设置SpringProfiles的Active和Include属性.
其中第2步中PropertySourcesPropertyValues的构造器代码如下:
PropertySourcesPropertyValues(PropertySources propertySources,
Collection<String> nonEnumerableFallbackNames,PropertyNamePatternsMatcher includes, boolean resolvePlaceholders) {
Assert.notNull(propertySources, "PropertySources must not be null");
Assert.notNull(includes, "Includes must not be null");
this.propertySources = propertySources;
this.nonEnumerableFallbackNames = nonEnumerableFallbackNames;
this.includes = includes;
this.resolvePlaceholders = resolvePlaceholders;
PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver(
propertySources);
for (PropertySource<?> source : propertySources) {
processPropertySource(source, resolver);
}
}
其中最主要的代码是 初始化了 PropertySourcesPropertyResolver.并依次遍历environment中的
PropertySources.调⽤processPropertySource⽅法进⾏处理.
注意
这⾥的source为 [SimpleCommandLinePropertySource {name='commandLineArgs'},StubPropertySource {name='servletConfigInitParams'}, StubPropertySource{name='servletContextInitParams'}, MapPropertySource {name='systemProperties'},SystemEnvironmentPropertySource {name='systemEnvironment'},RandomValuePropertySource {name='random'}}
processPropertySource 代码如下:
private void processPropertySource(PropertySource<?> source,
PropertySourcesPropertyResolver resolver) {
if (source instanceof CompositePropertySource) {
processCompositePropertySource((CompositePropertySource) source, resolver);
}else if (source instanceof EnumerablePropertySource) {
processEnumerablePropertySource((EnumerablePropertySource<?>) source,resolver, this.includes);
}else {
processNonEnumerablePropertySource(source, resolver);
}
}
这⾥的逻辑很简单:
1. 如果 source 为 CompositePropertySource的话,调⽤processCompositePropertySource
2. 如果 source 为 EnumerablePropertySource 的话,调⽤processEnumerablePropertySource
3. 否则 调⽤ processNonEnumerablePropertySource
这⾥我们需要看下各个source的类图.分别如下:
StubPropertySource 类图为:
MapPropertySource 类图为:
SystemEnvironmentPropertySource 类图为:
RandomValuePropertySource 类图为:
(未完结,暂搁置)