一、介绍
在[上一篇文章:springboot创建并配置环境1 - 创建环境
](https://developer.aliyun.com/article/1462605)中我们探讨了springboot是如何根据当前应用程序类型去创建对应的环境实例的。接下来探讨如何去配置完善该运行环境。
本文基于以下版本进行展开:
- jdk:1.8
- springboot:2.4.3
另外:由于篇幅过长,决定分四集文章来讲解分析
[二、配置基础环境]()
下面我们以标准环境StandardEnvironment
为例进行分析。
二、配置系统属性和环境变量
首先我们应该判断在创建一个运行环境实例对象时,在构造器内部是否就已经开始对某些配置属性进行处理了。
在创建运行环境实例时,是通过标准环境StandardEnvironment
的无参构造方法完成的,进入该构造方法后发现它是一个空方法
由于该类继承于AbstractEnvironment
,那么在执行StandardEnvironment
的构造方法时会默认先调用父类的无参构造方法,接下来再看父类的无参构造。
在该无参构造中,先实例化一个MutablePropertySources
对象,然后再调用了下面的有参构造方法,并对propertySources
和propertyResolver
这两个属性进行初始化。
- MutablePropertySources
该类内部维护了一个
PropertySource
集合,该集合中保存着大量以key,value
形式的属性配置,且value
值可以是任何数据类型。mutable意为可变的,表示允许调用方去修改其内部的属性配置。如下图所示
看到PropertiySource
大家是否还有印象,我们在springboot从命令行读取应用程序参数这篇文章中有介绍过,它其实就是一个以key,value
形式的属性配置对象,且value
值可以是任何数据类型(用泛型T表示)。
- propertySources
该属性指向
MutablePropertySources
对象。 - propertyResolver
属性解析器,提供一些从propertySources中获取所需要的属性的方法。
该运行环境实例的两个重要属性初始化完成后,该实例就具备了利用属性解析器propertyResolver
解析配置属性并将解析后的结果保存到propertySources
中的功能了。
接下来我们再看customizePropertySources()
方法做了什么?从命名上来看,它可以自定义地添加一些属性,查看该方法是一个空方法
那么我们再回到它的子类StandardEnvironment
查看该方法实现。
在该方法中,我们可以看到,通过调用MutablePropertySources
的addLast()
方法,向其内部的PropertySource
集合尾部添加两种属性:PropertiesPropertySource
和SystemEnvironmentPropertySource
。
这两个类都是PropertiySource
抽象类的实现类,用于保存不同类型的属性,但他们本质上都是PropertiySource
实例。其中
- PropertiesPropertySource
该类用于保存系统属性,其中key为systemProperties,value为Map集合,该集合中保存所有系统属性。
- SystemEnvironmentPropertySource
该类用于保存系统环境变量,其中key为systemEnvironment,value为Map集合,该集合中保存所有系统环境变量。
另外,PropertiySource
还有很多种不同的实现类,用于保存不同类型的属性,如下所示
下面我们用图示将当前已经保存的属性、以及目前运行环境保存属性的结构表示出来
好了,说了这么多我会不会是在瞎说,我们测一下就好了,把断点打在创建标准环境StandardEnvironment
实例的下一行,查看此时运行环境中的属性
- 系统属性
从调试中我们看到,springboot找到了64个系统属性
- 系统环境变量
从调试中我们看到,springboot找到了65个系统环境变量
三、配置自定义属性命令行参数
自定义属性主要是来自命令行参数。在前面的文章springboot读取命令行参数中我们已经详细介绍过springboot是如何读取命令行参数并将其保存在ApplicationArguments
对象中的,但这些来自命令行的参数目前并不能作为启动环境信息、,需要将其也保存到启动环境中。
我们继续读prepareEnvironment()
方法源码,来到configureEnvironment()
这一行,
进入configureEnvironment()
方法,该方法的逻辑主要分三部分,其中第一部分设置类型转换器
该方法的处理逻辑主要分三部分
- 设置类型转换器
该部分逻辑只是向环境中设置一些springboot内置的类型转换器Convertor,本篇文章不具体展开来讲。
配置自定义的普通参数
- 首先将默认属性配置添加到
MutablePropertySources
的尾部默认属性配置的设置方法是通过
SpringApplication
对象的setDefaultProperties()
方法设置的,如下所示 - 配置命令行参数
在前面的文章springboot读取命令行参数我们已经详细介绍过springboot如何将命令行参数转为
SimpleCommandLinePropertySource
,本文就不再赘述。在这一步会先判断我们已经保存的属性配置中是否已经存在
key=commandLineArgs
了,从我们逐行阅读源码的过程中我们可以断定是不存在这样的属性的,因此会执行else代码块,即只需要将SimpleCommandLinePropertySource
添加到已经保存的属性配置的首部即可。此时我们再次用图示将当前已经保存的属性、以及目前运行环境保存属性的结构表示出来
- 首先将默认属性配置添加到
当然了,如果你想拒绝任何来自命令行的属性参数,可以通过以下方法将`addCommandLineProperties`属性设置为`false`,这样springboo就不会把命令行参数保存到启动环境中了
![关闭命令行参数功能.png](https://ucc.alicdn.com/pic/developer-ecology/een7m2naevh4a_16e76d38a560490c870332b9c03e53d9.png)
- 配置来自命令行的profile
该方法为空方法,保留该方法方面日后扩展。
四、作为应用配置信息
在处理完自定义的属性后,下一步springboot需要对当前启动环境中的属性配置适配ConfigurationPropertySources
的支持,如下图所示
进入attach()
方法,如下所示
该方法执行后的结果就是将当前启动环境中已保存的属性配置source
封装到一个ConfigurationPropertySourcesPropertySource
对象中,并且对应的key=configurationProperties
,此时启动环境中保存的属性配置如下所示
至于为什么这么做,我们可以看一下方法注释:
Attach a ConfigurationPropertySource support to the specified Environment. Adapts each PropertySource managed by the environment to a ConfigurationPropertySource and allows classic PropertySourcesPropertyResolver calls to resolve using configuration property names.
The attached resolver will dynamically track any additions or removals from the underlying Environment property sources.
从注释中得知,该方法的目的就是真正的把当前保存在启动环境中的这些propertySources
作为配置属性,就是说这些属性在此之前springboot并没有把他们作为配置来看,如今它们成为了配置属性
纸上得来终觉浅,绝知此事要躬行。
————————我是万万岁,我们下期再见————————