前置了解
Environment
本身是一个PropertyResolver
,但是提供了Profile特性,即可以根据环境得到相应数据(即激活不同的Profile,可以得到不同的属性数据,用于多环境场景的配置。我们分析Spring Boot的启动流程,以创建StandardServletEnvironment
为例:
PropertySource
属性源,key-value属性对抽象,比如用于配置数据。
PropertyResolver
属性解析器,用于解析相应key的value。
Profile
剖面,只有激活的剖面的组件/配置才会注册到Spring容器
Context
上下文,这个上下文由多种数据结构组成,可以提供我们运行时需要的一些数据和保存运行时的一些数据,context 可以理解对一个程序运行时所需要的一些数据结构的抽象表达。
Spring Boot的启动流程中申明创建了ConfigurableApplicationContext
(实际的类型为AnnotationConfigServletWebServerApplicationContext
)
组成
- environment:所属
AbstractApplicationContext
,是将上一步的prepareEnvironment()中的environment赋值给Context中变量。
主流程
我将SpringApplication#run()
主流程分为#getRunListeners
、#prepareEnvironment
、#prepareContext
、#refreshContext
、#afterRefresh
这5部分,本篇讲解的Spring加载配置,与Environment和Context两个类关联紧密,主要讲解#prepareEnvironment
、#prepareContext
1. #getRunListeners
获取EventPublishingRunListener
,该Listener对象内包含成员变量SimpleApplicationEventMulticaster
,用于广播后续流程中的事件。
2. #prepareEnvironment
#prepareEnvironment
方法内分为#getOrCreateEnvironment
、#configureEnvironment
、listeners#environmentPrepared
3个部分。
2.1 #getOrCreateEnvironment
根据webApplicationType
生成环境类new StandardServletEnvironment()
。在构造方法中会封装成员变量propertySources
和propertyResolver
。封装的propertySources
为systemEnvironment�、systemProperties�、servletConfigInitParams、servletContextInitParams
2.2 #configureEnvironment
封装环境信息分为
configurePropertySources
,添加、删除、重排PropertySource
configureProfiles
,配置activeProfiles
2.3 listeners#environmentPrepared
EventPublishingRunListener
通过initialMulticaster
�发布ApplicationEnvironmentPreparedEvent
事件,然后通过event和eventType获取监听的listeners,listener基于同步的方式处理事件,此处是ConfigFileApplicationListener
处理该事件。ConfigFileApplicationListener
中包含数个EnvironmentPostProcessor
环境准备完的后置处理。3. #prepareContext
3.1 context.setEnvironment(environment)
将createApplicationContext()创建的context的变量environment赋值。�3.2 postProcessApplicationContext(context)
� 后置处理ApplicationContext,设置context的类型转换ConversionService,context.getBeanFactory().setConversionService(xxx)
,
�
�
其他细节
监听器部分使用了观察者模式,回调的实现是在ApplicationEventMulticaster在广播时候(调用multicastEvent
�方法)�中实现的,以子类SimpleApplicationEventMulticaster
为例,最终调用#doInvokeListener
代码如下:
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
�
参考
【1】:https://zhuanlan.zhihu.com/p/48030077
【2】:https://www.cnblogs.com/yourbatman/p/14061177.html
【3】:https://blog.csdn.net/dkyaoyao/article/details/84819519