: Bean 的诞生:从 getBean 到 doCreateBean 全链路)
引子面试里另一道高频题“getBean()之后Spring 到底做了什么”很多人知道Bean 会被创建但说不清从getBean到真正拿到对象之间经过了doGetBean → getSingleton → createBean → doCreateBean这条链更说不清doCreateBean内部那段经典的三段式实例化createBeanInstance→ 属性填充populateBean→ 初始化initializeBean本篇把这条全链路走通并点出提前暴露这一循环依赖的关键伏笔第 9 篇会专门拆。一句话结论getBean是门面先查缓存单例只建一次查不到才进doCreateBean内部按实例化 → 提前暴露 → 填充 → 初始化四步产出对象最后放回一级缓存。前置知识getBean是BeanFactory接口的门面方法真正逻辑在AbstractBeanFactory.doGetBean。真正的创建动作在AbstractAutowireCapableBeanFactory.doCreateBean。doCreateBean的核心三段createBeanInstancenew 出来→populateBean注入属性→initializeBean回调与代理。一、getBean 到 doCreateBean 的调用链doGetBean的精简骨架关键分支已注释// AbstractBeanFactory.doGetBeanprotectedTTdoGetBean(Stringname,ClassTrequiredType,Object[]args,booleantypeCheckOnly){StringbeanNametransformedBeanName(name);// 1. 先查一级缓存已完全初始化的成品 BeanObjectsharedInstancegetSingleton(beanName);if(sharedInstance!nullargsnull){// 处理 FactoryBean拿到的是 getObject() 结果见第 10 篇beangetObjectForBeanInstance(sharedInstance,name,beanName,null);}else{// 2. 原型 Bean 正在创建 → 说明出现循环依赖直接抛异常if(isPrototypeCurrentlyInCreation(beanName)){thrownewBeanCurrentlyInCreationException(beanName);}// 3. 父类容器存在则委托 parent层级容器// ... parentBeanFactory.getBean(...)// 4. 单例调用 getSingleton 模板内部触发 createBeanif(mbd.isSingleton()){sharedInstancegetSingleton(beanName,()-createBean(beanName,mbd,args));beangetObjectForBeanInstance(sharedInstance,name,beanName,mbd);}// 5. 原型 / 其他作用域分支略}return(T)bean;}getSingleton(beanName, singletonFactory)这个模板方法是单例只建一次 循环依赖提前暴露的总开关publicObjectgetSingleton(StringbeanName,ObjectFactory?singletonFactory){synchronized(this.singletonObjects){ObjectsingletonObjectthis.singletonObjects.get(beanName);// 再加锁查一次if(singletonObjectnull){beforeSingletonCreation(beanName);// 标记正在创建singletonsCurrentlyInCreationtry{singletonObjectsingletonFactory.getObject();// ← 实际调用 createBean}finally{afterSingletonCreation(beanName);// 取消正在创建标记}addSingleton(beanName,singletonObject);// 放入一级缓存清二三级}returnsingletonObject;}}⚠️注意getSingleton的正在创建标记singletonsCurrentlyInCreation正是循环依赖能被识别的基础——B 要 A 时发现 A 已在创建中就走提前暴露分支而不是再 new 一个 A。二、doCreateBean 的三段式含提前暴露// AbstractAutowireCapableBeanFactory.doCreateBean精简protectedObjectdoCreateBean(StringbeanName,RootBeanDefinitionmbd,Object[]args){// 1. 实例化反射 / 工厂方法 new 出裸对象BeanWrapperinstanceWrappercreateBeanInstance(beanName,mbd,args);ObjectbeaninstanceWrapper.getWrappedInstance();// 2. 提前暴露解决循环依赖把工厂放进三级缓存booleanearlySingletonExposure(mbd.isSingleton()this.allowCircularReferencesisSingletonCurrentlyInCreation(beanName));if(earlySingletonExposure){addSingletonFactory(beanName,()-getEarlyBeanReference(beanName,mbd,bean));}// 3. 属性填充Autowired / XML property 在此populateBean(beanName,mbd,instanceWrapper);// 4. 初始化Aware → BPP 前置 → init → BPP 后置/AOPObjectexposedObjectinitializeBean(beanName,exposedObject,mbd);// 5. 循环依赖校验若早期引用与最终对象不一致如被代理且无依赖真正用到早期引用则抛异常returnexposedObject;}步骤方法干了什么关键扩展点① 实例化createBeanInstance推断构造器反射 new 实例SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors② 提前暴露addSingletonFactory把() - getEarlyBeanReference放进三级缓存仅单例且允许循环依赖③ 属性填充populateBean注入依赖AutowiredAnnotationBeanPostProcessor第 8 篇④ 初始化initializeBean回调与代理Aware/BeanPostProcessor/InitializingBean⑤ 校验末尾判断早期引用 vs 最终对象一致性不一致且无依赖使用则报错三、三段各自展开3.1 createBeanInstance对象怎么 new 出来若mbd指定了工厂方法factory-method走instantiateUsingFactoryMethod。否则推断构造器SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors决定用哪个构造器构造器注入在此解析见第 8 篇。用BeanUtils.instantiateClass(constructor, args)反射创建——最常见的是无参构造。3.2 populateBean属性从哪来protectedvoidpopulateBean(StringbeanName,RootBeanDefinitionmbd,BeanWrapperbw){// 1. InstantiationAwareBeanPostProcessor 后处理Autowired 在此触发for(InstantiationAwareBeanPostProcessorbp:getBeanPostProcessors()){PropertyValuespvsbp.postProcessProperties(pvs,bw.getWrappedInstance(),beanName);}// 2. 应用 XML 配置的 property 值applyPropertyValues(beanName,mbd,bw,pvs);}关键记忆点Autowired/Resource注入发生在populateBean即属性填充阶段不是initializeBean。这是第 8 篇的主角。3.3 initializeBean回调与代理的四阶段protectedObjectinitializeBean(StringbeanName,Objectbean,RootBeanDefinitionmbd){invokeAwareMethods(beanName,bean);// ① Aware 回调wrappedBeanapplyBeanPostProcessorsBeforeInitialization(...);// ② BPP 前置PostConstructinvokeInitMethods(beanName,wrappedBean,mbd);// ③ InitializingBean init-methodwrappedBeanapplyBeanPostProcessorsAfterInitialization(...);// ④ BPP 后置AOP 代理在此生成returnwrappedBean;}① 只回调BeanNameAware/BeanFactoryAware/BeanClassLoaderAware见第 7 篇。④ 若存在 AOP 自动代理创建器postProcessAfterInitialization会返回代理对象——你最终拿到的 Bean 可能已不是原始对象。四、流程图五、常见误区误区正解getBean一定创建新对象先查一级缓存单例只建一次提前暴露 提前初始化完成只暴露刚 new 出来的半成品AOP 代理在initializeBean才生成实例化好就立刻可被别人用需经populateBeaninitializeBean但循环依赖时靠三级缓存提前拿到半成品引用构造器注入的循环依赖能解不能——构造器在createBeanInstance阶段就要求依赖就绪而那时还没进三级缓存第 9 篇六、面试题自测从getBean到doCreateBean的完整调用链是什么doCreateBean的三段式实例化/填充/初始化各自对应哪个方法提前暴露发生在哪一步它的作用是什么initializeBean的四个阶段按什么顺序执行为什么构造器注入的循环依赖无法被 Spring 解决七、Debug 小技巧在第 2 篇的调试工程里在AbstractAutowireCapableBeanFactory.doCreateBean第一行打断电观察instanceWrapper出来后bean是裸对象未经填充/代理。在initializeBean前后分别打印bean的getClass().getName()若有 AOP会发现返回的是$$EnhancerBySpringCGLIB$$代理类证明代理在 ④ 阶段生成。在getSingleton的singletonFactory.getObject()处Step Into直接进createBean→doCreateBean看清模板方法触发创建的机制。下篇预告第 7 篇我们把initializeBean里那条生命周期完整展开实例化 → 属性填充 → 初始化 → 销毁把 Aware /PostConstruct/InitializingBean/ 销毁回调的顺序与源码一次性讲透。如果这篇对你有帮助欢迎点赞 · 收藏 · 关注三连支持。Spring 源码系列共 30 篇由浅入深持续更新中。有疑问或想深挖的源码点评论区告诉我下篇见。