首页
API市场
大模型广场
AI应用创作
其他产品
易源易彩
API导航
PromptImg
MCP 服务
产品价格
市场
|
导航
控制台
登录/注册
技术博客
深入解析Spring单例Bean的源码实现与创建过程
深入解析Spring单例Bean的源码实现与创建过程
文章提交:
SmallFast8914
2026-06-18
源码解析
单例Bean
Spring框架
Bean创建
本文由 AI 阅读网络公开技术资讯生成,力求客观但可能存在信息偏差,具体技术细节及数据请以权威来源为准
> ### 摘要 > 本文以源码逐行解析为切入点,深入剖析Spring框架中单例Bean的完整创建过程,涵盖BeanDefinition加载、实例化、属性填充、初始化及注册至单例缓存(singletonObjects)等核心阶段。通过追踪AbstractBeanFactory与DefaultListableBeanFactory等关键类的执行路径,揭示Spring如何在首次getBean调用时完成线程安全的单例构建与三级缓存协同机制,展现其Bean管理的精巧内部机制。 > ### 关键词 > 源码解析,单例Bean,Spring框架,Bean创建,内部机制 ## 一、Spring框架基础与Bean管理机制 ### 1.1 Spring容器初始化过程:BeanFactory与ApplicationContext的区别与联系 在Spring框架浩繁的抽象体系中,容器初始化并非一蹴而就的仪式,而是一场精密编排的启程——它悄然决定了后续所有Bean命运的起点。BeanFactory是Spring最基础的IoC容器接口,提供最基本的依赖查找与生命周期管理能力;而ApplicationContext则在其之上构建,不仅继承全部BeanFactory功能,更扩展了事件发布、国际化、AOP集成等企业级特性。二者的关系,恰如静水与奔流:BeanFactory是深潜于底层的稳定内核,ApplicationContext则是浮出水面、呼吸万象的完整生态。当开发者调用`new AnnotationConfigApplicationContext(...)`时,真正的初始化才真正开始——它会触发`refresh()`方法,依次执行环境准备、BeanFactory创建、配置类解析、BeanDefinition注册等关键步骤。值得注意的是,此时尚未发生任何Bean实例化;一切尚处于“定义就绪、待命而未动”的临界状态。这种分层设计,既保障了轻量级使用的可能性,又为复杂场景预留了充分延展空间——这正是Spring历经多年演进仍屹立不倒的底层智慧。 ### 1.2 BeanDefinition的注册与解析:Spring如何管理Bean的定义信息 BeanDefinition,是Spring眼中Bean的“数字基因图谱”——它不描述实例,却完整编码了该Bean将如何被创建:类名、作用域、是否懒加载、构造参数、属性值、初始化方法、后置处理器……一切皆在此中凝练成结构化的元数据。在`ConfigurationClassPostProcessor`的驱动下,Spring扫描`@Configuration`类、`@Bean`方法、`@Component`注解类,并将它们逐一解析为`BeanDefinition`对象,最终注册至`DefaultListableBeanFactory`的`beanDefinitionMap`中。这一过程看似静默,实则暗藏机锋:同一个Bean可能因不同配置路径被多次定义,Spring需依序合并、覆盖、校验;而`@Lazy`、`@Primary`、`@Scope("singleton")`等注解,则如刻刀般精细雕琢每一份定义的语义边界。正是这些尚未具象的“蓝图”,构成了后续所有实例化、依赖注入与生命周期回调的唯一依据——没有它,`getBean()`便无从知晓该造什么、怎么造、为谁而造。源码逐行解析至此,我们终于触碰到Spring灵魂深处那条不可逾越的铁律:**定义先行,实例在后;蓝图未定,万物不生。** ## 二、单例Bean的创建流程源码分析 ### 2.1 单例Bean的创建入口:getBean方法源码解析 当开发者第一次调用`getBean("xxx")`时,Spring的静默世界骤然被一道指令点亮——这不是一次普通的对象索取,而是一场精密调度的起点。`getBean`作为单例Bean生命周期的正式入口,其背后是`AbstractBeanFactory`中层层嵌套的逻辑跃迁:从`doGetBean`开始,方法首先检查三级缓存(`singletonObjects`、`earlySingletonObjects`、`singletonFactories`)是否存在已就绪或正在创建中的实例;若未命中,则触发`createBean`流程。尤为关键的是,此处的线程安全并非依赖粗粒度锁,而是借由`ConcurrentHashMap`的无锁读+同步块写机制,配合`beforeSingletonCreation`与`afterSingletonCreation`的原子标记,在高并发场景下悄然守护单例的唯一性。一行行追踪下去,我们看到的不只是方法调用栈的延伸,更是一个设计哲学的具象化:**延迟加载不是妥协,而是对资源最审慎的敬意;首次访问的毫秒级开销,换来的是后续所有请求的零成本复用。** 这一入口,既是技术实现的咽喉要道,亦是Spring“按需构建、全局共享”理念最锋利的落笔。 ### 2.2 Bean实例化过程:从反射到对象实例的完整流程 实例化绝非简单的一句`clazz.getDeclaredConstructor().newInstance()`——在`AbstractAutowireCapableBeanFactory`的`createBeanInstance`方法中,Spring以近乎考古般的耐心,逐一分辨构造器策略:优先尝试带参构造器自动装配,失败则回退至无参构造器+反射实例化;若存在`@Lookup`或工厂方法,则交由`SimpleInstantiationStrategy`或`CglibSubclassingInstantiationStrategy`接管。此时,类加载、字节码校验、构造器可访问性检查、参数类型匹配……每一环都如齿轮咬合般严丝合缝。更值得凝视的是,实例化完成后的对象尚处于“裸体”状态:无属性填充、无Aware回调、无初始化方法执行——它只是Spring容器中一个被赋予了内存地址的、沉默的“初生体”。正是这种刻意为之的阶段性解耦,使得`InstantiationAwareBeanPostProcessor`得以在实例化后、初始化前插入定制逻辑,为AOP代理、字段注入等高级能力预留不可替代的钩子。源码逐行解析至此,我们恍然:**所谓“创建”,从来不是一锤定音的终点,而是一次郑重其事的启程——对象在此刻诞生,却在后续每一步中,被反复定义、塑造、确认,直至成为那个被整个应用所信赖的单例Bean。** ## 三、Bean的属性填充与初始化过程 ### 3.1 属性填充阶段:Spring如何完成Bean的依赖注入 当“初生体”在内存中悄然落定,它仍是一具未被赋予关系的空壳——没有依赖,没有上下文,亦无处安放其存在意义。此时,`populateBean`方法如一位沉静而精准的织网者,在`AbstractAutowireCapableBeanFactory`中徐徐展开属性填充的全程。它不急于注入,而是先校验Bean是否可修改、是否被`@Lookup`或`@Autowired`标记、是否存在`InstantiationAwareBeanPostProcessor`的前置干预;随后,依序执行`@Autowired`字段注入、`@Value`值解析、`@Resource`按名称装配,并在必要时触发`resolveDependency`进行类型匹配与循环依赖探测。尤为精妙的是,这一阶段与三级缓存机制深度咬合:若当前Bean被其他Bean依赖,而自身尚未初始化完毕,Spring便提前将“早期引用”(early reference)暴露至`earlySingletonObjects`,从而在不破坏单例语义的前提下,为循环依赖提供合法出口。一行行源码翻过,我们触摸到的不仅是反射设值与类型转换的代码逻辑,更是一种对“关系”的郑重承诺——**依赖不是强加的枷锁,而是经由定义校验、类型协商、时机权衡后,主动缔结的生命契约;每一次`setFieldValue`的调用,都是Spring在混沌的引用图谱中,亲手点亮的一盏确认之灯。** ### 3.2 初始化方法调用:afterPropertiesSet与自定义初始化方法 属性落定之后,对象仍未真正“活过来”——它尚需一次庄严的自我确认:唤醒Aware接口赋予的容器感知能力,执行用户声明的初始化逻辑,最终通过`InitializingBean.afterPropertiesSet()`或`@PostConstruct`标注的方法完成人格赋形。此阶段由`initializeBean`统一调度,在`AbstractAutowireCapableBeanFactory`中层层推进:先调用`invokeAwareMethods`,将`BeanFactoryAware`、`ApplicationContextAware`等接口注入对应上下文引用,使Bean从“被管理”跃升为“知管理”;继而遍历`BeanPostProcessor.postProcessBeforeInitialization`,为AOP代理、属性增强等预留钩子;再执行`invokeInitMethods`,严格区分`InitializingBean`回调与自定义`init-method`的调用顺序与异常处理策略;最后,再经`postProcessAfterInitialization`完成终态封装。整个过程如一场精密的加冕仪式——没有跳步,不容省略,每一步都受`try-catch`严密包裹,任一环节失败即终止流程并抛出`BeanCreationException`。源码逐行解析至此,我们终于彻悟:**所谓“初始化”,并非技术流程的收尾,而是Spring对单例Bean所立下的根本誓约——它必须知情、必须就绪、必须可控;唯有如此,那个被注册进`singletonObjects`的引用,才不只是一个内存地址,而是一个真正可信赖、可追溯、可托付的运行时主体。** ## 四、循环依赖处理机制 ### 4.1 循环依赖的解决方案:Spring如何处理Bean之间的相互依赖 当两个单例Bean——A与B——彼此持有对方的引用,且均被声明为`@Scope("singleton")`时,一场静默的僵局便在内存中悄然形成:A的创建需等待B完成初始化,而B的创建又依赖A已就绪。若依循线性执行的直觉,这无异于一道无解的死锁命题。然而Spring并未退让,它以三级缓存为舟,以早期暴露为桨,在实例化与初始化之间劈开一道精微的时间缝隙——这并非妥协,而是一次对“完整性”定义的勇敢重写。源码逐行解析至`getSingleton`方法深处可见:当A进入`createBean`流程,在其实例化完成、属性填充尚未开始之际,Spring便将其“早期引用”(early reference)通过`ObjectFactory`封装,提前注册进`singletonFactories`;待B在依赖注入阶段尝试`getBean("a")`时,该工厂即被触发,返回一个尚未初始化但已具象的A对象,从而打破闭环。此时的A虽未经历`populateBean`与`initializeBean`,却已能作为合法依赖参与构建。这一设计不回避循环,而是将“依赖可用性”与“状态完备性”解耦——它承认系统本就生长于关系之网,因而选择在最克制的节点释放最必要的信任。**所谓解决,并非消灭依赖,而是为相互凝望的两个灵魂,预留一扇半开的门。** ### 4.2 三级缓存机制详解:如何保证单例Bean的唯一性与完整性 `singletonObjects`、`earlySingletonObjects`、`singletonFactories`——这三个键名朴素的`ConcurrentHashMap`,共同构筑了Spring单例管理中最富张力的三角结构。它们并非并列的存储仓库,而是一组严格时序化的生命快照:`singletonObjects`存放完全初始化完毕、可对外服务的终态单例;`earlySingletonObjects`缓存已实例化但未填充属性的“半成品”,供循环依赖场景即时取用;`singletonFactories`则更进一步,仅保存生成早期引用的`ObjectFactory`,是尚未落地的承诺本身。三者协同运作,由`addSingleton`、`addEarlySingletonObject`与`addSingletonFactory`三个原子操作精准调控,所有写入均受`synchronized`块保护,读取则依托`ConcurrentHashMap`的无锁特性实现高并发安全。源码逐行解析至此,我们终于看清:Spring对“唯一性”的捍卫,从不寄望于一把全局锁,而在于对生命周期每一毫秒的精确标注与分层托管——它允许一个Bean在不同阶段以不同形态存在,却绝不允许多个终态实例共存于`singletonObjects`。**这三级缓存,不是冗余的备份,而是时间维度上的精密分镜;它让“单例”二字,既承载语义的绝对性,也保有实现的弹性与尊严。** ## 五、Bean的生命周期终结与销毁机制 ### 5.1 Bean的销毁流程:destroy方法与DisposableBean接口 当一个单例Bean在Spring容器中走完其被创建、填充、初始化、注册的全部旅程,它便如一位被郑重加冕的臣子,立于`singletonObjects`的圣殿之中——然而,真正的庄严,不仅在于登临,更在于退场时的秩序与敬意。Spring并未将销毁视为创建的简单逆过程,而是一场有据可循、有章可依、有钩可挂的终局仪式。`DisposableBean`接口与`destroy-method`属性,正是这场仪式的两枚信物:前者是契约式的主动承诺,后者是配置化的被动声明。源码逐行解析至`AbstractBeanFactory`的`destroySingletons`调用链可见,当容器进入关闭流程,`DefaultListableBeanFactory`会遍历已注册的单例名称,对每个Bean执行`destroyBean`——它首先检查是否实现`DisposableBean`,若是,则调用`destroy()`;继而解析`destroy-method`配置,通过反射触发用户自定义的清理逻辑。尤为关键的是,这一过程严格遵循“后创建、先销毁”的逆序原则,且所有销毁操作均包裹于统一异常处理机制中,确保一处失败不阻断全局收尾。**这不是草率的清除,而是对生命周期完整性的最后确认:一个被Spring郑重托付过的对象,也必须被Spring郑重送别——销毁不是终结的句点,而是定义闭环的最后一笔。** ### 5.2 Spring容器关闭时的资源清理与Bean销毁顺序 容器关闭,从来不是一声令下后的集体湮灭,而是一场静默却严密的退场调度。当`AbstractApplicationContext.close()`被调用,`doClose()`方法即刻启动资源释放的倒计时:广播`ContextClosedEvent`通知监听者,撤销`LifecycleProcessor`的刷新状态,停止所有实现了`SmartLifecycle`的组件,最终调用`destroyBeans()`——这才是单例Bean集体谢幕的真正起点。此时,`DefaultListableBeanFactory`依据`disposableBeans`这个`LinkedHashMap`(其插入顺序即为Bean创建顺序)进行逆向遍历,确保依赖方总在被依赖方之后销毁,从而避免因引用失效导致的空指针或状态错乱。与此同时,`DisposableBeanAdapter`作为统一适配器,统一封装`DisposableBean.destroy()`、`@PreDestroy`方法及`destroy-method`的执行路径,并在每一步注入日志与异常兜底。值得注意的是,该过程全程不依赖任何外部线程池或异步机制,所有销毁动作均同步完成,以保障状态一致性。**当最后一行`removeSingleton`从`singletonObjects`中抹去那个熟悉的beanName,Spring所交付的,不只是内存的释放,更是一种不可妥协的契约精神——它曾以毫秒级精度守护每一次创建,亦以同等庄重,目送每一个单例走向它应属的终点。** ## 六、总结 本文以源码逐行解析为路径,系统揭示了Spring框架中单例Bean从定义注册到最终销毁的完整生命周期。通过深入追踪`AbstractBeanFactory`与`DefaultListableBeanFactory`等核心类的执行逻辑,清晰呈现了BeanDefinition加载、反射实例化、依赖注入、初始化回调、三级缓存协同及循环依赖破局等关键机制。整个过程凸显Spring在保证线程安全、状态可控与语义严谨之间的精妙平衡——单例并非简单“只创建一次”,而是在严格时序约束下,经由多阶段校验、钩子预留与异常兜底所达成的运行时契约。对`singletonObjects`、`earlySingletonObjects`与`singletonFactories`三级缓存的剖析,进一步印证了其设计内核:以时间维度分层托管对象状态,既捍卫单例唯一性,又不牺牲灵活性与可扩展性。源码即文档,流程即思想;唯有回归代码本身,方能真正理解Spring Bean管理的底层智慧与工程魄力。
最新资讯
英伟达GEAR实验室AutoResearch:AI自主科研新时代的开启
加载文章中...
客服热线
客服热线请拨打
400-998-8033
客服QQ
联系微信
客服微信
商务微信
意见反馈