JAVA 高级进阶05篇《Spring容器机制:Bean生命周期与三级缓存全解》

「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的创建流程

关键时序分析

  1. 实例化阶段:Bean被创建但未初始化,此时放入三级缓存
  2. 属性填充阶段:如果遇到循环依赖,从三级缓存获取ObjectFactory
  3. 初始化阶段:Bean完成初始化,移入一级缓存
  4. 使用阶段:从一级缓存获取完整的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.

定位过程

  1. 日志分析:异常信息显示orderService被注入到了performanceMonitor中,但最终被包装了

  2. 依赖关系梳理

    • OrderService依赖PerformanceMonitor(通过@Autowired)
    • PerformanceMonitor依赖OrderService(通过自定义BeanPostProcessor)
  3. 代码检查

    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代理与循环依赖的冲突。具体表现为:

  1. Bean创建时序

    • OrderService实例化后放入三级缓存
    • 属性填充时创建PerformanceMonitor
    • PerformanceMonitor初始化时通过BeanPostProcessor为OrderService创建代理
    • PerformanceMonitor依赖OrderService,从三级缓存获取原始OrderService
    • 最终容器中存在两个OrderService对象:原始对象和代理对象
  2. 缓存不一致

    • 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容器机制理解上的不足。关键教训包括:

  1. AOP代理与循环依赖的冲突:BeanPostProcessor中创建代理时,如果涉及循环依赖,会导致对象不一致
  2. 三级缓存的局限性:三级缓存只能解决单例Bean的Setter/字段注入循环依赖,无法处理AOP代理场景
  3. 设计原则:避免在BeanPostProcessor中注入其他Bean,特别是可能形成循环依赖的情况
  4. 技术选型权衡:在架构设计时要考虑循环依赖的可能性,优先选择不会产生循环依赖的设计方案

经验教训

通过这次故障处理,我们深刻认识到:

  1. 技术债务:循环依赖往往是架构设计不合理的结果,应该从源头避免
  2. 监控重要性:建立完善的Bean依赖关系监控,能够及早发现问题
  3. 代码审查:在代码审查环节重点关注循环依赖风险
  4. 技术培训:加强团队对Spring容器机制的理解,提高架构设计能力

追问链条

一句话结论:面试官通过追问来验证候选人是否真正理解Spring容器机制,而非停留在表面概念。

追问1:为什么需要三级缓存而不是二级缓存?

候选人视角

我认为三级缓存的核心价值在于支持AOP代理的延迟生成。如果只有二级缓存,当Bean需要生成代理时,代理对象必须在实例化阶段就创建完成。但在循环依赖场景下,这会导致问题:Bean A和Bean B互相依赖,如果A需要生成代理,那么B注入的就是代理A,而A最终又可能被重新代理,造成对象不一致。

面试官视角

这个问题在筛选真正理解Spring源码的候选人。很多候选人只能回答"三级缓存解决循环依赖",但说不清楚为什么需要三级。我在看候选人是否理解:

  1. ObjectFactory的作用:三级缓存存储的是ObjectFactory而不是直接的对象,这支持延迟生成
  2. AOP代理的特殊性:代理对象需要在初始化后生成,但循环依赖又需要提前暴露
  3. 性能权衡:没有循环依赖时,ObjectFactory永远不会被调用,不影响正常性能

回答要点

  • 二级缓存只能存储原始对象,无法处理代理场景
  • 三级缓存的ObjectFactory支持getEarlyBeanReference方法,在需要时才生成代理
  • 这种设计既解决了循环依赖,又不影响无循环依赖时的性能

追问2:构造器注入为什么无法解决循环依赖?

候选人视角

构造器注入无法解决循环依赖是因为构造函数的执行时机。当Spring创建Bean A时,需要先调用A的构造函数,而构造函数中已经注入了Bean B的依赖。这时Spring需要先创建Bean B,但Bean B的构造函数又依赖Bean A,形成无限递归。而Setter注入可以在对象实例化后再设置依赖,为循环依赖的解决提供了时间窗口。

面试官视角

这个问题考察候选人对Spring Bean创建机制的理解深度。我在看候选人是否明白:

  1. 构造函数的原子性:构造函数必须完整执行,不能部分完成
  2. 实例化vs属性填充的分离:三级缓存依赖这两个阶段的分离
  3. 设计哲学:Spring为什么推荐Setter注入而不是构造器注入(除了可测试性)

回答要点

  • 构造函数必须在对象完全创建前执行,无法"部分实例化"
  • 三级缓存的提前暴露机制只适用于实例化后、属性填充前的阶段
  • 这是Spring的设计选择:构造器注入保证对象完整性,但牺牲了循环依赖解决能力

追问3:@Autowired和@Resource在循环依赖处理上有区别吗?

候选人视角

@Autowired和@Resource在循环依赖处理上没有本质区别,因为它们都是在属性填充阶段进行依赖注入的。两者的区别主要在于:

  1. 注入方式:@Autowired按类型注入,@Resource按名称注入
  2. 依赖查找:@Autowired支持@Primary和@Qualifier,@Resource支持name属性
  3. 来源:@Autowired是Spring注解,@Resource是JSR-250标准

但在循环依赖场景下,两者都会触发相同的缓存查找逻辑。

面试官视角

这个问题看似简单,但能看出候选人对Spring依赖注入机制的掌握程度。我在看:

  1. 底层实现一致性:是否知道两个注解最终都调用相同的注入逻辑
  2. 容错能力:是否知道@Resource找不到时会回退到类型匹配
  3. 最佳实践:是否知道在循环依赖场景下应该优先使用哪种注解

回答要点

  • 底层都通过AutowiredAnnotationBeanPostProcessor处理,循环依赖处理逻辑相同
  • @Resource的名称匹配可能在某些边缘情况下影响循环依赖的解决
  • 最佳实践:在循环依赖场景下,建议使用@Autowired并配合明确的@Qualifier,避免名称不确定性

追问4:Spring Boot 3中虚拟线程对循环依赖有什么影响?

候选人视角

虚拟线程(Virtual Threads)是JDK 21引入的新特性,在Spring Boot 3中可以通过配置启用。虚拟线程主要通过改变线程调度模型来提高并发性能,但不会直接影响Spring的Bean创建机制。循环依赖的解决仍然依赖于三级缓存机制,虚拟线程可能会影响Bean的初始化性能,但不会改变循环依赖的基本解决逻辑。

面试官视角

这个问题考察候选人对新技术与现有框架结合的理解。我在看候选人是否了解:

  1. 虚拟线程的适用场景:是否知道虚拟线程主要适用于IO密集型任务
  2. 与Spring框架的兼容性:是否了解虚拟线程对Spring容器机制的影响
  3. 性能影响:是否能够分析虚拟线程对循环依赖场景的性能影响

回答要点

  • 虚拟线程不影响三级缓存的运作机制,循环依赖解决逻辑不变
  • 虚拟线程主要影响Bean初始化和属性填充阶段的执行性能
  • 在IO密集型场景下,虚拟线程可以提高循环依赖解决的并发性能
  • 但要注意虚拟线程不适合CPU密集型操作,避免在Bean初始化中使用复杂计算

追问5:如何检测和调试Spring中的循环依赖?

候选人视角

检测和调试Spring循环依赖有多种方法:

  1. 启动时异常 :观察BeanCurrentlyInCreationException异常信息
  2. 日志分析:启用DEBUG级别日志,观察Bean创建时序
  3. 工具使用 :使用Spring Boot Actuator的/beans端点查看Bean依赖关系
  4. 代码分析:静态代码分析工具如SpotBugs可以检测潜在的循环依赖

调试时可以结合这些方法,从异常信息入手,逐步定位循环依赖的具体位置。

面试官视角

这个问题考察候选人的问题解决能力工具使用经验。我在看:

  1. 调试方法的多样性:是否了解多种检测和调试手段
  2. 实际经验:是否有处理循环依赖的实际经验
  3. 工具熟练度:是否熟悉Spring生态中的调试工具

回答要点

  • 启用Spring的debug模式,观察详细的Bean创建日志
  • 使用ApplicationContext.getBeansOfType()方法逐步检查依赖关系
  • 在关键Bean的@PostConstruct方法中打印依赖信息
  • 使用IDE的调试功能,设置断点观察Bean创建时序
  • 对于复杂项目,可以考虑使用依赖注入图可视化工具

总结延伸

一句话结论:掌握Spring容器机制不仅是面试需要,更是成为优秀架构师的必备技能。

核心结论速记表

结论 关键点
三级缓存分工 一级存成品、二级存半成品、三级存工厂
循环依赖解决 实例化→三级缓存→属性填充→缓存获取→初始化→一级缓存
AOP代理支持 ObjectFactory延迟生成,避免早期代理对象问题
构造器限制 无法解决循环依赖,必须使用Setter/字段注入
FactoryBean机制 getObject()返回实际对象,支持复杂对象创建
异常处理 BeanCurrentlyInCreationException标识对象不一致风险

Spring容器机制面试要点总结

面试维度 高频考点 重要性 难度
基础概念 Bean生命周期、三级缓存作用 ⭐⭐⭐
源码实现 getBean流程、缓存查找机制 ⭐⭐⭐⭐ ⭐⭐⭐
实际应用 循环依赖解决、AOP代理处理 ⭐⭐⭐⭐ ⭐⭐
性能优化 缓存策略、内存管理 ⭐⭐⭐ ⭐⭐
异常处理 常见异常、调试技巧 ⭐⭐

未来面试趋势分析

根据行业发展趋势,Spring容器机制相关考点可能呈现以下趋势:

  1. 从理论到实践:不再单纯考察概念记忆,而是结合实际生产场景
  2. 源码深度要求提高:要求候选人能够阅读和理解Spring核心源码
  3. 新技术结合:虚拟线程、Spring AI等新技术与现有框架的结合
  4. 问题解决能力:重点考察候选人定位和解决实际问题的能力
  5. 架构设计思维:从使用层面上升到架构设计层面的理解

学习建议

  • 深入理解Spring Framework最新版本源码
  • 多实践生产环境中的循环依赖场景
  • 关注Spring Boot新版本的新特性和最佳实践
  • 掌握调试工具和性能分析方法

延伸阅读

  1. 官方文档

  2. 源码分析

    • Spring Framework最新版本: DefaultSingletonBeanRegistry.java
    • Spring Framework最新版本: AbstractAutowireCapableBeanFactory.java
  3. 经典论文

    • JEP 444: Virtual Threads (JDK 21)
    • JSR-250: Common Annotations for Java Platform
  4. 实战指南


如果这篇对你有帮助,欢迎点赞+关注,专栏持续更新。

相关推荐
岁月如歌77862 小时前
分布式锁完全指南:从数据库到 Redisson 的演进
java·后端·架构
ocean21032 小时前
2025-2026年Python大厂面试高频问题
python·面试·面试经验
AI深栈2 小时前
第 8 章 · Tool Calling 与 Tool Search
java·人工智能
写后端的胖头鱼2 小时前
【高频面试题】spring事物失效场景(带原理 + 代码示例)
java·后端·spring·事务·事物失效
小孩玩什么2 小时前
深入理解字符串匹配算法:BF算法,KMP算法
java·c语言·开发语言·数据结构·c++·算法
长谷深风1113 小时前
Agent执行系统中的身份与版本设计
java·大数据·人工智能·ai·大模型·task·aiagent
Wang's Blog3 小时前
Java框架快速入门: Spring Security+OAuth2之UserDetails与JDBC认证实践
java·网络·spring
爱从未走散3 小时前
面试八股题
java·面试·职场和发展
晚安日记wanna3 小时前
大文件分片上传的五层追问从 Blob 切片到秒传与弱网容错
前端·面试