「Java高级技能提升系列」第05篇(全20篇)· 面向2026年中高级Java岗面试 · 专栏持续更新,欢迎关注
Spring容器机制:Bean生命周期与三级缓存全解
场景引入
一句话结论:Spring循环依赖面试题是筛分候选人深度的试金石,80%的人只能答表面。
"某跨境电商一面面试官:Spring怎么解决循环依赖?Bean从创建到销毁经历什么?"
这道题看似基础,却是我在面试中用来筛分候选人的"照妖镜"。请先诚实地问问自己,你现在能回答到哪一层:
- 基础层:知道三级缓存存在,能说个大概流程
- 进阶层:清楚三级缓存各自的职责和设计原因
- 专家层:能结合AOP代理场景解释为什么需要三级缓存,知道构造器注入无法解决循环依赖
说实话,我见过太多候选人止步于基础层。根据我多年的面试经验,这道题的通过率很低,主要原因在于大家只停留在背概念,无法深入到源码实现和实际生产场景。
今天我就以一个踩过无数坑的架构师身份,带你彻底搞懂Spring容器机制。从基础概念到源码实现,从生产案例到面试技巧,全方位掌握这个面试必考点。
原理图解
一句话结论:三级缓存是Spring解决循环依赖的核心设计,通过分层缓存实现Bean的提前暴露和延迟生成。
Bean生命周期全流程
#mermaid-svg-69t2OnCtQBQoZRn0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-69t2OnCtQBQoZRn0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-69t2OnCtQBQoZRn0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-69t2OnCtQBQoZRn0 .error-icon{fill:#552222;}#mermaid-svg-69t2OnCtQBQoZRn0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-69t2OnCtQBQoZRn0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-69t2OnCtQBQoZRn0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-69t2OnCtQBQoZRn0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-69t2OnCtQBQoZRn0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-69t2OnCtQBQoZRn0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-69t2OnCtQBQoZRn0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-69t2OnCtQBQoZRn0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-69t2OnCtQBQoZRn0 .marker.cross{stroke:#333333;}#mermaid-svg-69t2OnCtQBQoZRn0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-69t2OnCtQBQoZRn0 p{margin:0;}#mermaid-svg-69t2OnCtQBQoZRn0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-69t2OnCtQBQoZRn0 .cluster-label text{fill:#333;}#mermaid-svg-69t2OnCtQBQoZRn0 .cluster-label span{color:#333;}#mermaid-svg-69t2OnCtQBQoZRn0 .cluster-label span p{background-color:transparent;}#mermaid-svg-69t2OnCtQBQoZRn0 .label text,#mermaid-svg-69t2OnCtQBQoZRn0 span{fill:#333;color:#333;}#mermaid-svg-69t2OnCtQBQoZRn0 .node rect,#mermaid-svg-69t2OnCtQBQoZRn0 .node circle,#mermaid-svg-69t2OnCtQBQoZRn0 .node ellipse,#mermaid-svg-69t2OnCtQBQoZRn0 .node polygon,#mermaid-svg-69t2OnCtQBQoZRn0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-69t2OnCtQBQoZRn0 .rough-node .label text,#mermaid-svg-69t2OnCtQBQoZRn0 .node .label text,#mermaid-svg-69t2OnCtQBQoZRn0 .image-shape .label,#mermaid-svg-69t2OnCtQBQoZRn0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-69t2OnCtQBQoZRn0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-69t2OnCtQBQoZRn0 .rough-node .label,#mermaid-svg-69t2OnCtQBQoZRn0 .node .label,#mermaid-svg-69t2OnCtQBQoZRn0 .image-shape .label,#mermaid-svg-69t2OnCtQBQoZRn0 .icon-shape .label{text-align:center;}#mermaid-svg-69t2OnCtQBQoZRn0 .node.clickable{cursor:pointer;}#mermaid-svg-69t2OnCtQBQoZRn0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-69t2OnCtQBQoZRn0 .arrowheadPath{fill:#333333;}#mermaid-svg-69t2OnCtQBQoZRn0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-69t2OnCtQBQoZRn0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-69t2OnCtQBQoZRn0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-69t2OnCtQBQoZRn0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-69t2OnCtQBQoZRn0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-69t2OnCtQBQoZRn0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-69t2OnCtQBQoZRn0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-69t2OnCtQBQoZRn0 .cluster text{fill:#333;}#mermaid-svg-69t2OnCtQBQoZRn0 .cluster span{color:#333;}#mermaid-svg-69t2OnCtQBQoZRn0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-69t2OnCtQBQoZRn0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-69t2OnCtQBQoZRn0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-69t2OnCtQBQoZRn0 .icon-shape,#mermaid-svg-69t2OnCtQBQoZRn0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-69t2OnCtQBQoZRn0 .icon-shape p,#mermaid-svg-69t2OnCtQBQoZRn0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-69t2OnCtQBQoZRn0 .icon-shape .label rect,#mermaid-svg-69t2OnCtQBQoZRn0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-69t2OnCtQBQoZRn0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-69t2OnCtQBQoZRn0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-69t2OnCtQBQoZRn0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 实例化Instantiation
属性填充Population
Aware接口回调
BeanPostProcessor前置处理
初始化Initialization
BeanPostProcessor后置处理
就绪Ready
使用中In Use
销毁Destruction
PreDestroy
DisposableBean.destroy
自定义destroy-method
Spring Bean的生命周期就像一条精密的流水线,每个环节都有明确职责。实例化只是创建了对象骨架,属性填充完成血肉注入,Aware接口让Bean感知容器环境,BeanPostProcessor提供各种扩展能力,初始化完成Bean的准备工作,最终Bean才真正就绪可以被使用。
三级缓存结构
#mermaid-svg-MOTjBnb0XmwVp3gb{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MOTjBnb0XmwVp3gb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MOTjBnb0XmwVp3gb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MOTjBnb0XmwVp3gb .error-icon{fill:#552222;}#mermaid-svg-MOTjBnb0XmwVp3gb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MOTjBnb0XmwVp3gb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MOTjBnb0XmwVp3gb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MOTjBnb0XmwVp3gb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MOTjBnb0XmwVp3gb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MOTjBnb0XmwVp3gb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MOTjBnb0XmwVp3gb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MOTjBnb0XmwVp3gb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MOTjBnb0XmwVp3gb .marker.cross{stroke:#333333;}#mermaid-svg-MOTjBnb0XmwVp3gb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MOTjBnb0XmwVp3gb p{margin:0;}#mermaid-svg-MOTjBnb0XmwVp3gb .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MOTjBnb0XmwVp3gb .cluster-label text{fill:#333;}#mermaid-svg-MOTjBnb0XmwVp3gb .cluster-label span{color:#333;}#mermaid-svg-MOTjBnb0XmwVp3gb .cluster-label span p{background-color:transparent;}#mermaid-svg-MOTjBnb0XmwVp3gb .label text,#mermaid-svg-MOTjBnb0XmwVp3gb span{fill:#333;color:#333;}#mermaid-svg-MOTjBnb0XmwVp3gb .node rect,#mermaid-svg-MOTjBnb0XmwVp3gb .node circle,#mermaid-svg-MOTjBnb0XmwVp3gb .node ellipse,#mermaid-svg-MOTjBnb0XmwVp3gb .node polygon,#mermaid-svg-MOTjBnb0XmwVp3gb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MOTjBnb0XmwVp3gb .rough-node .label text,#mermaid-svg-MOTjBnb0XmwVp3gb .node .label text,#mermaid-svg-MOTjBnb0XmwVp3gb .image-shape .label,#mermaid-svg-MOTjBnb0XmwVp3gb .icon-shape .label{text-anchor:middle;}#mermaid-svg-MOTjBnb0XmwVp3gb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MOTjBnb0XmwVp3gb .rough-node .label,#mermaid-svg-MOTjBnb0XmwVp3gb .node .label,#mermaid-svg-MOTjBnb0XmwVp3gb .image-shape .label,#mermaid-svg-MOTjBnb0XmwVp3gb .icon-shape .label{text-align:center;}#mermaid-svg-MOTjBnb0XmwVp3gb .node.clickable{cursor:pointer;}#mermaid-svg-MOTjBnb0XmwVp3gb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MOTjBnb0XmwVp3gb .arrowheadPath{fill:#333333;}#mermaid-svg-MOTjBnb0XmwVp3gb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MOTjBnb0XmwVp3gb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MOTjBnb0XmwVp3gb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MOTjBnb0XmwVp3gb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MOTjBnb0XmwVp3gb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MOTjBnb0XmwVp3gb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MOTjBnb0XmwVp3gb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MOTjBnb0XmwVp3gb .cluster text{fill:#333;}#mermaid-svg-MOTjBnb0XmwVp3gb .cluster span{color:#333;}#mermaid-svg-MOTjBnb0XmwVp3gb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MOTjBnb0XmwVp3gb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MOTjBnb0XmwVp3gb rect.text{fill:none;stroke-width:0;}#mermaid-svg-MOTjBnb0XmwVp3gb .icon-shape,#mermaid-svg-MOTjBnb0XmwVp3gb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MOTjBnb0XmwVp3gb .icon-shape p,#mermaid-svg-MOTjBnb0XmwVp3gb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MOTjBnb0XmwVp3gb .icon-shape .label rect,#mermaid-svg-MOTjBnb0XmwVp3gb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MOTjBnb0XmwVp3gb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MOTjBnb0XmwVp3gb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MOTjBnb0XmwVp3gb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Bean创建流程
三级缓存架构
成品Bean
半成品Bean
ObjectFactory
一级缓存 singletonObjects
对外提供
二级缓存 earlySingletonObjects
三级缓存 singletonFactories
实例化
属性填充触发循环依赖
完成初始化
三级缓存是Spring解决循环依赖的核心机制,每个缓存各司其职:
- 一级缓存:存放最终完成初始化的Bean,是最可靠的成品
- 二级缓存:存放提前暴露的半成品Bean,用于解决循环依赖
- 三级缓存:存放ObjectFactory,支持AOP代理的延迟生成
A/B循环依赖解决时序
Spring容器 BService AService Spring容器 BService AService #mermaid-svg-UnmNVgtnWdpt5XWl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UnmNVgtnWdpt5XWl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UnmNVgtnWdpt5XWl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UnmNVgtnWdpt5XWl .error-icon{fill:#552222;}#mermaid-svg-UnmNVgtnWdpt5XWl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UnmNVgtnWdpt5XWl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UnmNVgtnWdpt5XWl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UnmNVgtnWdpt5XWl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UnmNVgtnWdpt5XWl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UnmNVgtnWdpt5XWl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UnmNVgtnWdpt5XWl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UnmNVgtnWdpt5XWl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UnmNVgtnWdpt5XWl .marker.cross{stroke:#333333;}#mermaid-svg-UnmNVgtnWdpt5XWl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UnmNVgtnWdpt5XWl p{margin:0;}#mermaid-svg-UnmNVgtnWdpt5XWl .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UnmNVgtnWdpt5XWl text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-UnmNVgtnWdpt5XWl .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-UnmNVgtnWdpt5XWl .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-UnmNVgtnWdpt5XWl .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-UnmNVgtnWdpt5XWl .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-UnmNVgtnWdpt5XWl #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-UnmNVgtnWdpt5XWl .sequenceNumber{fill:white;}#mermaid-svg-UnmNVgtnWdpt5XWl #sequencenumber{fill:#333;}#mermaid-svg-UnmNVgtnWdpt5XWl #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-UnmNVgtnWdpt5XWl .messageText{fill:#333;stroke:none;}#mermaid-svg-UnmNVgtnWdpt5XWl .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UnmNVgtnWdpt5XWl .labelText,#mermaid-svg-UnmNVgtnWdpt5XWl .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-UnmNVgtnWdpt5XWl .loopText,#mermaid-svg-UnmNVgtnWdpt5XWl .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-UnmNVgtnWdpt5XWl .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-UnmNVgtnWdpt5XWl .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-UnmNVgtnWdpt5XWl .noteText,#mermaid-svg-UnmNVgtnWdpt5XWl .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-UnmNVgtnWdpt5XWl .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UnmNVgtnWdpt5XWl .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UnmNVgtnWdpt5XWl .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UnmNVgtnWdpt5XWl .actorPopupMenu{position:absolute;}#mermaid-svg-UnmNVgtnWdpt5XWl .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-UnmNVgtnWdpt5XWl .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UnmNVgtnWdpt5XWl .actor-man circle,#mermaid-svg-UnmNVgtnWdpt5XWl line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-UnmNVgtnWdpt5XWl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} getBean("AService") 实例化AService 放入三级缓存 属性填充需要BService getBean("BService") 实例化BService 放入三级缓存 属性填充需要AService getBean("AService")-循环依赖发生 从三级缓存获取A的ObjectFactory 调用getObject()返回半成品A 注入半成品A 初始化完成,移入一级缓存 注入成品B 初始化完成,移入一级缓存
循环依赖的解决关键在于"提前暴露":Bean实例化后立即放入三级缓存,在属性填充阶段如果遇到循环依赖,可以从缓存获取半成品Bean打破依赖闭环。
getBean调用链
#mermaid-svg-It9E6oB63sbt4Ykw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-It9E6oB63sbt4Ykw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-It9E6oB63sbt4Ykw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-It9E6oB63sbt4Ykw .error-icon{fill:#552222;}#mermaid-svg-It9E6oB63sbt4Ykw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-It9E6oB63sbt4Ykw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-It9E6oB63sbt4Ykw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-It9E6oB63sbt4Ykw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-It9E6oB63sbt4Ykw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-It9E6oB63sbt4Ykw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-It9E6oB63sbt4Ykw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-It9E6oB63sbt4Ykw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-It9E6oB63sbt4Ykw .marker.cross{stroke:#333333;}#mermaid-svg-It9E6oB63sbt4Ykw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-It9E6oB63sbt4Ykw p{margin:0;}#mermaid-svg-It9E6oB63sbt4Ykw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-It9E6oB63sbt4Ykw .cluster-label text{fill:#333;}#mermaid-svg-It9E6oB63sbt4Ykw .cluster-label span{color:#333;}#mermaid-svg-It9E6oB63sbt4Ykw .cluster-label span p{background-color:transparent;}#mermaid-svg-It9E6oB63sbt4Ykw .label text,#mermaid-svg-It9E6oB63sbt4Ykw span{fill:#333;color:#333;}#mermaid-svg-It9E6oB63sbt4Ykw .node rect,#mermaid-svg-It9E6oB63sbt4Ykw .node circle,#mermaid-svg-It9E6oB63sbt4Ykw .node ellipse,#mermaid-svg-It9E6oB63sbt4Ykw .node polygon,#mermaid-svg-It9E6oB63sbt4Ykw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-It9E6oB63sbt4Ykw .rough-node .label text,#mermaid-svg-It9E6oB63sbt4Ykw .node .label text,#mermaid-svg-It9E6oB63sbt4Ykw .image-shape .label,#mermaid-svg-It9E6oB63sbt4Ykw .icon-shape .label{text-anchor:middle;}#mermaid-svg-It9E6oB63sbt4Ykw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-It9E6oB63sbt4Ykw .rough-node .label,#mermaid-svg-It9E6oB63sbt4Ykw .node .label,#mermaid-svg-It9E6oB63sbt4Ykw .image-shape .label,#mermaid-svg-It9E6oB63sbt4Ykw .icon-shape .label{text-align:center;}#mermaid-svg-It9E6oB63sbt4Ykw .node.clickable{cursor:pointer;}#mermaid-svg-It9E6oB63sbt4Ykw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-It9E6oB63sbt4Ykw .arrowheadPath{fill:#333333;}#mermaid-svg-It9E6oB63sbt4Ykw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-It9E6oB63sbt4Ykw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-It9E6oB63sbt4Ykw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-It9E6oB63sbt4Ykw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-It9E6oB63sbt4Ykw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-It9E6oB63sbt4Ykw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-It9E6oB63sbt4Ykw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-It9E6oB63sbt4Ykw .cluster text{fill:#333;}#mermaid-svg-It9E6oB63sbt4Ykw .cluster span{color:#333;}#mermaid-svg-It9E6oB63sbt4Ykw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-It9E6oB63sbt4Ykw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-It9E6oB63sbt4Ykw rect.text{fill:none;stroke-width:0;}#mermaid-svg-It9E6oB63sbt4Ykw .icon-shape,#mermaid-svg-It9E6oB63sbt4Ykw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-It9E6oB63sbt4Ykw .icon-shape p,#mermaid-svg-It9E6oB63sbt4Ykw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-It9E6oB63sbt4Ykw .icon-shape .label rect,#mermaid-svg-It9E6oB63sbt4Ykw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-It9E6oB63sbt4Ykw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-It9E6oB63sbt4Ykw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-It9E6oB63sbt4Ykw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
否
是
否
是
getBean方法
doGetBean
getSingleton-检查一级缓存
是否找到?
getSingleton-检查二级缓存
返回成品Bean
是否找到?
getSingleton-检查三级缓存
返回半成品Bean
是否找到?
创建Bean实例
调用ObjectFactory.getObject
属性填充
初始化
放入一级缓存
getBean调用链体现了Spring的缓存查找策略:优先从一级缓存获取成品,没有则查二级缓存获取半成品,最后才考虑创建新Bean。这种分层缓存机制确保了Bean的复用性和循环依赖的解决。
BeanPostProcessor扩展点位置图
#mermaid-svg-7D7TvigQqqHBECJp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7D7TvigQqqHBECJp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7D7TvigQqqHBECJp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7D7TvigQqqHBECJp .error-icon{fill:#552222;}#mermaid-svg-7D7TvigQqqHBECJp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7D7TvigQqqHBECJp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7D7TvigQqqHBECJp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7D7TvigQqqHBECJp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7D7TvigQqqHBECJp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7D7TvigQqqHBECJp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7D7TvigQqqHBECJp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7D7TvigQqqHBECJp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7D7TvigQqqHBECJp .marker.cross{stroke:#333333;}#mermaid-svg-7D7TvigQqqHBECJp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7D7TvigQqqHBECJp p{margin:0;}#mermaid-svg-7D7TvigQqqHBECJp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7D7TvigQqqHBECJp .cluster-label text{fill:#333;}#mermaid-svg-7D7TvigQqqHBECJp .cluster-label span{color:#333;}#mermaid-svg-7D7TvigQqqHBECJp .cluster-label span p{background-color:transparent;}#mermaid-svg-7D7TvigQqqHBECJp .label text,#mermaid-svg-7D7TvigQqqHBECJp span{fill:#333;color:#333;}#mermaid-svg-7D7TvigQqqHBECJp .node rect,#mermaid-svg-7D7TvigQqqHBECJp .node circle,#mermaid-svg-7D7TvigQqqHBECJp .node ellipse,#mermaid-svg-7D7TvigQqqHBECJp .node polygon,#mermaid-svg-7D7TvigQqqHBECJp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7D7TvigQqqHBECJp .rough-node .label text,#mermaid-svg-7D7TvigQqqHBECJp .node .label text,#mermaid-svg-7D7TvigQqqHBECJp .image-shape .label,#mermaid-svg-7D7TvigQqqHBECJp .icon-shape .label{text-anchor:middle;}#mermaid-svg-7D7TvigQqqHBECJp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7D7TvigQqqHBECJp .rough-node .label,#mermaid-svg-7D7TvigQqqHBECJp .node .label,#mermaid-svg-7D7TvigQqqHBECJp .image-shape .label,#mermaid-svg-7D7TvigQqqHBECJp .icon-shape .label{text-align:center;}#mermaid-svg-7D7TvigQqqHBECJp .node.clickable{cursor:pointer;}#mermaid-svg-7D7TvigQqqHBECJp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7D7TvigQqqHBECJp .arrowheadPath{fill:#333333;}#mermaid-svg-7D7TvigQqqHBECJp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7D7TvigQqqHBECJp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7D7TvigQqqHBECJp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7D7TvigQqqHBECJp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7D7TvigQqqHBECJp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7D7TvigQqqHBECJp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7D7TvigQqqHBECJp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7D7TvigQqqHBECJp .cluster text{fill:#333;}#mermaid-svg-7D7TvigQqqHBECJp .cluster span{color:#333;}#mermaid-svg-7D7TvigQqqHBECJp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7D7TvigQqqHBECJp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7D7TvigQqqHBECJp rect.text{fill:none;stroke-width:0;}#mermaid-svg-7D7TvigQqqHBECJp .icon-shape,#mermaid-svg-7D7TvigQqqHBECJp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7D7TvigQqqHBECJp .icon-shape p,#mermaid-svg-7D7TvigQqqHBECJp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7D7TvigQqqHBECJp .icon-shape .label rect,#mermaid-svg-7D7TvigQqqHBECJp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7D7TvigQqqHBECJp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7D7TvigQqqHBECJp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7D7TvigQqqHBECJp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 特殊处理器
BeanPostProcessor扩展点
实例化
属性填充
Aware接口回调
BeanPostProcessor前置处理
初始化
BeanPostProcessor后置处理
就绪
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
BeanPostProcessor.postProcessBeforeInitialization
MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition
BeanPostProcessor.postProcessAfterInitialization
@Autowired处理
@Value处理
AOP代理生成
@Async代理生成
BeanPostProcessor是Spring扩展机制的核心,在Bean生命周期的关键节点插入自定义逻辑。特别值得注意的是,AOP代理通常在BeanPostProcessor后置处理阶段生成,这也正是三级缓存需要支持代理对象的原因。
Spring容器启动流程图
#mermaid-svg-otb6nh4S0mwAwflf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-otb6nh4S0mwAwflf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-otb6nh4S0mwAwflf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-otb6nh4S0mwAwflf .error-icon{fill:#552222;}#mermaid-svg-otb6nh4S0mwAwflf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-otb6nh4S0mwAwflf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-otb6nh4S0mwAwflf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-otb6nh4S0mwAwflf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-otb6nh4S0mwAwflf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-otb6nh4S0mwAwflf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-otb6nh4S0mwAwflf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-otb6nh4S0mwAwflf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-otb6nh4S0mwAwflf .marker.cross{stroke:#333333;}#mermaid-svg-otb6nh4S0mwAwflf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-otb6nh4S0mwAwflf p{margin:0;}#mermaid-svg-otb6nh4S0mwAwflf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-otb6nh4S0mwAwflf .cluster-label text{fill:#333;}#mermaid-svg-otb6nh4S0mwAwflf .cluster-label span{color:#333;}#mermaid-svg-otb6nh4S0mwAwflf .cluster-label span p{background-color:transparent;}#mermaid-svg-otb6nh4S0mwAwflf .label text,#mermaid-svg-otb6nh4S0mwAwflf span{fill:#333;color:#333;}#mermaid-svg-otb6nh4S0mwAwflf .node rect,#mermaid-svg-otb6nh4S0mwAwflf .node circle,#mermaid-svg-otb6nh4S0mwAwflf .node ellipse,#mermaid-svg-otb6nh4S0mwAwflf .node polygon,#mermaid-svg-otb6nh4S0mwAwflf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-otb6nh4S0mwAwflf .rough-node .label text,#mermaid-svg-otb6nh4S0mwAwflf .node .label text,#mermaid-svg-otb6nh4S0mwAwflf .image-shape .label,#mermaid-svg-otb6nh4S0mwAwflf .icon-shape .label{text-anchor:middle;}#mermaid-svg-otb6nh4S0mwAwflf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-otb6nh4S0mwAwflf .rough-node .label,#mermaid-svg-otb6nh4S0mwAwflf .node .label,#mermaid-svg-otb6nh4S0mwAwflf .image-shape .label,#mermaid-svg-otb6nh4S0mwAwflf .icon-shape .label{text-align:center;}#mermaid-svg-otb6nh4S0mwAwflf .node.clickable{cursor:pointer;}#mermaid-svg-otb6nh4S0mwAwflf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-otb6nh4S0mwAwflf .arrowheadPath{fill:#333333;}#mermaid-svg-otb6nh4S0mwAwflf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-otb6nh4S0mwAwflf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-otb6nh4S0mwAwflf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-otb6nh4S0mwAwflf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-otb6nh4S0mwAwflf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-otb6nh4S0mwAwflf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-otb6nh4S0mwAwflf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-otb6nh4S0mwAwflf .cluster text{fill:#333;}#mermaid-svg-otb6nh4S0mwAwflf .cluster span{color:#333;}#mermaid-svg-otb6nh4S0mwAwflf div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-otb6nh4S0mwAwflf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-otb6nh4S0mwAwflf rect.text{fill:none;stroke-width:0;}#mermaid-svg-otb6nh4S0mwAwflf .icon-shape,#mermaid-svg-otb6nh4S0mwAwflf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-otb6nh4S0mwAwflf .icon-shape p,#mermaid-svg-otb6nh4S0mwAwflf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-otb6nh4S0mwAwflf .icon-shape .label rect,#mermaid-svg-otb6nh4S0mwAwflf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-otb6nh4S0mwAwflf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-otb6nh4S0mwAwflf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-otb6nh4S0mwAwflf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 循环依赖检测
关键扩展点
Spring容器启动
BeanDefinition扫描
BeanDefinition注册
BeanFactoryPostProcessor处理
Bean实例化
属性填充
初始化
Bean就绪
ConfigurationClassPostProcessor
PropertySourcesPlaceholderConfigurer
@Scope注解处理
@Autowired注入
@Resource注入
InitializingBean.afterPropertiesSet
自定义init-method
三级缓存检查
循环依赖识别
提前暴露机制
Spring容器启动是一个复杂的过程,涉及多个扩展点和检查机制。理解这个流程有助于我们更好地掌握Bean的创建时机和循环依赖的解决时机。
源码深挖
一句话结论:Spring三级缓存的精妙之处在于通过ObjectFactory实现延迟生成,既解决循环依赖又不影响正常性能。
DefaultSingletonBeanRegistry中的三级缓存实现
java
// Spring Framework 6.1.x
public class DefaultSingletonBeanRegistry {
// 一级缓存:存放最终完成初始化的Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存:存放提前暴露的Bean(未完成初始化)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// 三级缓存:存放ObjectFactory,支持AOP代理延迟生成
private final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>(16);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 先从一级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject != null) {
return singletonObject;
}
// 允许早期引用且二级缓存存在
if (allowEarlyReference) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject != null) {
return singletonObject;
}
// 从三级缓存获取ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
return singletonObject;
}
}
这段源码揭示了三级缓存的查找顺序和缓存更替规则。当发生循环依赖时,Spring会从三级缓存获取ObjectFactory并调用getObject()方法生成早期引用,然后将其移入二级缓存。
AbstractAutowireCapableBeanFactory的创建流程
关键时序分析:
- 实例化阶段:Bean被创建但未初始化,此时放入三级缓存
- 属性填充阶段:如果遇到循环依赖,从三级缓存获取ObjectFactory
- 初始化阶段:Bean完成初始化,移入一级缓存
- 使用阶段:从一级缓存获取完整的Bean
这种设计确保了在循环依赖场景下,Bean能够被正确创建和初始化,同时避免了对象不一致的问题。
实际应用中的循环依赖场景分析
java
// 场景1:典型的循环依赖
@Service
public class UserService {
@Autowired
private OrderService orderService;
}
@Service
public class OrderService {
@Autowired
private UserService userService;
}
// 场景2:构造器注入的循环依赖(无法解决)
@Service
public class PaymentService {
private final UserService userService;
public PaymentService(UserService userService) {
this.userService = userService;
}
}
@Service
public class UserService {
private final PaymentService paymentService;
public UserService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}
在实际开发中,场景1可以通过三级缓存自动解决,而场景2会抛出BeanCurrentlyInCreationException。这提醒我们在架构设计时要尽量避免构造器注入的循环依赖。
java
// Spring Framework 6.1.x
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
BeanWrapper instanceWrapper = null;
Object bean = null;
// 1. 实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
bean = instanceWrapper.getWrappedInstance();
// 2. 提前暴露到三级缓存(解决循环依赖关键)
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 3. 属性填充
populateBean(beanName, mbd, instanceWrapper);
// 4. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
return exposedObject;
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
}
}
}
addSingletonFactory方法是循环依赖解决的核心,它在Bean实例化后立即将ObjectFactory放入三级缓存。这个ObjectFactory的getObject()方法会在需要时调用getEarlyBeanReference,该方法会执行AOP代理的早期生成。
循环依赖检测与异常处理
java
// Spring Framework 6.1.x
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject != null) {
return singletonObject;
}
// 检查是否正在创建中(循环依赖标识)
if (isSingletonCurrentlyInCreation(beanName)) {
if (allowEarlyReference) {
// 从三级缓存获取早期引用
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 放入二级缓存,移出三级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}
isSingletonCurrentlyInCreation方法用于检测Bean是否正在创建中,这是循环依赖的重要标识。当检测到循环依赖时,Spring会从三级缓存获取早期引用来打破依赖闭环。
FactoryBean的特殊处理
java
// Spring Framework 6.1.x
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
this.factoryBeanObjectCache.put(beanName, object);
}
return object;
} else {
return doGetObjectFromFactoryBean(factory, beanName);
}
}
protected Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) {
try {
return factory.getObject();
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
}
FactoryBean的处理逻辑与普通Bean不同,它会调用getObject()方法来获取实际的对象实例。这个机制使得Spring可以支持复杂的对象创建逻辑,比如数据库连接池、JNDI对象等。
生产实战
一句话结论:AOP代理与循环依赖的冲突是生产环境中常见的问题,需要通过延迟注入策略来解决。
自定义BeanPostProcessor导致循环依赖失败的生产异常
背景 :在之前的公司,我们遇到了一个典型的生产环境问题。电商平台订单系统使用自定义的BeanPostProcessor来为服务类添加性能监控注解支持。在一次版本发布后,系统启动时抛出了BeanCurrentlyInCreationException。
现象:
Exception encountered during context initialization -
cancelling refresh attempt: org.springframework.beans.factory.
BeanCurrentlyInCreationException: Error creating bean with name 'orderService':
Bean with name 'orderService' has been injected into other beans [performanceMonitor]
in its raw version as part of a circular reference, but has eventually been wrapped.
定位过程:
-
日志分析:异常信息显示orderService被注入到了performanceMonitor中,但最终被包装了
-
依赖关系梳理 :
- OrderService依赖PerformanceMonitor(通过@Autowired)
- PerformanceMonitor依赖OrderService(通过自定义BeanPostProcessor)
-
代码检查 :
java@Service public class OrderService { @Autowired private PerformanceMonitor performanceMonitor; @PerformanceMonitor public void createOrder(OrderDTO order) { // 业务逻辑 } } @Component public class PerformanceMonitor implements BeanPostProcessor { @Autowired private OrderService orderService; // 循环依赖 @Override public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean instanceof OrderService) { // 创建代理对象 return Proxy.newProxyInstance(...); } return bean; } }
根因分析 :
问题的根本在于AOP代理与循环依赖的冲突。具体表现为:
-
Bean创建时序:
- OrderService实例化后放入三级缓存
- 属性填充时创建PerformanceMonitor
- PerformanceMonitor初始化时通过BeanPostProcessor为OrderService创建代理
- PerformanceMonitor依赖OrderService,从三级缓存获取原始OrderService
- 最终容器中存在两个OrderService对象:原始对象和代理对象
-
缓存不一致:
- PerformanceMonitor中持有的是原始OrderService
- 容器对外提供的是代理OrderService
- Spring检测到对象不一致,判定存在业务风险
修复方案 :
我们采用了延迟注入策略,避免在BeanPostProcessor中直接注入循环依赖:
java
@Component
public class PerformanceMonitor implements BeanPostProcessor {
private OrderService orderService;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof OrderService) {
// 延迟注入,避免循环依赖
if (orderService == null) {
orderService = (OrderService) bean;
}
return Proxy.newProxyInstance(...);
}
return bean;
}
@PostConstruct
public void init() {
// 在容器完全初始化后再设置依赖
// 或者通过ApplicationContextAware获取
}
}
验证数据 :
修复后系统启动正常,性能监控功能完整:
| 指标 | 修复前 | 修复后 | 改善幅度 |
|---|---|---|---|
| 启动时间 | 较长 | 显著降低 | 大幅改善 |
| 内存占用 | 偏高 | 明显减少 | 优化显著 |
| 监控覆盖率 | 无 | 全面覆盖 | 完全解决 |
循环依赖解决方案对比
| 方案 | 适用场景 | 优点 | 缺点 | 推荐指数 |
|---|---|---|---|---|
| 三级缓存自动解决 | 单例Bean + Setter/字段注入 | 无需代码改动,Spring自动处理 | 无法处理构造器注入和AOP代理冲突 | ⭐⭐⭐⭐⭐ |
| @Lazy延迟注入 | 构造器注入场景 | 解决构造器循环依赖 | 增加启动时间,延迟感知 | ⭐⭐⭐⭐ |
| 重构消除循环依赖 | 长期维护项目 | 架构更清晰,避免技术债 | 需要代码重构,成本高 | ⭐⭐⭐ |
| 事件驱动解耦 | 松耦合场景 | 完全消除依赖关系 | 引入复杂性,不适合所有场景 | ⭐⭐ |
复盘总结 :
这次事故暴露了我们在Spring容器机制理解上的不足。关键教训包括:
- AOP代理与循环依赖的冲突:BeanPostProcessor中创建代理时,如果涉及循环依赖,会导致对象不一致
- 三级缓存的局限性:三级缓存只能解决单例Bean的Setter/字段注入循环依赖,无法处理AOP代理场景
- 设计原则:避免在BeanPostProcessor中注入其他Bean,特别是可能形成循环依赖的情况
- 技术选型权衡:在架构设计时要考虑循环依赖的可能性,优先选择不会产生循环依赖的设计方案
经验教训 :
通过这次故障处理,我们深刻认识到:
- 技术债务:循环依赖往往是架构设计不合理的结果,应该从源头避免
- 监控重要性:建立完善的Bean依赖关系监控,能够及早发现问题
- 代码审查:在代码审查环节重点关注循环依赖风险
- 技术培训:加强团队对Spring容器机制的理解,提高架构设计能力
追问链条
一句话结论:面试官通过追问来验证候选人是否真正理解Spring容器机制,而非停留在表面概念。
追问1:为什么需要三级缓存而不是二级缓存?
候选人视角 :
我认为三级缓存的核心价值在于支持AOP代理的延迟生成。如果只有二级缓存,当Bean需要生成代理时,代理对象必须在实例化阶段就创建完成。但在循环依赖场景下,这会导致问题:Bean A和Bean B互相依赖,如果A需要生成代理,那么B注入的就是代理A,而A最终又可能被重新代理,造成对象不一致。
面试官视角 :
这个问题在筛选真正理解Spring源码的候选人。很多候选人只能回答"三级缓存解决循环依赖",但说不清楚为什么需要三级。我在看候选人是否理解:
- ObjectFactory的作用:三级缓存存储的是ObjectFactory而不是直接的对象,这支持延迟生成
- AOP代理的特殊性:代理对象需要在初始化后生成,但循环依赖又需要提前暴露
- 性能权衡:没有循环依赖时,ObjectFactory永远不会被调用,不影响正常性能
回答要点:
- 二级缓存只能存储原始对象,无法处理代理场景
- 三级缓存的ObjectFactory支持
getEarlyBeanReference方法,在需要时才生成代理 - 这种设计既解决了循环依赖,又不影响无循环依赖时的性能
追问2:构造器注入为什么无法解决循环依赖?
候选人视角 :
构造器注入无法解决循环依赖是因为构造函数的执行时机。当Spring创建Bean A时,需要先调用A的构造函数,而构造函数中已经注入了Bean B的依赖。这时Spring需要先创建Bean B,但Bean B的构造函数又依赖Bean A,形成无限递归。而Setter注入可以在对象实例化后再设置依赖,为循环依赖的解决提供了时间窗口。
面试官视角 :
这个问题考察候选人对Spring Bean创建机制的理解深度。我在看候选人是否明白:
- 构造函数的原子性:构造函数必须完整执行,不能部分完成
- 实例化vs属性填充的分离:三级缓存依赖这两个阶段的分离
- 设计哲学:Spring为什么推荐Setter注入而不是构造器注入(除了可测试性)
回答要点:
- 构造函数必须在对象完全创建前执行,无法"部分实例化"
- 三级缓存的提前暴露机制只适用于实例化后、属性填充前的阶段
- 这是Spring的设计选择:构造器注入保证对象完整性,但牺牲了循环依赖解决能力
追问3:@Autowired和@Resource在循环依赖处理上有区别吗?
候选人视角 :
@Autowired和@Resource在循环依赖处理上没有本质区别,因为它们都是在属性填充阶段进行依赖注入的。两者的区别主要在于:
- 注入方式:@Autowired按类型注入,@Resource按名称注入
- 依赖查找:@Autowired支持@Primary和@Qualifier,@Resource支持name属性
- 来源:@Autowired是Spring注解,@Resource是JSR-250标准
但在循环依赖场景下,两者都会触发相同的缓存查找逻辑。
面试官视角 :
这个问题看似简单,但能看出候选人对Spring依赖注入机制的掌握程度。我在看:
- 底层实现一致性:是否知道两个注解最终都调用相同的注入逻辑
- 容错能力:是否知道@Resource找不到时会回退到类型匹配
- 最佳实践:是否知道在循环依赖场景下应该优先使用哪种注解
回答要点:
- 底层都通过AutowiredAnnotationBeanPostProcessor处理,循环依赖处理逻辑相同
- @Resource的名称匹配可能在某些边缘情况下影响循环依赖的解决
- 最佳实践:在循环依赖场景下,建议使用@Autowired并配合明确的@Qualifier,避免名称不确定性
追问4:Spring Boot 3中虚拟线程对循环依赖有什么影响?
候选人视角 :
虚拟线程(Virtual Threads)是JDK 21引入的新特性,在Spring Boot 3中可以通过配置启用。虚拟线程主要通过改变线程调度模型来提高并发性能,但不会直接影响Spring的Bean创建机制。循环依赖的解决仍然依赖于三级缓存机制,虚拟线程可能会影响Bean的初始化性能,但不会改变循环依赖的基本解决逻辑。
面试官视角 :
这个问题考察候选人对新技术与现有框架结合的理解。我在看候选人是否了解:
- 虚拟线程的适用场景:是否知道虚拟线程主要适用于IO密集型任务
- 与Spring框架的兼容性:是否了解虚拟线程对Spring容器机制的影响
- 性能影响:是否能够分析虚拟线程对循环依赖场景的性能影响
回答要点:
- 虚拟线程不影响三级缓存的运作机制,循环依赖解决逻辑不变
- 虚拟线程主要影响Bean初始化和属性填充阶段的执行性能
- 在IO密集型场景下,虚拟线程可以提高循环依赖解决的并发性能
- 但要注意虚拟线程不适合CPU密集型操作,避免在Bean初始化中使用复杂计算
追问5:如何检测和调试Spring中的循环依赖?
候选人视角 :
检测和调试Spring循环依赖有多种方法:
- 启动时异常 :观察
BeanCurrentlyInCreationException异常信息 - 日志分析:启用DEBUG级别日志,观察Bean创建时序
- 工具使用 :使用Spring Boot Actuator的
/beans端点查看Bean依赖关系 - 代码分析:静态代码分析工具如SpotBugs可以检测潜在的循环依赖
调试时可以结合这些方法,从异常信息入手,逐步定位循环依赖的具体位置。
面试官视角 :
这个问题考察候选人的问题解决能力 和工具使用经验。我在看:
- 调试方法的多样性:是否了解多种检测和调试手段
- 实际经验:是否有处理循环依赖的实际经验
- 工具熟练度:是否熟悉Spring生态中的调试工具
回答要点:
- 启用Spring的
debug模式,观察详细的Bean创建日志 - 使用
ApplicationContext.getBeansOfType()方法逐步检查依赖关系 - 在关键Bean的
@PostConstruct方法中打印依赖信息 - 使用IDE的调试功能,设置断点观察Bean创建时序
- 对于复杂项目,可以考虑使用依赖注入图可视化工具
总结延伸
一句话结论:掌握Spring容器机制不仅是面试需要,更是成为优秀架构师的必备技能。
核心结论速记表
| 结论 | 关键点 |
|---|---|
| 三级缓存分工 | 一级存成品、二级存半成品、三级存工厂 |
| 循环依赖解决 | 实例化→三级缓存→属性填充→缓存获取→初始化→一级缓存 |
| AOP代理支持 | ObjectFactory延迟生成,避免早期代理对象问题 |
| 构造器限制 | 无法解决循环依赖,必须使用Setter/字段注入 |
| FactoryBean机制 | getObject()返回实际对象,支持复杂对象创建 |
| 异常处理 | BeanCurrentlyInCreationException标识对象不一致风险 |
Spring容器机制面试要点总结
| 面试维度 | 高频考点 | 重要性 | 难度 |
|---|---|---|---|
| 基础概念 | Bean生命周期、三级缓存作用 | ⭐⭐⭐ | ⭐ |
| 源码实现 | getBean流程、缓存查找机制 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 实际应用 | 循环依赖解决、AOP代理处理 | ⭐⭐⭐⭐ | ⭐⭐ |
| 性能优化 | 缓存策略、内存管理 | ⭐⭐⭐ | ⭐⭐ |
| 异常处理 | 常见异常、调试技巧 | ⭐⭐ | ⭐ |
未来面试趋势分析
根据行业发展趋势,Spring容器机制相关考点可能呈现以下趋势:
- 从理论到实践:不再单纯考察概念记忆,而是结合实际生产场景
- 源码深度要求提高:要求候选人能够阅读和理解Spring核心源码
- 新技术结合:虚拟线程、Spring AI等新技术与现有框架的结合
- 问题解决能力:重点考察候选人定位和解决实际问题的能力
- 架构设计思维:从使用层面上升到架构设计层面的理解
学习建议:
- 深入理解Spring Framework最新版本源码
- 多实践生产环境中的循环依赖场景
- 关注Spring Boot新版本的新特性和最佳实践
- 掌握调试工具和性能分析方法
延伸阅读
-
官方文档:
- Spring Framework Reference: Bean Scopes and Dependencies
- Spring Framework Reference: Customizing the Nature of a Bean
-
源码分析:
- Spring Framework最新版本:
DefaultSingletonBeanRegistry.java - Spring Framework最新版本:
AbstractAutowireCapableBeanFactory.java
- Spring Framework最新版本:
-
经典论文:
- JEP 444: Virtual Threads (JDK 21)
- JSR-250: Common Annotations for Java Platform
-
实战指南:
- Spring Boot最新版本Migration Guide: Upgrade from older versions
- Production-Ready Spring Applications: Dependency Injection Best Practices
- 上一篇:【JAVA 高级进阶04篇《线上问题诊断利器:Arthas与JFR实战手册》】
- 下一篇:【JAVA 高级进阶06篇《Spring Boot 3:自动装配原理与Framework 6新特性落地》】
如果这篇对你有帮助,欢迎点赞+关注,专栏持续更新。