文章目录
- 一、介绍
- 二、启动环境Environment的分析
- 三、进入源码
- 四、创建环境
- 1. 如何确定应用类型
- 2. 测试
 
一、介绍
在springboot的启动流程中,启动环境Environment是可以说是除了应用上下文ApplicationContext之外最重要的一个组件了,而且启动环境为应用上下文提供了最基本的前提基础。
在启动环境中,主要保存大量配置信息和当前操作系统的配置信息以及环境变量。
对于它的重要性,我们可以这样理解:启动环境为创建应用上下文提供了基础支持,而应用上下文为我们开发springboot项目提供了基础支持。
本文基于以下版本进行展开:
- jdk:1.8
- springboot:2.4.3
另外:由于篇幅过长,决定分四集文章来讲解分析
一、springboot创建并配置环境(一) - 创建环境
二、springboot创建并配置环境(二) - 配置基础环境
三、springboot创建并配置环境(三) - 配置扩展属性(上集)
四、springboot创建并配置环境(四) - 配置扩展属性(下集)
二、启动环境Environment的分析
老规矩,在了解一个类之前,我们需要先通过其UML图对该类的功能有一个大致的了解,下面是启动环境Environment的UML图:

-  PropertyResolver:顾名思义为属性解析器,提供用来解析并保存形如 key=value这样的属性。
-  Environment:在 PropertyResolver的基础上添加了对profile的支持,其实profile也是形如key=value的属性配置,只是为了更清晰就把它做成独立的api了。
-  ConfigurablePropertyResolver:可配置的属性解析器。在 PropertyResolver的基础上添加了类型转换器ConversionService。
-  ConfigurableEnvironment:可配置的环境,即启动环境。本片文章主要就是围绕它来展开的。它对 Environment做出了扩展,允许动态设置profile。并对其内部保存的属性集合进行分类,如:操作系统的属性、操作系统的环境变量。
-  ConfigurableWebEnvironment:在 ConfigurableEnvironment的基础上添加了对servlet类型的web环境的支持。
-  ConfigurableReactiveWebEnvironment:在 ConfigurableEnvironment的基础上添加了对响应式类型的web环境的支持。
从上图中不难看出,springboot为我们提供了三种启动环境
- StandardEnvironment:标准环境。提供基本的springboot启动环境。
- StandardServletEnvironment:servlet类型的web环境。在标准环境的基础上,添加了对servlet类型的web环境的环境处理。
- StandardReactiveWebEnvironment:响应式类型的web环境。在标准环境的基础上,添加了对响应式类型的web环境的环境处理。
三、进入源码
在springboot启动流程的源码中,我们不难发现,启动环境的创建和配置是在一个prepareEnvironment()方法中完成的,如下所示:

进入该方法查看其实现逻辑:

本文主要围绕prepareEnvironment()方法探讨springboot是如何创建运行环境并对其进行配置的。
下面进入正题。
四、创建环境
在prepareEnvironment()方法中,getOrCreateEnvironment()方法负责实例化环境对象,并将创建好的环境返回。所以我们需要进入该方法:

该方法很简单,就是根据当前应用类型去实例化对应的环境对象:
- 如果是servlet类型的web环境,则实例化一个StandardServletEnvironment对象
- 如果是响应式类型的web环境,则实例化一个StandardReactiveWebEnvironment对象
- 如果以上两种web环境都不是,则默认实例化一个标准环境对象StandardEnvironment。
但是,springboot是如何知道我们当前应用是哪一种类型呢?即webAppliicationType是如何确定的?
1. 如何确定应用类型
当我们在springboot的主启动类中使用SpringApplicaton.run()启动项目时,其内部其实是先创建一个SpringApplicaton实例,然后对该实例调用其run()方法,如下图所示

在创建SpringApplicaton实例时,该构造方法内部确定当前应用程序类型并将该类型保存到webApplicationType属性中,如下图所示

从该行代码可以看出,springboot通过调用WebApplicationType的静态方法deduceFromClasspath(),推断出当前应用程序类型。
我们再进入该静态方法来了解它是如何推断的

从该方法中看到,推断过程无非就是从类路径中判断是否存在指定的类
- 如果类路径中存在servlet相关的类,那么当前应用程序就是servlet类型的应用程序
- 如果类路径中仅存在reactive相关的类,那么当前应用程序就是响应式类型的应用程序
- 如果以上两种类都不存在,那么当前应用程序就什么类型的应用程序都不是了。
判断类路径中判断是否存在指定的类只需要调用ClassUtils的静态方法isPresent()就行了。而在该静态方法中,则是通过对传入的类进行反射去实例化,如果实例化失败并抛出了异常,则说明该类是不存在的。
2. 测试
-  既不存在reactive相关的类,也不存在servlet相关的类 在pom中我们仅仅引入springboot的依赖  然后启动项目进入断点,查看当前应用程序的类型,确定为NONE类型的应用程序  
-  仅存在reactive相关的类 在pom中我们引入springboot的依赖 和 reactive相关的依赖  然后启动项目进入断点,查看当前应用程序的类型,确定为响应式类型的应用程序  
-  存在servlet相关的类 在pom中我们引入springboot的依赖 和 servlet相关的依赖  然后启动项目进入断点,查看当前应用程序的类型,确定为servlet类型的应用程序  
点此进入下一集:springboot创建并配置环境(二) - 配置基础环境
纸上得来终觉浅,绝知此事要躬行。
————————我是万万岁,我们下期再见————————



















