# Springboot 中BeanDefinition是在什么阶段被创建成Bean的

89 阅读3分钟

这些 BeanDefinition 到底是哪一行代码、在哪个时间点,真正变成「看得见摸得着」的 Bean 实例,并塞进 BeanFactory 的?


1. 结论

Bean 的创建(初始化)发生在
AbstractApplicationContext#refresh()
finishBeanFactoryInitialization(beanFactory)
beanFactory.preInstantiateSingletons()
AbstractBeanFactory#getBean(name)
doGetBean(...)
createBean(...)
实例化、填充、初始化、代理,最终放进 DefaultSingletonBeanRegistry 的一级缓存(singletonObjects)。


2. 全景时序图

启动主类 main()
└─ SpringApplication.run()
   └─ new AnnotationConfigApplicationContext()
      └─ refresh()  // AbstractApplicationContext
         ├─ 1. prepareRefresh()
         ├─ 2. obtainFreshBeanFactory()          // 已有 BeanDefinition,但无实例
         ├─ 3. postProcessBeanFactory()
         ├─ 4. invokeBeanFactoryPostProcessors() // 解析 @ComponentScan、@Configuration
         ├─ 5. registerBeanPostProcessors()      // 注册后置处理器
         ├─ 6. initMessageSource()
         ├─ 7. initApplicationEventMulticaster()
         ├─ 8. onRefresh()
         ├─ 9. finishBeanFactoryInitialization() // ← 今天的主角
         │   └─ beanFactory.preInstantiateSingletons()
         │       └─ getBean(beanName)            // 首次触发创建
         │           └─ doCreateBean()
         │               ├─ createBeanInstance() // 反射 or CGLIB 构造
         │               ├─ populateBean()       // 依赖注入
         │               └─ initializeBean()     //  Aware、@PostConstruct、init-method、AOP 代理
         └─ 10. finishRefresh()                  // 事件发布,启动完成

3. 关键代码逐行定位

阶段类 / 方法行号(6.x 版本)说明
入口AbstractApplicationContext#finishBeanFactoryInitialization913 行显式转换 beanFactoryDefaultListableBeanFactory
循环DefaultListableBeanFactory#preInstantiateSingletons928 行遍历所有 非抽象、单例、非懒加载 的 BeanDefinition
触发AbstractBeanFactory#getBean(beanName)211 行第一次走 getBean,才会真正 create
创建AbstractAutowireCapableBeanFactory#doCreateBean594 行实例化 + 属性赋值 + 初始化
缓存DefaultSingletonBeanRegistry#addSingleton153 行创建完后放进 ConcurrentHashMap singletonObjects

懒加载(@Lazy(true))的 Bean 不会在这一步创建,而是第一次 getBean 时才触发。


4. 源码片段速读

4.1 只关心单例、非懒加载

// DefaultListableBeanFactory#preInstantiateSingletons
for (String beanName : beanDefinitionNames) {
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        getBean(beanName);   // 就是这一行触发创建
    }
}

4.2 真正的创建逻辑

// AbstractAutowireCapableBeanFactory#doCreateBean
instanceWrapper = createBeanInstance(beanName, mbd, args); // ① 实例化
populateBean(beanName, mbd, instanceWrapper);             // ② 依赖注入
exposedObject = initializeBean(beanName, exposedObject, mbd); // ③ 初始化

4.3 初始化里干了啥?

// initializeBean 内部顺序
invokeAwareMethods(beanName, bean);          // BeanNameAware 等
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd); // @PostConstruct → InitializingBean → 自定义 init-method
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

最后一步如果开启 AOP,会在这里返回代理对象。


5. 三级缓存与循环依赖(面试高频)

Spring 为了解决 单例循环依赖,在 doCreateBean 里引入三级缓存:

缓存数据结构作用
singletonObjectsConcurrentHashMap成品 Bean
earlySingletonObjectsConcurrentHashMap早期引用(已实例化但未初始化)
singletonFactoriesConcurrentHashMap<String, ObjectFactory<?>>工厂对象,可生成代理

流程:

  1. 实例化后,先把工厂放进 singletonFactories
  2. 如果发生循环依赖,提前执行工厂拿到引用,塞进 earlySingletonObjects
  3. 初始化完成后,升级成正式 Bean,放入 singletonObjects,清理其它两级。

6. 懒加载、原型、Bean 的区分

类型何时创建
singleton + 非懒加载finishBeanFactoryInitialization() 阶段统一创建
singleton + 懒加载第一次 getBean 才创建
prototype每次 getBean 都重新 doCreateBean
request/sessionWebApplicationContext 中对应作用域第一次访问时创建

7. 调试技巧一条命令

把日志开到 DEBUG,一眼看全:

logging:
  level:
    org.springframework.beans.factory.support.DefaultListableBeanFactory: DEBUG
    org.springframework.beans.factory.support.AbstractBeanFactory: DEBUG

启动后你会看到:

Creating instance of bean 'userService'
Finished creating instance of bean 'userService'

8. 小结

  1. 注册@ComponentScan 等把类变成 BeanDefinition → Map
  2. 实例化refresh() 末尾的 preInstantiateSingletons() 统一遍历,首次 getBeandoCreateBean
  3. 三级缓存:解决循环依赖,同时支持 AOP 提前代理
  4. 懒加载 / 原型:各自在第一次使用时才走创建链路
getBean(beanName); // 没有就创建,创建完就放缓存