1. 简介
之前其实有写过Spring Bean的生命周期:Spring 容器Bean与生命周期。
当时太过于关注细节的实现,而进入了Spring庞大的体系之中,对于还不太了解Spring的朋友不太友好,也不方便记忆。
所以,这一次以应用为目的来重新梳理一下Spring核心流程。
因为对于实用主义来说,暂时并不想关心那么多Spring的细节,现在只希望能做2件事情:
- 当遇到问题了能快速知道大致那个步骤出现了问题,知道debug入口,以便于快速定位问题
- 知道一些Spring的重要扩展点,以便于更好的根据自己的需求完成自定义
2. 开始
想想我们使用Spring最常用的操作是什么?
无非就是我们添加一些xml、properties、注解配置。
然后,Spring解析这些配置帮我们创建相应的对象,并且用一个容器(上下文,BeanFactory,ApplicationContext)统一来管理。
如果,我们想要知道Spring怎样根据我们的配置,创建出我们需要的对象,那就得对Spring怎样创建上下文的流程有所了解。
所以,下面我们来简单看一下Spring创建上下文的核心流程。
注意:不要太过于关注每一个分支的细节,需要的时候再细看,否则就会没完没了的陷入一个又一个的分支细节之中。
不关心细节,只关心流程。
所以我们这里先不管是使用xml配置的ClassPathXmlApplicationContext,还是使用注解的AnnotationConfigApplicationContext,亦或是其他的Context。
我们这里只关注一个抽象类:AbstractApplicationContext,并且只关注它的refresh方法。
3. AbstractApplicationContext的refresh
这是一个典型的模板方法模式,在refresh方法中定义了各种Context的创建流程,具体怎么实现,就看个人。
1@Override 2 public void refresh() throws BeansException, IllegalStateException { 3 synchronized (this.startupShutdownMonitor) { 4 StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); 5 prepareRefresh(); 6 // 告诉子类该刷新BeanFactory了 7 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 8 prepareBeanFactory(beanFactory); 9 10 try { 11 // 告诉子类BeanFactory准备完成了 12 postProcessBeanFactory(beanFactory); 13 14 // 统计信息 15 StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); 16 // 调用BeanFactoryPostProcessor来进一步定义BeanFactory 17 invokeBeanFactoryPostProcessors(beanFactory); 18 19 // 创建注册BeanPostProcessor 20 registerBeanPostProcessors(beanFactory); 21 beanPostProcess.end(); 22 23 // 国际化设置 24 initMessageSource(); 25 26 // 初始化事件多播 27 initApplicationEventMulticaster(); 28 29 // 告诉子类可以实例化其他一些特殊Bean了 30 onRefresh(); 31 32 // 检查注册事件监听器 33 registerListeners(); 34 35 // 实例化所有剩下的非懒加载单例bean 36 finishBeanFactoryInitialization(beanFactory); 37 38 // 发布相应的事件 39 finishRefresh(); 40 } 41 42 catch (BeansException ex) { 43 if (logger.isWarnEnabled()) { 44 logger.warn("Exception encountered during context initialization - " + 45 "cancelling refresh attempt: " + ex); 46 } 47 48 // 消耗已经创建的bean 49 destroyBeans(); 50 51 // 重置 'active' 标识 52 cancelRefresh(ex); 53 throw ex; 54 } 55 finally { 56 // 重置哪些可能已经不需要的公共缓存 57 resetCommonCaches(); 58 contextRefresh.end(); 59 } 60 } 61 }
4. refresh方法说明
顺序
调用方法
说明
1
prepareRefresh
处理properties的占位符,验证上下文环境中所有的properties是否可以解析,设置早期事件监听器
2
obtainFreshBeanFacotry
获取的BeanFactory,主要是为了得到BeanDefinition这么一个玩意儿,解析创建BeanDefinition不一定发生在这一步
3
prepareBeanFactory
BeanFactory定制化工作
4
postProcessBeanFactory
BeanFactory准备好了,如果还想在对BeanFactory进行定制可以在这里完成
5
invokeBeanFactoryPostProcessors
BeanFctoryPostProcessor在这个地方被执行,可以处理一些特殊的bean,如EventListenerMethodProcessor的EventListenerFactory
6
registerBeanPostProcessors
实例化和注册BeanPostProcessor,并处理它们的执行顺序
7
initMessageSource
国际化设置
8
initApplicationEventMulticaster
初始化事件多播器
9
onRefresh
用于初始化一些特定Bean,如SpringBoot重写该方法启动Tomcat容器
10
registerListeners
检查容器中所有的事件监听器,并注册
11
finishBeanFactoryInitialization
实例化剩下所有非懒加载的单例
12
finishRefresh
发布容器刷新完成事件
13
resetCommonCaches
清除公共缓存数据
AbstractApplicationContext为prepareBeanFactory提供了默认实现,主要完成下面的工作:
-
设置类加载器
-
设置SpEL解析器和属性注册解析器
-
利用BeanPostProcessor的特性给各种Aware接口的实现类注入ApplicationContext中对应的属性
-
设置各种Aware接口的实现类为忽略自动装配
-
手动注册BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
-
探测LoadTimeWeaver,并完成动态织入
-
注册其他工具bean:ConfigurableEnvironment、系统属性、系统环境变量、ApplicationStartup(容器启动监控)
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 设置类加载器 beanFactory.setBeanClassLoader(getClassLoader()); if (!shouldIgnoreSpel) {//设置SpEL解析器 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); } // 属性注册解析器 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
1// 配置BeanFactory的回调类 2beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); 3// 配置忽略自动装配的接口 4beanFactory.ignoreDependencyInterface(EnvironmentAware.class); 5beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); 6beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); 7beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); 8beanFactory.ignoreDependencyInterface(MessageSourceAware.class); 9beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); 10beanFactory.ignoreDependencyInterface(ApplicationStartup.class); 11 12// BeanFactory中手动注册下面这些类 13beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); 14beanFactory.registerResolvableDependency(ResourceLoader.class, this); 15beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); 16beanFactory.registerResolvableDependency(ApplicationContext.class, this); 17 18// 注册一个早期的BeanPostProcessor用来探测beans是不是一个ApplicationListeners 19beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); 20 21// 探测LoadTimeWeaver,如果是准备织入 22if (!IN_NATIVE_IMAGE && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { 23 beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); 24 // 设置临时类加载器 25 beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); 26} 27 28// 注册默认的environment beans ConfigurableEnvironment 29if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { 30 beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); 31} 32// 注册系统属性bean 33if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { 34 beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); 35} 36 37//注册系统环境变量bean 38if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { 39 beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); 40} 41// 注册启动指标监测bean 42if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) { 43 beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup()); 44}}
TIPS:
- PropertySource,主要处理properties文件中的键值对和系统变量
- PropertySource会注册到上下文环境中,我们可以通过Environment这个类直接获取
- systemProperties与systemEnvironment有啥区别?就是System.getProperties()与System.getenv(),更具体就是systemProperties是user.dir这些,systemEnvironment是PATH、OS这些
5. 核心流程梳理
前面我们已经大致从代码层面简单的介绍了Spring上下文启动的流程,下面用一个图做一个简单的梳理。

6. Bean生命周期
前面在介绍Spring上下文启动的流程,我们为了尽量聚焦于核心的流程,并没有细化进入介绍和Bean生命周期的流程。
其实,对于定制化来说,我们更多的是针对Bean的定制化,你可以通过【】这篇文章了解Bean的生命周期。
当然,你也可以通过下面两个类来详细了解:
AnnotationConfigApplicationContext:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

ClassPathXmlApplicationContext:
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
