前言
前面介绍了 Spring 容器的概念,其核心可归纳为两个类: BeanFactory 和 ApplicationContext,ApplicationContext 继承自 BeanFactory ,其不仅包含 BeanFactory 所有功能,还扩展了容器功能。之后介绍了在 SSM 时期和 SpringBoot 时期如何启动 ApplicationContext 。在结尾处,我们指出,ApplicationContext 核心其实是 refresh 方法,容器一系列功能都在该方法中实现,如:注册 Bean、注入 Bean 等。
在 refresh 方法中,实现容器核心功能前,先进行了一系列环境准备工作,我们以 SpringBoot 为当前运行环境,深入讨论这部分内容。
注:本篇文章使用的 SpringBoot 版本为 2.0.3.RELEASE,其 Spring 版本为 5.0.7.RELEASE
正文
refresh 方法定义在 ConfigurableApplicationContext 接口中,被 AbstractApplicationContext 抽象类实现,该方法由十几个子方法组成,这些子方法各司其职,但部分子方法被 AbstractApplicationContext 的子类进行扩展,来增强功能。其中,前四个子方法主要进行上下文准备工作。
第一步:prepareRefresh
我们先从 refresh 中的 prepareRefresh 方法开始讨论:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 初始化上下文环境,就是记录下容器的启动时间、活动状态等
prepareRefresh();
...
}
}
该方法被继承 AbstractApplicationContext 抽象类的子类进行扩展,扩展该方法的子类有:
image
因本次演示的环境是 SpringBoot ,前面我们讲过,SpringBoot 会根据当前 Web 应用类型创建不同的上下文对象 ,如 Servlet Web、Reactive Web 等。这里演示的是 Servlet Web 应用,所以创建的上下文对象是 AnnotationConfigServletWebServerApplicationContext 。该类的 prepareRefresh 方法会被执行:
public class AnnotationConfigServletWebServerApplicationContext
extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
...
@Override
protected void prepareRefresh() {
// 清除 Class 的元数据缓存。底层用 Map 保存元数据,执行 Map 的 clear 方法
this.scanner.clearCache();
// 调用父类,也就是 AbstractApplicationContext 的 prepareRefresh 方法
super.prepareRefresh();
}
...
}
public abstract class AbstractApplicationContext {
...
private long startupDate;
private final AtomicBoolean active = new AtomicBoolean();
private final AtomicBoolean closed = new AtomicBoolean();
private Set earlyApplicationEvents;
...
protected void p