本文已参与「新人创作礼」活动,一起开启掘金创作之路。
11.refreshContext
refreshContext(context);方法传入的是 context 上下文。当前传入的上下文是 ConfigurableApplicationContext类型的。
进入该方法如下:
首先进入 refresh() 方法如下:
可以看到是首先判断了当前上下文是否是AbstractApplicationContext的子类/实现,然后将当前的上下文 context 转为了 AbstractApplicationContext 对象。当前传入的上下文是 ConfigurableApplicationContext 类型的。
点进 AbstractApplicationContext 的 refresh() 方法如下,可以看到几乎每一行都有注释,这里就是 refresh() 方法的核心逻辑了。
首先使用了 synchronized锁包住了这块逻辑,锁对象是private final Object startupShutdownMonitor = new Object();
1.刷新前的准备工作 prepareRefresh
进入prepareRefresh()方法,方法上的注释如下:Prepare this context for refreshing, setting its startup date and active flag as well as performing any initialization of property sources.
翻译过来就是:准备此上下文以进行刷新、设置其启动日期和活动标志以及执行任何属性源的初始化。
\
1.1 首先设置开始执行的时间和 context 上下文活动标记。
活动标记使用两个 boolean 类型的原子变量来完成,这里将 active 设置为 true,closed 设置为 false。
\
1.2 初始化占位符资源
方法上的注释 Initialize any placeholder property sources in the context environment 翻译过来就是:初始化上下文环境中的任何占位符属性源。
进入initPropertySources()方法,该方法是由子类GenericWebApplicationContext来完成的,进入 GenericWebApplicationContext 的 initPropertySources() 方法如下:
1.首先获取了当前环境,获取的是StandardServletEnvironment对象。该类的继承关系如下:
2.然后调用其initPropertySources()方法,进入该方法如下:
在方法内部调用了WebApplicationContextUtils.initServletPropertySources()方法,由名称可得知,它用于初始化 Servlet 的属性资源,在实际执行过程中分别根据 ServletContext 和 ServletConfig 的值来判定是否要将指定的配置包装为 ServletContextPropertySource 和 ServletConfigPropertySource 对象.
在实际 DEBUG 过程中,他们的值都为空,也就是没有进行任何操作。
1.3 检查必要属性是否可以被解析
方法上的注释:Validate that all properties marked as required are resolvable see ConfigurablePropertyResolver#setRequiredProperties。 翻译过来就是:验证所有标记为必需的属性都是可解析的,参见 ConfigurablePropertyResolver#setRequiredProperties。
进入getEnvironment().validateRequiredProperties();方法,这里获取的环境是 StandardServletEnvironment 对象,但是其并没有重写 validateRequiredProperties() 方法,父类 StandardEnvironment 中也没有,这里实际由父类 AbstractEnvironment 来完成。
进入AbstractEnvironment.validateRequiredProperties()方法如下:
其中 propertyResolver 是ConfigurablePropertyResolver类型的对象。
ConfigurablePropertyResolver 是个接口,这里实际由其子实现AbstractPropertyResolver来完成。
进入 AbstractPropertyResolver 的 validateRequiredProperties() 方法如下:
创建了MissingRequiredPropertiesException异常对象,然后遍历 requiredProperties 对象,找出不存在的必要属性,若有,则直接抛出异常。
实际 DEBUG 中发现 requiredProperties 是空的,所以这里并没有执行。
2.让子容器刷新内部 bean 工厂
方法上注释:Tell the subclass to refresh the internal bean factory. 翻译过来就是:告诉子类刷新内部 bean 工厂。
进入obtainFreshBeanFactory()方法如下:
内部调用了refreshBeanFactory()方法,该方法由 AbstractApplicationContext 的子类GenericApplicationContext来实现,进入子类的 refreshBeanFactory() 方法如下:
通过一个 Boolean 类型的原子变量refreshed来判断容器是否已经刷新过,如果刷新过,则报错。
然后给 beanFactory 设置serializationId属性,该值和 beanFactory 的 id 一致。
obtainFreshBeanFactory() 方法最终返回的 beanFactory 为org.springframework.beans.factory.support.DefaultListableBeanFactory.
3.准备使用在当前上下文的 beanFactory
方法上注释:Prepare the bean factory for use in this context. 翻译过来就是:准备 bean 工厂以在此上下文中使用。
进入prepareBeanFactory()方法如下:
方法上注释:Configure the factory's standard context characteristics, such as the context's ClassLoader and post-processors. 翻译过来就是:配置工厂的标准上下文特征,例如上下文的 ClassLoader 和后处理器。
1.设置类加载器
2.设置 SPEL 表达式解析器
最后设置的是:
3.属性编辑器注册
为容器设置属性编辑注册器,这个注册器注册了很多属性编辑器 PropertyEditor,用来为 bean 的成员属性做类型转换,这在配置文件时代用的较多,因为在配置文件中设置属性都是字符串,Spring需要将这些字符串转换成相应的类型,现在应该是不太常用
4.添加 ApplicationContextAwareProcessor 类型的 后置处理器,忽略指定的接口注入
添加了 bean 的后置处理器ApplicationContextAwareProcessor到 beanFactory 的beanPostProcessors属性中,在 bean 的初始化前置调用中会用到,用来为 bean 设置一些 context 相关的属性,如 applicationContext,Environment 等。
ignoreDependencyInterface()方法则是往 beanFactory 的ignoredDependencyInterfaces属性中添加需要被忽略的接口,在添加之前,已经存在3个如下:
然后又添加了6个。设置之后,在bean的属性注入阶段容器将不会为这些类的成员属性赋值,容器会在其它地方为这些类型的成员属性赋值。
5.指定对特定接口注入时实际的注入对象
容器在为bean设置以下类型的成员属性时,设置的就是第二个参数,因为这些类型的bean在容器中很可能有多个。
registerResolvableDependency()方法,则是往 beanFactory 的 Map 类型的 resolvableDependencies 属性设置值。
6.添加 ApplicationListenerDetector 类型的后置处理器
添加了 bean 的后置处理器ApplicationContextAwareProcessor到 beanFactory 的beanPostProcessors属性中,在 bean 的初始化后置调用中会用到,主要用来把用户自定义的监听器,即实现了 ApplicationListener 接口的 bean 添加到容器中。
7.如果存在loadTimeWeaver类型的 bean,则添加 LoadTimeWeaverAwareProcessor 类型的后置处理器。
LoadTimeWeaver 似乎和动态代理相关,还有个注解 @EnableLoadTimeWeaving,没用过。
8.注册默认环境 bean 对象
分别是:environment,systemProperties,systemEnvironment