SpringBoot启动之refreshContext

SpringBoot启动之refreshContext

这篇主要要通过refreshContext方法来将SpringBoot是如何初始化ioc容器的。

refreshContext

SpringBoot中的run方法中,调用refreshContext()方法,进而调用 AbstractApplicationContext类中的refresh()方法。然后分析每个方法的代码,来看这些方法的作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备此上下文以进行刷新,设置其启动日期
// 并且设置 active 标志以及执行属性源(系统属性、环境变量)的任何初始化。
prepareRefresh();
// 告诉子类刷新 bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 为上下文准备 bean factory.
prepareBeanFactory(beanFactory);

// 接下来的方法就是装载组件的方法
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 使用beanFactory在上下文中注册bean
invokeBeanFactoryPostProcessors(beanFactory);
// 注册bean的拦截器
registerBeanPostProcessors(beanFactory);
// 加载国际化
initMessageSource();
// 初始化上下文的事件广播
initApplicationEventMulticaster();
// 加载特殊的bean
onRefresh();
// 加载所有的listeners并启动
registerListeners();
// 完成对所有的剩下的非懒加载的单例的创建
finishBeanFactoryInitialization(beanFactory);
// 最后发布对应的事件。
finishRefresh();
}
}
}

prepareRefresh 准备刷新方法

这个方法的作用就是为了接下来的refresh进行的准备。主要的有两个过程

  1. 调用initPropertySources()方法进行propertySource的初始化。
  2. 验证有没有缺失的必要的Property属性。

initPropertySources 初始化propertySource

调用实现类的initPropertySources,根据debug的结果,进入到了子类GenericWebApplication类中,对servletContex进行属性设置。如下图中所展示的。

图1

obtainFreshBeanFactory 获得beanFactory

该方法依靠refreshBeanFactory()来只是bean工厂的实际刷新。因为SpringBoot在ApplicationContext已经持有一个类型为DefaultListableBeanFactory类型的beanFactory。所以可以直接返回。

prepareBeanFactory准备BeanFactory

配置BeanFactory的标准上下文特征。主要体现在一下几个方面:

  1. 设置classLoader和bean名称的解析策略等。
  2. 设置以Aware结尾的callback接口函数。通过对这些接口的实现。来达到对环境设置的目的。如可继承ResourceLoaderAware接口,来设置资源加载器,来实现自定义的资源加载。
  3. 使用特定的自动装配值注册特殊依赖关系类型。如beanFactory.registerResolvableDependency(ApplicationContext.class, this);
  4. 设置环境相关的bean.如beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());

postProcessBeanFactory

允许在上下文子类中对bean进行后处理。调用相关方法完成对beanFactory的后置处理其的加载。
在之后的invokeBeanFactoryPostProcessors实例化并调用所有已注册的BeanFactoryPostProcessor bean。在方法registerBeanPostProcessors中实例化并注册所有BeanPostProcessor bean。

initMessageSource 初始化MessageSource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected void initMessageSource() {
// 先获得bean工厂
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果存在bean名称为messageSource的bean
// 也就是国际化的Message
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
// 获得messageSource
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
//。。。这里省略
}
}

在debug时的结果,因为SpringBoot默认实现类Message,所以容器会加载SpringBoot配置好的国际化配置文件。如图中的basenameSet;
图2

onRefresh

在这一步,SpringBoot会根据应用类型来判断,如果是web应用,则会启动默认的web容器,如tomcat。
它回去找所有的类型为ServletWebServerFactory的类。然后获取第一个getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);进行bean注入。这样通过注入的bean就能够启动web容器了。

图3

SpringBoot中默认实现有以上几种。

registerListeners 注册listeners

在这一步,注册类型为ApplicationListener的所有listeners;

finishBeanFactoryInitialization 完成所有非懒加载的bean的初始化

finishRefresh 完成刷新

这步有以下几个操作。

  1. clearResourceCaches方法。 清空context-level的缓存。
  2. initLifecycleProcessor方法,用来设置生命周期processer
  3. 发布最后的事件(ContextRefreshedEvent

以上就完成了refresh方法中的所有操作。

-------------本文结束感谢您的阅读-------------

本文标题:SpringBoot启动之refreshContext

文章作者:NanYin

发布时间:2019年08月05日 - 12:08

最后更新:2019年08月12日 - 23:08

原始链接:https://nanyiniu.github.io/2019/08/05/SpringBoot%E5%90%AF%E5%8A%A8%E4%B9%8BrefreshContext/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。