Spring源码:Bean的生命周期

Spring源码:Bean的生命周期

文件目录结构

文件树、UserService实现类、启动类如下:

image-20250405231638188

image-20250405231652955

image-20250405231705800

源码解析

在AnnotationConfigApplicationContext中:

主要的Bean注册逻辑在refresh()函数中

image-20250405231922340

进入到refresh()之后看到一系列的方法调用,秉着刨根问底和点到为止的原则。。。先把他们的作用给列出来,如果以后涉及到可以有个印象:

image-20250405232701519

  • this.postProcessBeanFactory(beanFactory):该方法是 AbstractApplicationContext 提供的一个模板方法(Template Method),子类(如 AbstractRefreshableWebApplicationContext 或自定义的 ApplicationContext)可以重写它来自定义 BeanFactory 的后处理逻辑,比如注册额外的属性编辑器、添加某些特定的 BeanPostProcessor 等。

  • this.invokeBeanFactoryPostProcessors(beanFactory):执行所有实现了 BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor 接口的 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,并将其添加到事件广播器中。这让你可以监听如 ContextRefreshedEventContextClosedEvent 等容器事件。

  • this.finishBeanFactoryInitialization(beanFactory)

    完成剩余的 singleton Bean 的实例化,包括:

    • 创建所有非懒加载的单例 Bean
    • 初始化 conversionService
    • 初始化 loadTimeWeaver
    • 注册所有 BeanPostProcessor
    • 初始化 ApplicationContextAware 等特殊接口
  • this.finishRefresh():容器刷新最后一步,包括:

    • 清理资源缓存
    • 初始化 LifecycleProcessor 并调用 onRefresh()
    • 发布 ContextRefreshedEvent 事件通知监听器
    • 注册 JVM shutdown 钩子(如果设置了)

方法:finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory)

代码总览如下,方便进行费曼学习法。

image-20250405233928588

设置类型转换器(500~502)

如果用户定义了名为 "conversionService" 的 Bean,并且是 ConversionService 类型,则设置为 BeanFactory 的全局类型转换器。用于属性注入、SpEL 表达式、@Value、配置绑定(比如 Spring Boot 配置文件 -> Bean 属性)等。

添加占位符解析器(如 ${...}) (504~508)

添加用于解析字符串中的 ${} 占位符的处理器。实现原理是:当 Bean 的字段、注解参数等地方写了 "${xxx}",就可以解析成配置中的值。

比如:

1
2
@Value("${server.port}")
private int port;

提前初始化 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

image-20250405234714162

image-20250405234733040


我们将一些循环代码块缩小,先看看他们的循环条件是什么:

image-20250405235541071


循环体中主要的那一块代码主要是在所有非懒加载的单例 Bean 实例化完成后,统一执行所有实现了 SmartInitializingSingleton 的 Bean 的回调。在所有非懒加载的单例 Bean 实例化完成后,统一执行所有实现了 SmartInitializingSingleton 的 Bean 的回调。到时候有需要我们再回过头来看看。

image-20250406000117586


image-20250406000330417

如果是 FactoryBean,先获取它本身的实例。否则直接实例化普通 Bean。&beanName 是 Spring 中用来获取 FactoryBean 本身的方式(而不是它生产的对象)。

getBean(beanName) 是创建 Bean 的关键步骤,会触发依赖注入、初始化、AOP 包装等。所以后面的关键代码为getBean()方法

总结一下流程图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
for (beanName in allBeanNames) {
bd = getBeanDefinition(beanName)

if (bd is abstract || !singleton || lazy-init) continue;

if (isFactoryBean(beanName)) {
factory = getBean("&" + beanName)
if (factory is SmartFactoryBean && isEagerInit) {
getBean(beanName)
}
} else {
getBean(beanName)
}
}

// 第二轮,SmartInitializingSingleton 回调
for (beanName in allBeanNames) {
instance = getSingleton(beanName)
if (instance instanceof SmartInitializingSingleton) {
instance.afterSingletonsInstantiated()
}
}

方法:getBean()、doGetBean()

image-20250406000916277

if中的逻辑

先来看看这几行

image-20250406002809960

129行,尝试从 一级缓存 获取已经创建的单例对象。如果非空,说明这个 Bean 已经被创建过,可以直接返回。getSingleton()就是三级缓存实现的主要逻辑。


image-20250406003146557

如果这个 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 实例
  • 异常处理和埋点记录

image-20250406004052168

这段代码的意思是如果当前正在创建一个原型作用域的 Bean,则抛出 BeanCurrentlyInCreationException 异常。

为什么原型 Bean 不支持循环依赖?

  • 原型作用域的 Bean 每次请求都会创建一个新的实例,而单例 Bean 是在容器初始化时就被创建并缓存起来的。

  • 原型 Bean 在创建过程中并不会缓存自己,因此 Spring 不允许原型 Bean 之间出现相互依赖的情况。如果原型 Bean 正在创建过程中再次被请求,Spring 会认为这是一个循环依赖(类似于递归调用),因此抛出异常。


image-20250406004239131

这一段就是通过父类的容器去加载bean,通过判断参数调用不同的重载方法。


image-20250406004400052

这段代码的作用是 标记一个 Bean 为已创建,但只有在 typeCheckOnlyfalse 时才执行。只有在真正需要创建 Bean 时,typeCheckOnlyfalse,这时 Spring 才会标记 Bean 为已创建,表示该 Bean 正在构建过程中,并且避免多个地方同时尝试创建这个 Bean,避免不必要的资源浪费或循环依赖的出现。


image-20250406005618447

这段代码的作用是检查当前 Bean 是否有 depends-on 依赖。检查这些依赖是否已经在当前 Bean 创建过程中被处理,防止循环依赖。确保所有依赖的 Bean 都已创建并且有效。如果缺少依赖的 Bean,抛出异常。


image-20250406005746057

这里应该就是很关键的单例bean的创建代码了,主要关注的是createBean()这个方法。可以看到getSingleton()方法的参数,第二个使用匿名表达式去写了一个创建工厂:

image-20250406005924929


image-20250406010120709

如果是原型方法,就多了两个前后处理:

beforePrototypeCreation() 这个方法在创建 prototype 类型的 Bean 之前,管理和记录正在创建的 prototype Bean 名称。如果有多个 prototype Bean 正在创建,它会使用 Set 存储它们的名字,从而确保在整个创建过程中的依赖关系能够被正确处理。

afterPrototypeCreation() 也就是从before的set中把我们创建好的bean的名称给删除掉。

方法:createBean()

这是一个抽象方法。里面包含了一个静态内部类,该类的目的是缓存与 Bean 后处理器相关的实例。不同类型的后处理器会对 Bean 的创建和销毁过程起作用。通过缓存这些后处理器,可以提高性能并简化后续的处理。

image-20250406010719246

方法:populateBean()

image-20250406213409813

914:!mbd.isSynthetic():不是“合成”的 Bean,合成 Bean 是 Spring 自己内部创建的,比如 @Configuration 中的增强类,通常跳过扩展处理。

hasInstantiationAwareBeanPostProcessors():是否注册了实现了该接口的后处理器。

919:如果任意一个后处理器返回 false则直接中断属性注入过程(即 populateBean() 提前 return,不会进入后续的依赖注入流程)。也就是说,你可以通过这个方法 “拦截并跳过”后续的依赖注入


image-20250406213828610

如果这个 Bean 的定义中开启了自动注入(byName 或 byType),Spring 就会根据 Bean 的名字或类型把需要的依赖注入进去,并更新最终使用的属性值 pvs


image-20250406212045351

在执行 属性注入(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() 会直接退出。


image-20250406213146631

前面已经走过了 BeanPostProcessor 的属性扩展(postProcessProperties 等)

接下来进行:

  • 依赖检查(dependency-check)
  • 实际属性注入(applyPropertyValues)

如果 Bean 定义中设置了 dependency-check="all"(或对象、简单类型等),则需要检查所有需要注入的属性是否都有值。filterPropertyDescriptorsForDependencyCheck:从当前 Bean 的属性中筛选出那些“需要检查”的字段,比如 setXxx(...) 存在但没有配置依赖的。

真正的属性赋值 applyPropertyValues。把 PropertyValues 中的属性值(可能包括配置文件中写的、BeanPostProcessor 动态添加的)应用到目标 Bean 的实例中。会做以下处理:

  • 类型转换
  • 依赖解析
  • 反射调用 setter 方法,把值注入到属性中。