2.4、准备Spring Boot的环境 prepareEnvironment
源码:
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 是个接口,主要作用是提供当前运行环境的公开接口,其中 StandardServletEnviroment
和 StandardEnvironment
都是其实现类,类图如下:
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相关推荐
- spring boot分环境导出自定义xml配置
背景介绍: 由于新的spring boot项目需要使用老的jar包,老的jar包的配置是用xml方式配置的,而且开发development.测试test.集成off.正式production环境都会有 ...
- spring boot多环境配置
spring boot多环境配置 通过多环境配置,可以实现生产环境和测试环境灵活切换. 主配置文件加载生产环境配置文件语法: spring.profiles.active=pro 注意一旦pro被激活 ...
- Spring Boot——不同环境调用不同的配置文件解决方案
问题描述 我们在开发Spring Boot应用时,通常同一套程序会被应用和安装到几个不同的环境,比如:开发.测试.生产等.其中每个环境的数据库地址.服务器端口等等配置都会不同,如果在为不同环境打包时都 ...
- 从零搭建一个 Spring Boot 开发环境!Spring Boot+Mybatis+Swagger2 环境搭建
从零搭建一个 Spring Boot 开发环境!Spring Boot+Mybatis+Swagger2 环境搭建 本文简介 为什么使用Spring Boot 搭建怎样一个环境 开发环境 导入快速启动 ...
- 学习第五篇:【SpringBoot-Labs】Spring Boot 调试环境、热部署入门、Lombok、MapStruct入门
本周(8.21-8.27)将学习芋道 Spring Boot的以下文章: 8.21: 快速入门 8.22:Spring Boot 自动配置原理 .Jar 启动原理 8.23:调试环境. 热部署入门.消 ...
- 普歌-云言团队-Spring Boot入门:环境搭建Spring Boot HelloWorld
Spring Boot入门:环境搭建Spring Boot HelloWorld 前言:SpringBoot 是来简化Spring应用开发, 约定大于配置, 去繁从简, just run就能创建一个独 ...
- 嗯,挺全乎儿的,Spring Boot 多环境配置都在这儿了,你喜欢哪一种呢?
目录 前言 Spring Boot 自带的多环境配置 创建不同环境的配置文件 指定运行的环境 Maven 的多环境配置 创建多环境配置文件 定义激活的变量 pom 文件中定义 profiles 资源过 ...
- Linux系统CentOS 7配置Spring Boot运行环境
从阿里云新买的一台Linux服务器,用来部署SpringBoot应用,由于之前一直使用Debian版本,环境配置有所不同,也较为繁琐,本文主要介绍CentOS下配置SpringBoot环境的过程 新建 ...
- Spring Boot基础学习笔记05:Spring Boot多环境配置
文章目录 零.学习目标 1.掌握使用Profile文件进行多环境配置 2.掌握使用@Profile注解进行多环境配置 3.熟悉随机值设置以及参数间引用 一.项目进行多环境配置的必要性 二.使用Prof ...
最新文章
- 微服务海量日志怎么处理,推荐你试试这款工具....
- 基于vue2实现省市联动
- 【paddlepaddle速成】paddlepaddle图像分类从模型自定义到测试
- maven环境下使用java、scala混合开发spark应用
- MySQL优化(2)--------常用优化
- python核心编程怎么做_Python核心编程:8个实践性建议
- linux网卡pci信息,在进行CGKlinux系统网络配置时,使用()命令可以查询出网卡的PCI编号与设备名的对应关系。...
- 资深面试官解答:大厂月薪过20K的测试工程师,都需要满足哪些要求?
- Python打基础一定要吃透这68个内置函数
- 高斯分布函数c语言编程,c语言 写高斯分布函数
- 微信小程序社区论坛源码
- hadoop处理excel数据
- SEO外语网站批量翻译软件
- xshell绿色版下载-连接远程服务器-unzip使用
- 从fastq生成vcf文件
- 企业采用云计算的战略路线图
- 电脑端微信双开、N开
- (附源码)计算机毕业设计ssm个性化旅游线路推荐系统
- php实现手机归属地的查询、,PHP实现查询手机归属地的方法详解
- HTML网页版雷电游戏
热门文章
- 河北科技大学计算机考研率,河北科技大学研究生,河北科技大学考研率!
- python class def try_python 中exception,class学习
- php 数据映射,数据映射模式(Data Mapper)
- win7下ado连接mysql_提示连接无法用于执行此操作_ADODB.Recordset (0x800A0E7D)连接无法用于执行此操作。在此上下文中它可能已被关闭或无效。...
- html页面色块布局代码,Html 实现动态显示颜色块的报表效果(实例代码)
- idea ---- 快捷键
- mysql批量存图片_教你如何在MySQL数据库中直接储存图片(3)
- @Pathvariable的参数允许为空的问题的解决
- Tomcat与JDK版本对应关系
- 《好好学Java 从零基础到项目实战》姗姗而来