Spring IOC - Spring启动过程解析

Spring启动流程的核心逻辑主要体现在方法AbstractApplicationContext#refresh中,该方法没有被子类重写。

本文主要从宏观层面对其进行剖析,从整体上感知。各执行步骤和作用按先后顺序如下表所示,其中标红方法为核心方法,标绿色方法提供了扩展点。

|----------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 方法名 | 主要作用 |
| prepareRefresh() | 记录容器启动时间、设置容器状态;提供扩展点用于自定义添加key-value属性 |
| obtainFreshBeanFactory() | 获取一个新鲜的beanFactory实例,该方法由两个子类实现: 1.GenericApplicationContext:很简单,返回无参构造方法创建的beanFactory 2.AbstractRefreshableApplicationContext:关闭当前beanFactory,创建新的beanFactory,体现了刷新的含义 |
| prepareBeanFactory(beanFactory) | 提前给beanFactory塞入bean实例:如BeanFactory,ResourceLoader等,以及设置类加载器、属性编辑器等 |
| postProcessBeanFactory(beanFactory) | 此处是Spring留的扩展点,目的是在beanFactory准备好后,留给用户最后对beanFactory做一些设置 如对于Web应用,重写后给beanFactory塞入ServletContext等单例bean |
| invokeBeanFactoryPostProcessors(beanFactory) | 调用BeanFactoryPostProcessor的实现类对BeanFactory进行后置处理,如调用ConfigurationClassPostProcessor对常用注解进行解析,生成BeanDefinition |
| registerBeanPostProcessors(beanFactory) | 注册Bean的后置处理器,包括系统内置的和自定义的,如:AutowireAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor |
| initMessageSource() | 初始化MessageSource,用于支持国际化 |
| initApplicationEventMulticaster() | 初始化事件派发器,用于支持事件监听 |
| onRefresh() | Spring提供的扩展点,留给子类实现 |
| registerListeners() | 注册事件监听器 |
| finishBeanFactoryInitialization(beanFactory) | 实例化所有非懒加载的单例Bean,Spring Bean的生命周期就是从这里开始的 |
| finishRefresh() | 完成刷新,发布容器刷新完成事件等 |

源码及注释如下:

java 复制代码
	// Spring应用上下文的核心方法,它负责完成Spring容器的初始化和刷新工作
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			// 准备刷新操作,包括记录容器启动时间、设置容器状态、获取属性、验证必要的属性
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 获取一个新鲜的BeanFactory实例,该方法由子类实现
			// 获取新的beanFactory,销毁原有beanFactory、为每个bean生成BeanDefinition等,注意,此处是获取新的,销毁旧的,这就是刷新的意义
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// 对BeanFactory进行一些设置,例如设置类加载器、添加属性编辑器等
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 允许子类在BeanFactory标准初始化完成后对其进行进一步的处理
				// 此处是spring留的扩展点,目前是在beanFactory准备好后,留给用户最后对beanFactory做一些设置
				// 可参考GenericWebApplicationContext#postProcessBeanFactory实现
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// 调用BeanFactoryPostProcessor的实现类对BeanFactory进行后置处理
				// 扫描解析的核心代码
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 注册BeanPostProcessor的实现类,用于在Bean创建过程中进行拦截
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				// 初始化MessageSource,用于支持国际化
				initMessageSource();

				// Initialize event multicaster for this context.
				// 初始化事件派发器,用于支持事件监听
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 留给子类实现,用于在容器刷新时进行特殊的处理
				onRefresh();

				// Check for listener beans and register them.
				// 注册事件监听器
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 实例化所有非懒加载的单例Bean
				// 这一步可谓和我们开发者打交道最多,我们自定义的Bean绝大多都是在这一步被初始化的,包括依赖注入等等
				// 因此了解这一步,能让我们更深入的了解Spring是怎么管理我们的Bean的生命周期,以及依赖关系的
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// 完成刷新操作,包括发布容器刷新完成事件等
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				// 如果在刷新过程中出现异常,会执行该方法取消操作,并销毁已经创建的单例Bean,最后,会重置Spring核心中的一些缓存
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}
相关推荐
东风破_4 分钟前
大前端手里的 Next.js:从 #root 到 SEO,一份 HTML 的两种命运
前端·后端
IT_陈寒12 分钟前
Vue的v-for不听话?我被这个Key的坑整懵了
前端·人工智能·后端
2601_9638699518 分钟前
【计算机毕业设计】基于Java的相框定制系统的设计与实现
java·开发语言·课程设计
众人皆醒我独醉35 分钟前
训练加速实战:Flash Attention、Gradient Checkpointing 与数据流水线
后端·面试·gpu
阿黎梨梨40 分钟前
Next.js 全栈开发:从 SPA 的痛点到 SSR 的破局之道
前端·后端
名字还没想好☜1 小时前
Go 的 unsafe.Pointer 实战:零拷贝 []byte↔string 转换与三条铁律
开发语言·后端·golang·go·unsafe
老孙讲技术1 小时前
周末档期厨房爆单,带宽账单也爆了——不是直播难,是主码流 + always 计划在烧钱
后端·物联网
于烛1 小时前
为什么hasNext() 对只有一个元素的集合返回 true?90%初学者都有的疑问
java
老孙讲技术1 小时前
校园开放日前夜才说要「全校透明」?我用轻应用把 9 路教室预览和回放嵌进了校园后台
后端·物联网
wuminyu1 小时前
JVM利用io_uring优化堆外内存性能原理剖析
java·linux·c语言·jvm·c++