尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Spring 源码系列(6): 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 篇由浅入深持续更新中。有疑问或想深挖的源码点评论区告诉我下篇见。
RELATED

相关推荐

如何高效使用FAST-LIVO2:从零开始的多传感器融合SLAM实战指南

如何高效使用FAST-LIVO2:从零开始的多传感器融合SLAM实战指南

如何高效使用FAST-LIVO2:从零开始的多传感器融合SLAM实战指南 【免费下载链接】FAST-LIVO2 FAST-LIVO2: Fast, Direct LiDAR-Inertial-Visual Odometry 项目地址: https://gitcode.com/gh_mirrors/fa/FAST-LIVO2 FAST-LIVO2是一个高效且精确的LiDAR-惯性-视觉…

📅 2026/9/10 0:27:27
开源NestJS实战:企业级TypeScript后端开发终极指南

开源NestJS实战:企业级TypeScript后端开发终极指南

开源NestJS实战:企业级TypeScript后端开发终极指南 【免费下载链接】awesome-nest-boilerplate Awesome NestJS Boilerplate 😍, Typescript 💪, Postgres 🎉, TypeORM 🥳 项目地址: https://gitcode.com/gh_mirrors…

📅 2026/8/21 16:51:18
如何用Ruflo构建AI代理协作系统:从零开始的完整指南

如何用Ruflo构建AI代理协作系统:从零开始的完整指南

如何用Ruflo构建AI代理协作系统:从零开始的完整指南 【免费下载链接】ruflo 🌊 The leading agent meta-harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive …

📅 2026/8/21 16:51:19
MORE NEWS

更多资讯

📰

微信小程序贪吃蛇源码详解:从状态机到渲染实战

简介:一份基于微信小程序开发的贪吃蛇游戏完整源代码,面向微信小程序初学者、前端开发者以及对休闲游戏实现感兴趣的学习者,用来理解小程序项目结构、游戏循环与常见交互设计。资源包共22个文件,压缩后约414KB,主要包含…

📰

Astryx 主题规范(Theme Specifications):主题包决策的知识契约与 Neutral 实战解析

Astryx 主题规范(Theme Specifications):主题包决策的知识契约与 Neutral 实战解析 【免费下载链接】astryx An open source design system thats fully customizable and agent ready 项目地址: https://gitcode.com/GitHub_Trending/as/a…

📰

AI SDK:TypeScript 多 Provider 接入与 Agent 集成要点

const result await generateText({model: anthropic/claude-opus-4.6,prompt: Hello!, });import { anthropic } from ai-sdk/anthropic;const result await generateText({model: anthropic(claude-opus-4-6),prompt: Hello!, });这两段代码在 AI SDK 的 README 中并列出现…

📰

如何用camofox-browser批量提取页面所有链接和图片:完整教程

如何用camofox-browser批量提取页面所有链接和图片:完整教程 【免费下载链接】camofox-browser Stealth headless browser for AI agents — bypass Cloudflare, bot detection, and anti-scraping. Drop-in Puppeteer/Playwright replacement. 项目地址: https:/…

📰

基于 Plasmo 构建 SurfSense 跨浏览器扩展:浏览历史采集插件的开发、构建与发布全指南

基于 Plasmo 构建 SurfSense 跨浏览器扩展:浏览历史采集插件的开发、构建与发布全指南 【免费下载链接】SurfSense Open-source NotebookLM alternative. Research the open web with live data(Reddit, YT, IG, TikTok, Indeed, Google Search, Maps etc) through …

📰

上位机与安川PLC通讯:MEMOBUS协议解析及C#调用VB.net控件实战

简介:这套上位机与安川PLC通讯控件及C#使用实例源码,由工控老马出品并亲测校正,主要面向工业自动化领域需要借助C#或VB.NET实现上位机与安川PLC通讯的开发者,既能帮助新手快速上手控件调用,也能为有经验的工程师提供可…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬