SpringBoot 系列:(二)Spring 容器是如何构建的

本贴最后更新于 1858 天前,其中的信息可能已经时移俗易

在上一篇文章《SpringBoot 系列:(一)SpringBoot 启动过程》 的章节“执行 ConfigurableApplicationContext 对象的 refresh 方法 ”中,我们一句话跳过了对 ConfigurableApplicationContext 的 refresh 方法的解析,未做深入的解读。而在执行 refresh 方法之前,SpringApplication 帮我们做了一些准备工作;在执行 refresh 方法之后,整个容器已经构建成功可以被正常使用了。那么,这个 refresh 方法到底内部进行了何种处理?这即是本文需要探讨的问题。

以下,我将以 AnnotationConfigApplicationContext 为示例,分析其 refresh 方法是如何来构建 BeanFactory 的。

总体流程

下图展示的是 AnnotationConfigApplicationContext 的继承关系。跟踪其 refresh 方法,最终追溯到 AbstractApplicationContext 类的 refresh 方法上。
image.png

从 AbstractApplicationContext 类的 refresh 方法,我们大致整理出如下的容器构建流程:

  • 准备工作
  • 生成一个 BeanFactory 实例
  • 调整 BeanFactory
  • 触发 BeanFactoryPostProcessor
  • 注册 BeanPostProcessor
  • 其他动作
    • 初始化 MessageSource
    • 初始化事件广播器
    • onRefresh 回调
    • 注册事件监听器
  • 初始化 Singleton bean
  • 后续处理
从AbstractApplicationContext类的refresh方法代码
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 准备工作,记录容器启动时间、标记启动状态、处理配置文件中的占位符
		prepareRefresh();
		// 获取一个beanFactory
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		// 对beanFactory做进一步调整,如设置类加载器等
		prepareBeanFactory(beanFactory);
		try {
			// 钩子方法,开放给AbstractApplicationContext的子类实现
			postProcessBeanFactory(beanFactory);
			// 调用所有的BeanFactoryPostProcessor的postProcessBeanFactory方法
			invokeBeanFactoryPostProcessors(beanFactory);
			// 注册BeanPostProcessor
			registerBeanPostProcessors(beanFactory);
			// 初始化MessageSource,用于国际化
			initMessageSource();
			// 初始化事件广播器
			initApplicationEventMulticaster();
			// 钩子方法,开放给AbstractApplicationContext的子类实现
			onRefresh();
			// 注册事件监听器
			registerListeners();
			// 初始化所有的非lazy的singleton bean【重点】
			finishBeanFactoryInitialization(beanFactory);
			// 一些后续处理动作,如广播ContextRefreshedEvent事件
			finishRefresh();
		}catch (BeansException ex) {
			//代码省略
		}finally {
			resetCommonCaches();
		}
	}
}

各流程探究

下面,我们将就上述的各流程,深入到代码中,查看每一个流程究竟干了哪些事情。

准备工作

这里的准备工作,主要是指 AbstractApplicationContext 的 prepareRefresh 方法

	protected void prepareRefresh() {
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);
		//省略日志输出
		initPropertySources();
		getEnvironment().validateRequiredProperties();
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

从代码不难看出 ,准备工作包括记录启动时间、标记启动状态、处理配置文件中的占位符、验证配置文件。其中,处理配置文件中的占位符 (initPropertySources)是一个回调方法,AbstractApplicationContext 本身不提供具体实现。

生成一个 BeanFactory 实例

AbstractApplicationContext类
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	refreshBeanFactory();
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	//省略日志输出
	return beanFactory;
}

AbstractApplicationContext 类的 refreshBeanFactory 和 getBeanFactory 方法,都由其子类 GenericApplicationContext 实现

GenericApplicationContext类
protected final void refreshBeanFactory() throws IllegalStateException {
	// 代码省略
	this.beanFactory.setSerializationId(getId());
}

public final ConfigurableListableBeanFactory getBeanFactory() {
	return this.beanFactory;
}

通过代码可知,GenericApplicationContext 的 beanFactory 是一个 DefaultListableBeanFactory 实例。后续所有 bean 的管理,都是委托给该 beanFactory 进行的。因此,本质上 AnnotationConfigApplicationContext 是以一种组合的方式来实现容器的功能,而非用继承的方式。

对于非 SpringBoot 工程,比如,使用 ClassPathXmlApplicationContext 构建容器时,AbstractApplicationContext 的子类 AbstractRefreshableApplicationContext 会实现 refreshBeanFactory 方法:在生成一个 DefaultListableBeanFactory 实例后,会用该实例去加载类路径下的 xml 文件,从而维护一个 beanName 到 beanDefinition 的 map。此时,beanDefinition 中记录的是 bean 的配置信息,bean 对象还未生成。

回到主流程上,对于 AnnotationConfigApplicationContext 而言,通过 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(),AbstractApplicationContext 获取到的 beanFactory 是一个 DefaultListableBeanFactory 实例。

调整 BeanFactory

调整 BeanFactory,包含了 AbstractApplicationContext 类本身对于 beanFactory 的调整(AbstractApplicationContext 的 prepareBeanFactory 方法),以及 AbstractApplicationContext 的子类对于 beanFactory 的调整。

触发 BeanFactoryPostProcessor

通过 PostProcessorRegistrationDelegate 的 invokeBeanFactoryPostProcessors 方法来触发 BeanFactoryPostProcessor 的 postProcessBeanFactory。这里,我们需要区分一下 BeanFactoryPostProcessor 以及后续马上就要遇到的 BeanPostProcessor。

BeanFactoryPostProcessor 是用来处理、修改 bean 定义信息的后置处理器,这个时候 bean 还没有初始化,只是定好了 BeanDefinition。BeanFactory 创建时,在 BeanFactoryPostProcessor 接口的 postProcessBeanFactory 方法中,我们可以修改 bean 的定义信息,例如修改属性的值,修改 bean 的 scope 为单例或者多例。

而 BeanPostProcessor 则用于 bean 初始化前后对 bean 做一些操作,即 bean 的构造方法调用后(大前提,bean 实例已经生成了),在 bean 的初始化方法调用前和 bean 的初始化方法调用后,可以通过 BeanPostProcessor 对 bean 做一些修改。

一个 bean 的生命周期如下图所示:
image.png

public interface BeanFactoryPostProcessor {
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

public interface BeanPostProcessor {
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

这里需要注意,在调用 AnnotationConfigApplicationContext 的构造方法时,在其内部生成了一个 AnnotatedBeanDefinitionReader。在 AnnotatedBeanDefinitionReader 的生成过程中,会向 beanFactory 注册一个 ConfigurationClassPostProcessor。

ConfigurationClassPostProcessor 是一个 BeanFactoryPostProcessor,用于解析处理各种注解,包括:@Configuration、@ComponentScan、@Import、@PropertySource、@ImportResource、@Bean。SpringBoot 的自动配置也是通过 ConfigurationClassPostProcessor 来完成。

注册 BeanPostProcessor

AbstractApplicationContext 通过 PostProcessorRegistrationDelegate.registerBeanPostProcessors 来注册 BeanPostProcessor

其他动作

这里说的其他动作,包含初始化 MessageSource、初始化事件广播器、执行子类的 onRefresh 回调和注册事件监听器。由于不是我们关注的主要内容,因此不展开详细说明。

初始化 Singleton bean

AbstractApplicationContext 类
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// ... 省略很多代码

	// Instantiate all remaining (non-lazy-init) singletons.
	beanFactory.preInstantiateSingletons();
}

根据前面的分析,这里的 beanFactory 是一个 DefaultListableBeanFactory 类实例。

DefaultListableBeanFactory类
public void preInstantiateSingletons() throws BeansException {
	//省略很多代码
	for (String beanName : beanNames) {
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			if (isFactoryBean(beanName)) {
				...
			}
			else {
				getBean(beanName);
			}
		}
	}
}

getBean(beanName) 最终调用AbstractBeanFactory
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,  
 @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
	//... 省略很多代码
	if (mbd.isSingleton()) {
		sharedInstance = getSingleton(beanName, () -> {
			try {
				return createBean(beanName, mbd, args);
			}catch (BeansException ex) {
				destroySingleton(beanName);
				throw ex;
			}
			});
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}
}
AbstractAutowireCapableBeanFactory类  

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
	//... 省略很多代码
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
	//... 省略很多代码
}


protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
	//... 省略很多代码
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		//创建一个BeanWrapper
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
		
	Object exposedObject = bean;
	try {
		//属性装配。前面只是实例化了,但是各个字段还没有值
		populateBean(beanName, mbd, instanceWrapper);
		// 各种ware、init-method、BeanPostProcessor等都是在这里处理的
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	return exposedObject;
}



protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	if (System.getSecurityManager() != null) {
		...
	}
	else {// 注入各种ware
		invokeAwareMethods(beanName, bean);
	}

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
		//调用BeanPostProcessors的postProcessBeforeInitialization
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	//调用init方法  
 	invokeInitMethods(beanName, wrappedBean, mbd);
	if (mbd == null || !mbd.isSynthetic()) {
		//调用BeanPostProcessors的postProcessInitialiAfterzation
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}
	return wrappedBean;
}

至此,一个 BeanFactory 构造完毕并能被正常使用了。

  • 后续处理
    最后,广播事件,ApplicationContext 初始化完成等。非重点,跳过不分析。

总结

我们以 AnnotationConfigApplicationContext 为例,分析了 BeanFactory 的构建过程。

在文中曾提及,使用 ClassPathXmlApplicationContext 构建容器时,生成 DefaultListableBeanFactory 实例后,该实例会去加载类路径下的 xml 文件,从而维护一个 beanName 到 beanDefinition 的 map。后续则是基于这些 beanDefinition 来实例化所有的 no-lazy singleton bean 的。

但从前面的分析中可以看出,SpringBoot 启动主流程并没有主动去维护类似的 beanName 到 beanDefinition 的 map。那么,SpringBoot 实例化各种 bean 的时候,对应的 BeanDefinition 是从哪来的呢?在后续的文章中我们将就这点展开讨论。

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    944 引用 • 1459 回帖 • 17 关注
  • refresh
    1 引用

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...