源码:
run
 |- 1 stopWatch.start()
 |- 2 configureHeadlessProperty
 |- 3 listeners.starting()
 |- 4 prepareEnvironment(...)
 |- 5 printBanner(environment)
 |- 6 createApplicationContext()
 |- 7 new FailureAnalyzers(context)
 |- 8 prepareContext(...)
 |- 9 refreshContext(context)
 |- 10 afterRefresh
 |- 11 listeners.finished
 |- 12 stopWatch.stop()
 |- 13 new StartupInfoLogger(...).logStarted(...)
 |- 14 handleRunFailure(...)



public ConfigurableApplicationContext run(String... args) {// 略 1~3 ...try {// 4、ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);// 略 5~13 ...return context;}catch (Throwable ex) {// 略 14 ...}
}

1、创建DefaultApplicationArguments实例

DefaultApplicationArguments 是啥?说白了,它就是用来封装运行参数并提供一些方便访问参数的方法。

public DefaultApplicationArguments(String[] args) {Assert.notNull(args, "Args must not be null");this.source = new Source(args);this.args = args;
}

创建 DefaultApplicationArguments 实例时,初始化两个实例变量 ,最终的结果如下图所示(运行参数设置了 --server.port=8001),大家可以自行查看源码,简单不赘述

2、prepareEnvironment

这个方法做了三件事情:
1、获取或者创建ConfigurableEnvironment - StandardServletEnviroment
web环境会创建StandardServletEnviroment
2、
3、

2.1 获取或者创建ConfigurableEnvironment


/****** o.s.boot.SpringApplication ******/private ConfigurableEnvironment getOrCreateEnvironment() {if (this.environment != null) {return this.environment;}if (this.webEnvironment) {return new StandardServletEnvironment();}return new StandardEnvironment();
}

ConfigurableEnvironment 是个接口,主要作用是提供当前运行环境的公开接口,其中 StandardServletEnviromentStandardEnvironment 都是其实现类,类图如下:

StandardServletEnviroment 类图

我们在创建 StandardServletEnviroment 实例拥有从父类 AbstractEnviroment 继承来的 MutablePropertySources 类型属性 propertySources ,在创建实例时,调用 customizePropertySources(...) 方法向propertySources放入一些PropertySource对象。

调用关系

源码参考:

/****** o.s.core.env.AbstractEnvironment ******/
public AbstractEnvironment() {customizePropertySources(this.propertySources);if (logger.isDebugEnabled()) {logger.debug("Initialized " + getClass().getSimpleName() + " with PropertySources " + this.propertySources);}
}/****** o.s.web.context.support.StandardEnvironment ******/
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()));
}/****** o.s.web.context.support.StandardServletEnvironment ******/
protected void customizePropertySources(MutablePropertySources propertySources) {propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));}super.customizePropertySources(propertySources);
}

执行完这些代码后的内存状态如下图:

StandardServletEnvironment 内存状态图

点击查看:System.getProperties()内容
点击查看:System.getenv()内容

2.2 配置ConfigurableEnvironment

 protected void configureEnvironment(ConfigurableEnvironment environment,String[] args) {configurePropertySources(environment, args);configureProfiles(environment, args);}

2.2.1 配置PropertySources

所谓的配置PropertySource ,其实就是向环境中添加 PropertSource ,画个图看一下

StandardServletEnvironment 内存状态图
 private boolean addCommandLineProperties = true;// 在environment中添加、删除或重新排序所有的propertysource。protected void configurePropertySources(ConfigurableEnvironment environment,String[] args) {MutablePropertySources sources = environment.getPropertySources();// 我的 defaultProperties 为null,什么时候有值? 硬编码设置默认属性时有值!参考:[1、硬编码]if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {// 放在List的最后位置,表示优先级最低sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));}if (this.addCommandLineProperties && args.length > 0) {// COMMAND_LINE_PROPERTY_SOURCE_NAME 值为 "commandLineArgs"String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;// 从 MutablePropertySources 的变量 List<PropertySource<?>> propertySourceList  中// 查找有没有名称为 commandLineArgs 的 PropertySource,我们看一下上面的“内存状态图”,里面是没有的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 {// 将 命令行参数封装为SimpleCommandLinePropertySource 放入MutablePropertySources 中// 放在第一个表示优先级最高sources.addFirst(new SimpleCommandLinePropertySource(args));}}}

参考链接:    [1、硬编码]


我们来看看StandardServletEnvironment 中 MutablePropertySources 的 List<PropertySource<?>> propertySourceList 变量的结果:

/****************** StandardServletEnvironment ******************/
environment = {StandardServletEnvironment@1914} "..."ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active"activeProfiles = {LinkedHashSet@1998}  size = 0DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default"defaultProfiles = {LinkedHashSet@2000}  size = 1IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore"JNDI_PROPERTY_SOURCE_NAME = "jndiProperties"logger = {SLF4JLocationAwareLog@1978} propertyResolver = {PropertySourcesPropertyResolver@2003} /****************** MutablePropertySources  ******************/propertySources = {MutablePropertySources@1931} "[...]"logger = {SLF4JLocationAwareLog@1978} /****************** MutablePropertySources#List<PropertySource>propertySourceList ******************/propertySourceList = {CopyOnWriteArrayList@1979}  size = 50 = {SimpleCommandLinePropertySource@..} "SimpleCommandLinePropertySource {name='commandLineArgs'}"1 = {PropertySource$StubPropertySource@..} "StubPropertySource {name='servletConfigInitParams'}"2 = {PropertySource$StubPropertySource@..} "StubPropertySource {name='servletContextInitParams'}"3 = {MapPropertySource@1984} "MapPropertySource {name='systemProperties'}"4 = {SystemEnvironmentPropertySource@..} "SystemEnvironmentPropertySource {name='systemEnvironment'}"RESERVED_DEFAULT_PROFILE_NAME = "default"SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams"SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams"SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment"SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties"

2.2.2 配置 profiles

设置应用程序的 profiles,profiles 的作用就是将不同的配置参数作用于不同的的环境。

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

2.2.3

onApplicationEvent:167, ConfigFileApplicationListener (o.s.boot.context.config)
doInvokeListener:172, SimpleApplicationEventMulticaster (o.s.context.event)
invokeListener:165, SimpleApplicationEventMulticaster (o.s.context.event)
multicastEvent:139, SimpleApplicationEventMulticaster (o.s.context.event)
multicastEvent:122, SimpleApplicationEventMulticaster (o.s.context.event)
environmentPrepared:74, EventPublishingRunListener (o.s.boot.context.event)
environmentPrepared:54, SpringApplicationRunListeners (o.s.boot)
prepareEnvironment:325, SpringApplication (o.s.boot)
run:296, SpringApplication (o.s.boot)
main:20, PropertyTestMainSpringApplication (com.yh.stu.springboot.property)
@Overridepublic void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {Executor executor = getTaskExecutor();if (executor != null) {executor.execute(new Runnable() {@Overridepublic void run() {invokeListener(listener, event);}});}else {invokeListener(listener, event);}}}// getApplicationListeners(event, type)的结果:
result = {LinkedList@1976}  size = 70 = {ConfigFileApplicationListener@1864} 1 = {AnsiOutputApplicationListener@1978} 2 = {LoggingApplicationListener@1979} 3 = {ClasspathLoggingApplicationListener@1980} 4 = {BackgroundPreinitializer@1981} 5 = {DelegatingApplicationListener@1982} 6 = {FileEncodingApplicationListener@1983} 

Q&A :

1、❓ // TODO 查看其它 Listener 是如何判断是否监听特定event的

ConfigFileApplicationListener也监听了 ApplicationEnvironmentPreparedEvent 事件 ,是因为实现了 SmartApplicationListener 接口的方法supportsEventType,这里会判断是否支持特定的 event
从所有Listener中获取监听特定event 的ListenersupportsEventType

supportsEventType:156, ConfigFileApplicationListener (o.s.boot.context.config)
supportsEventType:64, GenericApplicationListenerAdapter (o.s.context.event)
supportsEvent:289, AbstractApplicationEventMulticaster (o.s.context.event)
retrieveApplicationListeners:221, AbstractApplicationEventMulticaster (o.s.context.event)
getApplicationListeners:192, AbstractApplicationEventMulticaster (o.s.context.event)
multicastEvent:128, SimpleApplicationEventMulticaster (o.s.context.event)
multicastEvent:122, SimpleApplicationEventMulticaster (o.s.context.event)
environmentPrepared:74, EventPublishingRunListener (o.s.boot.context.event)
environmentPrepared:54, SpringApplicationRunListeners (o.s.boot)
prepareEnvironment:325, SpringApplication (o.s.boot)
run:296, SpringApplication (o.s.boot)
run:1118, SpringApplication (o.s.boot)
run:1107, SpringApplication (o.s.boot)
main:20, SpringBootSourceStuApplication (com.yh.stu.springboot.hello)

2、如何解析application.yml/properties 文件的时机?

搜索:application.properties,找到 ConfigFileApplicationListener ,搜索yml 找到load方法,打上断点

调用栈:

getAllFileExtensions:205, PropertySourcesLoader (o.s.boot.env)
load:447, ConfigFileApplicationListener$Loader (o.s.boot.context.config)
load:386, ConfigFileApplicationListener$Loader (o.s.boot.context.config)
addPropertySources:225, ConfigFileApplicationListener (o.s.boot.context.config)
postProcessEnvironment:195, ConfigFileApplicationListener (o.s.boot.context.config)
onApplicationEnvironmentPreparedEvent:182, ConfigFileApplicationListener (o.s.boot.context.config)
onApplicationEvent:168, ConfigFileApplicationListener (o.s.boot.context.config)
doInvokeListener:172, SimpleApplicationEventMulticaster (o.s.context.event)
invokeListener:165, SimpleApplicationEventMulticaster (o.s.context.event)
multicastEvent:139, SimpleApplicationEventMulticaster (o.s.context.event)
multicastEvent:122, SimpleApplicationEventMulticaster (o.s.context.event)
environmentPrepared:74, EventPublishingRunListener (o.s.boot.context.event)
environmentPrepared:54, SpringApplicationRunListeners (o.s.boot)
prepareEnvironment:325, SpringApplication (o.s.boot)
run:296, SpringApplication (o.s.boot)
run:1118, SpringApplication (o.s.boot)
run:1107, SpringApplication (o.s.boot)
main:20, SpringBootSourceStuApplication (com.yh.stu.springboot.hello)
public PropertySourcesLoader(MutablePropertySources propertySources) {Assert.notNull(propertySources, "PropertySources must not be null");this.propertySources = propertySources;// 两个:YamlPropertySourceLoader PropertiesPropertySourceLoader this.loaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,getClass().getClassLoader());
}

附-YamlPropertySourceLoader

public class YamlPropertySourceLoader implements PropertySourceLoader {@Overridepublic String[] getFileExtensions() {return new String[] { "yml", "yaml" };}@Overridepublic PropertySource<?> load(String name, Resource resource, String profile)throws IOException {if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {Processor processor = new Processor(resource, profile);Map<String, Object> source = processor.process();if (!source.isEmpty()) {return new MapPropertySource(name, source);}}return null;}/*** {@link YamlProcessor} to create a {@link Map} containing the property values.* Similar to {@link YamlPropertiesFactoryBean} but retains the order of entries.*/private static class Processor extends YamlProcessor {Processor(Resource resource, String profile) {if (profile == null) {setMatchDefault(true);setDocumentMatchers(new SpringProfileDocumentMatcher());}else {setMatchDefault(false);setDocumentMatchers(new SpringProfileDocumentMatcher(profile));}setResources(resource);}@Overrideprotected Yaml createYaml() {return new Yaml(new StrictMapAppenderConstructor(), new Representer(),new DumperOptions(), new Resolver() {@Overridepublic void addImplicitResolver(Tag tag, Pattern regexp,String first) {if (tag == Tag.TIMESTAMP) {return;}super.addImplicitResolver(tag, regexp, first);}});}public Map<String, Object> process() {final Map<String, Object> result = new LinkedHashMap<String, Object>();process(new MatchCallback() {@Overridepublic void process(Properties properties, Map<String, Object> map) {result.putAll(getFlattenedMap(map));}});return result;}}}

附-PropertiesPropertySourceLoader

public class PropertiesPropertySourceLoader implements PropertySourceLoader {@Overridepublic String[] getFileExtensions() {return new String[] { "properties", "xml" };}@Overridepublic PropertySource<?> load(String name, Resource resource, String profile)throws IOException {if (profile == null) {Properties properties = PropertiesLoaderUtils.loadProperties(resource);if (!properties.isEmpty()) {return new PropertiesPropertySource(name, properties);}}return null;}}

2.4、准备Spring Boot的环境 prepareEnvironment相关推荐

  1. spring boot分环境导出自定义xml配置

    背景介绍: 由于新的spring boot项目需要使用老的jar包,老的jar包的配置是用xml方式配置的,而且开发development.测试test.集成off.正式production环境都会有 ...

  2. spring boot多环境配置

    spring boot多环境配置 通过多环境配置,可以实现生产环境和测试环境灵活切换. 主配置文件加载生产环境配置文件语法: spring.profiles.active=pro 注意一旦pro被激活 ...

  3. Spring Boot——不同环境调用不同的配置文件解决方案

    问题描述 我们在开发Spring Boot应用时,通常同一套程序会被应用和安装到几个不同的环境,比如:开发.测试.生产等.其中每个环境的数据库地址.服务器端口等等配置都会不同,如果在为不同环境打包时都 ...

  4. 从零搭建一个 Spring Boot 开发环境!Spring Boot+Mybatis+Swagger2 环境搭建

    从零搭建一个 Spring Boot 开发环境!Spring Boot+Mybatis+Swagger2 环境搭建 本文简介 为什么使用Spring Boot 搭建怎样一个环境 开发环境 导入快速启动 ...

  5. 学习第五篇:【SpringBoot-Labs】Spring Boot 调试环境、热部署入门、Lombok、MapStruct入门

    本周(8.21-8.27)将学习芋道 Spring Boot的以下文章: 8.21: 快速入门 8.22:Spring Boot 自动配置原理 .Jar 启动原理 8.23:调试环境. 热部署入门.消 ...

  6. 普歌-云言团队-Spring Boot入门:环境搭建Spring Boot HelloWorld

    Spring Boot入门:环境搭建Spring Boot HelloWorld 前言:SpringBoot 是来简化Spring应用开发, 约定大于配置, 去繁从简, just run就能创建一个独 ...

  7. 嗯,挺全乎儿的,Spring Boot 多环境配置都在这儿了,你喜欢哪一种呢?

    目录 前言 Spring Boot 自带的多环境配置 创建不同环境的配置文件 指定运行的环境 Maven 的多环境配置 创建多环境配置文件 定义激活的变量 pom 文件中定义 profiles 资源过 ...

  8. Linux系统CentOS 7配置Spring Boot运行环境

    从阿里云新买的一台Linux服务器,用来部署SpringBoot应用,由于之前一直使用Debian版本,环境配置有所不同,也较为繁琐,本文主要介绍CentOS下配置SpringBoot环境的过程 新建 ...

  9. Spring Boot基础学习笔记05:Spring Boot多环境配置

    文章目录 零.学习目标 1.掌握使用Profile文件进行多环境配置 2.掌握使用@Profile注解进行多环境配置 3.熟悉随机值设置以及参数间引用 一.项目进行多环境配置的必要性 二.使用Prof ...

最新文章

  1. 微服务海量日志怎么处理,推荐你试试这款工具....
  2. 基于vue2实现省市联动
  3. 【paddlepaddle速成】paddlepaddle图像分类从模型自定义到测试
  4. maven环境下使用java、scala混合开发spark应用
  5. MySQL优化(2)--------常用优化
  6. python核心编程怎么做_Python核心编程:8个实践性建议
  7. linux网卡pci信息,在进行CGKlinux系统网络配置时,使用()命令可以查询出网卡的PCI编号与设备名的对应关系。...
  8. 资深面试官解答:大厂月薪过20K的测试工程师,都需要满足哪些要求?
  9. Python打基础一定要吃透这68个内置函数
  10. 高斯分布函数c语言编程,c语言 写高斯分布函数
  11. 微信小程序社区论坛源码
  12. hadoop处理excel数据
  13. SEO外语网站批量翻译软件
  14. xshell绿色版下载-连接远程服务器-unzip使用
  15. 从fastq生成vcf文件
  16. 企业采用云计算的战略路线图
  17. 电脑端微信双开、N开
  18. (附源码)计算机毕业设计ssm个性化旅游线路推荐系统
  19. php实现手机归属地的查询、,PHP实现查询手机归属地的方法详解
  20. HTML网页版雷电游戏

热门文章

  1. 河北科技大学计算机考研率,河北科技大学研究生,河北科技大学考研率!
  2. python class def try_python 中exception,class学习
  3. php 数据映射,数据映射模式(Data Mapper)
  4. win7下ado连接mysql_提示连接无法用于执行此操作_ADODB.Recordset (0x800A0E7D)连接无法用于执行此操作。在此上下文中它可能已被关闭或无效。...
  5. html页面色块布局代码,Html 实现动态显示颜色块的报表效果(实例代码)
  6. idea ---- 快捷键
  7. mysql批量存图片_教你如何在MySQL数据库中直接储存图片(3)
  8. @Pathvariable的参数允许为空的问题的解决
  9. Tomcat与JDK版本对应关系
  10. 《好好学Java 从零基础到项目实战》姗姗而来