Spring源码:Bean的生命周期

Spring源码:Bean的生命周期
JohnnySpring源码:Bean的生命周期
文件目录结构
文件树、UserService实现类、启动类如下:
源码解析
在AnnotationConfigApplicationContext中:
主要的Bean注册逻辑在refresh()
函数中
进入到refresh()
之后看到一系列的方法调用,秉着刨根问底和点到为止的原则。。。先把他们的作用给列出来,如果以后涉及到可以有个印象:
this.postProcessBeanFactory(beanFactory)
:该方法是AbstractApplicationContext
提供的一个模板方法(Template Method
),子类(如AbstractRefreshableWebApplicationContext
或自定义的ApplicationContext
)可以重写它来自定义BeanFactory
的后处理逻辑,比如注册额外的属性编辑器、添加某些特定的BeanPostProcessor
等。this.invokeBeanFactoryPostProcessors(beanFactory)
:执行所有实现了BeanFactoryPostProcessor
和BeanDefinitionRegistryPostProcessor
接口的 Bean,这些接口允许在 Bean 定义被加载后、Bean 实例化前,修改 Bean 的定义信息,例如:替换属性值、修改依赖关系、注册额外的BeanDefinition
。其中很常见的例子就是 Spring Boot 自动配置用到的ConfigurationClassPostProcessor
。this.registerBeanPostProcessors(beanFactory)
:注册所有实现了BeanPostProcessor
接口的 Bean 到 BeanFactory 中。这些处理器会在 Bean 实例化前后被调用,是 AOP、事务、依赖注入等功能的核心机制。例如:AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
this.initMessageSource()
:初始化消息资源(国际化),如果用户没有定义messageSource
Bean,Spring 会创建一个默认的DelegatingMessageSource
。用于支持MessageSource.getMessage()
的国际化功能。this.initApplicationEventMulticaster()
:初始化事件广播器(ApplicationEventMulticaster
),用于应用内事件发布(publishEvent()
)与监听器之间解耦的核心组件。如果用户没有定义,Spring 会默认注册一个SimpleApplicationEventMulticaster
。this.onRefresh()
:一个扩展钩子方法,供子类在容器刷新过程中执行额外逻辑。在WebApplicationContext
中,这里会创建DispatcherServlet
的相关上下文。一般我们自己不实现这个方法,除非做底层框架扩展。this.registerListeners()
:注册所有实现了ApplicationListener
接口的 Bean,并将其添加到事件广播器中。这让你可以监听如ContextRefreshedEvent
、ContextClosedEvent
等容器事件。this.finishBeanFactoryInitialization(beanFactory)
:完成剩余的
singleton
Bean 的实例化,包括:- 创建所有非懒加载的单例 Bean
- 初始化
conversionService
- 初始化
loadTimeWeaver
- 注册所有
BeanPostProcessor
- 初始化
ApplicationContextAware
等特殊接口
this.finishRefresh()
:容器刷新最后一步,包括:- 清理资源缓存
- 初始化
LifecycleProcessor
并调用onRefresh()
- 发布
ContextRefreshedEvent
事件通知监听器 - 注册 JVM shutdown 钩子(如果设置了)
方法:finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory)
代码总览如下,方便进行费曼学习法。
设置类型转换器(500~502)
如果用户定义了名为 "conversionService"
的 Bean,并且是 ConversionService
类型,则设置为 BeanFactory 的全局类型转换器。用于属性注入、SpEL 表达式、@Value
、配置绑定(比如 Spring Boot 配置文件 -> Bean 属性)等。
添加占位符解析器(如 ${...}
) (504~508)
添加用于解析字符串中的 ${}
占位符的处理器。实现原理是:当 Bean 的字段、注解参数等地方写了 "${xxx}"
,就可以解析成配置中的值。
比如:
1 |
|
提前初始化 LoadTimeWeaverAware 的 Bean (510~517)
获取所有实现了 LoadTimeWeaverAware
的 Bean,并立刻初始化它们。这个接口是为了支持 JVM 的类加载期间织入,比如AspectJ 的 LTW。
清空临时类加载器(519)、冻结 Bean 定义防止修改(520)
- 清除临时 ClassLoader(用来做类型检查的)释放内存,提高性能。
- 标记所有的 BeanDefinition 都已加载完毕,不允许再注册或修改。
(关键)实例化所有非懒加载的单例 Bean(521)
实例化所有非懒加载(lazy-init = false
)的 singleton Bean。包括依赖注入、生命周期回调(如 InitializingBean
, @PostConstruct
),应用所有的 BeanPostProcessor
。如果有循环依赖,也会在这一步暴露 early singleton。这是真正“创建所有 Bean”的过程,是整个 Spring IOC 启动最核心的一步。
方法:preInstantiateSingletons()
这个方法完成了容器启动中实例化所有非懒加载的单例 Bean的过程,是 IOC 容器真正“构造出所有 Bean” 的阶段。这一部分代码比较长,而且很多while写死的循环有点难以理解。
这部分的作用主要有遍历所有注册的 BeanDefinition,找出:
- 非抽象的
- 单例的
- 非懒加载的 的 Bean,调用
getBean()
强制实例化它们。
此外,还会特别处理:
FactoryBean
SmartInitializingSingleton
我们将一些循环代码块缩小,先看看他们的循环条件是什么:
循环体中主要的那一块代码主要是在所有非懒加载的单例 Bean 实例化完成后,统一执行所有实现了 SmartInitializingSingleton
的 Bean 的回调。在所有非懒加载的单例 Bean 实例化完成后,统一执行所有实现了 SmartInitializingSingleton
的 Bean 的回调。到时候有需要我们再回过头来看看。
如果是 FactoryBean,先获取它本身的实例。否则直接实例化普通 Bean。&beanName
是 Spring 中用来获取 FactoryBean 本身的方式(而不是它生产的对象)。
getBean(beanName)
是创建 Bean 的关键步骤,会触发依赖注入、初始化、AOP 包装等。所以后面的关键代码为getBean()
方法
总结一下流程图
1 | for (beanName in allBeanNames) { |
方法:getBean()、doGetBean()
if中的逻辑
先来看看这几行
在129行
,尝试从 一级缓存 获取已经创建的单例对象。如果非空,说明这个 Bean 已经被创建过,可以直接返回。getSingleton()
就是三级缓存实现的主要逻辑。
如果这个 Bean 是单例,并且不是带参数创建的,那就直接返回缓存中已有的对象。sharedInstance != null
说明在调用 getSingleton(beanName)
时,已经在缓存中拿到了这个单例对象。可能是完全初始化的 Bean,也可能是为了解决循环依赖,提前暴露的引用即未 fully initialized
beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
这一行的工作是拿到你真正想要的 Bean 对象,而不是工厂本身:
- 如果
sharedInstance
是一个普通对象,直接返回; - 如果是一个
FactoryBean
,就调用它的getObject()
方法返回真正的实例; - 如果你调用
getBean("&myFactoryBean")
,就返回FactoryBean
本身。
else中的逻辑
再看看else中的逻辑,这个逻辑可分为五步:
- 处理原型 Bean 的循环依赖异常
- 找不到本地 BeanDefinition 时,尝试去父容器寻找
- 记录 Bean 开始创建(用于后续生命周期管理)
- 正式进入 Bean 创建流程
- 合并 BeanDefinition
- 检查依赖 Bean,提前实例化 depends-on 指定的 Bean
- 按作用域创建 Bean 实例
- 异常处理和埋点记录
这段代码的意思是如果当前正在创建一个原型作用域的 Bean,则抛出 BeanCurrentlyInCreationException
异常。
为什么原型 Bean 不支持循环依赖?
原型作用域的 Bean 每次请求都会创建一个新的实例,而单例 Bean 是在容器初始化时就被创建并缓存起来的。
原型 Bean 在创建过程中并不会缓存自己,因此 Spring 不允许原型 Bean 之间出现相互依赖的情况。如果原型 Bean 正在创建过程中再次被请求,Spring 会认为这是一个循环依赖(类似于递归调用),因此抛出异常。
这一段就是通过父类的容器去加载bean,通过判断参数调用不同的重载方法。
这段代码的作用是 标记一个 Bean 为已创建,但只有在 typeCheckOnly
为 false
时才执行。只有在真正需要创建 Bean 时,typeCheckOnly
为 false
,这时 Spring 才会标记 Bean 为已创建,表示该 Bean 正在构建过程中,并且避免多个地方同时尝试创建这个 Bean,避免不必要的资源浪费或循环依赖的出现。
这段代码的作用是检查当前 Bean 是否有 depends-on
依赖。检查这些依赖是否已经在当前 Bean 创建过程中被处理,防止循环依赖。确保所有依赖的 Bean 都已创建并且有效。如果缺少依赖的 Bean,抛出异常。
这里应该就是很关键的单例bean的创建代码了,主要关注的是createBean()
这个方法。可以看到getSingleton()
方法的参数,第二个使用匿名表达式去写了一个创建工厂:
如果是原型方法,就多了两个前后处理:
beforePrototypeCreation()
这个方法在创建 prototype
类型的 Bean 之前,管理和记录正在创建的 prototype
Bean 名称。如果有多个 prototype
Bean 正在创建,它会使用 Set
存储它们的名字,从而确保在整个创建过程中的依赖关系能够被正确处理。
afterPrototypeCreation()
也就是从before的set中把我们创建好的bean的名称给删除掉。
方法:createBean()
这是一个抽象方法。里面包含了一个静态内部类,该类的目的是缓存与 Bean 后处理器相关的实例。不同类型的后处理器会对 Bean 的创建和销毁过程起作用。通过缓存这些后处理器,可以提高性能并简化后续的处理。
方法:populateBean()
914:!mbd.isSynthetic()
:不是“合成”的 Bean,合成 Bean 是 Spring 自己内部创建的,比如 @Configuration
中的增强类,通常跳过扩展处理。
hasInstantiationAwareBeanPostProcessors()
:是否注册了实现了该接口的后处理器。
919:如果任意一个后处理器返回 false,则直接中断属性注入过程(即 populateBean()
提前 return,不会进入后续的依赖注入流程)。也就是说,你可以通过这个方法 “拦截并跳过”后续的依赖注入。
如果这个 Bean 的定义中开启了自动注入(byName 或 byType),Spring 就会根据 Bean 的名字或类型把需要的依赖注入进去,并更新最终使用的属性值 pvs
。
在执行 属性注入(applyPropertyValues) 之前,Spring 给了 InstantiationAwareBeanPostProcessor
一个机会去:
- 修改即将注入的属性值
- 甚至阻止属性注入
前三行的作用分别为
检查当前是否有
InstantiationAwareBeanPostProcessor
,如果没有就不走这段逻辑。needsDepCheck
标识是否需要依赖检查(dependency-check),Spring XML 中有对应配置。filteredPds
用于缓存属性描述符。
945:如果当前没有属性值 pvs
,就从 bean 定义中取出配置好的属性。(945)
949:遍历所有已缓存的 InstantiationAwareBeanPostProcessor
实例。(949)
951:用来修改、增强或完全替换即将注入的属性值。如果你用的是 @Autowired
注入依赖,AutowiredAnnotationBeanPostProcessor
就会在这里做依赖注入。
952:如果 postProcessProperties()
返回 null
,Spring 会回退调用 过时但兼容的旧扩展点。旧方法 postProcessPropertyValues(...)
是 Spring 早期版本使用的,允许开发者控制属性值、进行依赖注入等。如果该方法也返回 null
,表示放弃后续属性赋值,整个 populateBean()
会直接退出。
前面已经走过了 BeanPostProcessor 的属性扩展(postProcessProperties
等)
接下来进行:
- 依赖检查(dependency-check)
- 实际属性注入(applyPropertyValues)
如果 Bean 定义中设置了 dependency-check="all"
(或对象、简单类型等),则需要检查所有需要注入的属性是否都有值。filterPropertyDescriptorsForDependencyCheck
:从当前 Bean 的属性中筛选出那些“需要检查”的字段,比如 setXxx(...)
存在但没有配置依赖的。
真正的属性赋值 applyPropertyValues
。把 PropertyValues
中的属性值(可能包括配置文件中写的、BeanPostProcessor 动态添加的)应用到目标 Bean 的实例中。会做以下处理:
- 类型转换
- 依赖解析
- 反射调用 setter 方法,把值注入到属性中。