当前位置: 首页 > news >正文

Bean 的一生:从实例化到销毁的 12 个关键节点与扩展点

 欢迎来到“Spring 妇产医院”兼“职业介绍所”。很多开发者对 Bean 的理解停留在:“哦,加个 @Component,然后 @Autowired 就能用了。”哈哈 还是太天真了!

Bean 在 Spring 容器里的一生,比人类的成长史还要跌宕起伏。它要经历受孕、出生、认亲、培训、上岗、甚至退休

如果你不知道这些节点,你就会遇到这些灵异事件:

  • 灵异事件一@PostConstruct 里想注入某个 Bean,结果报 NullPointerException(因为它还没被注入呢!)。
  • 灵异事件二:想给所有 Bean 加个性能监控,结果改了 100 个类,累得半死(其实一个 BPP 就能搞定)。
  • 灵异事件三:Prototype 模式的 Bean,为什么 @PreDestroy 从来不执行?(容器:我只管生,不管养,更不管送终!)

今天,我们要拿着“生命监控仪”,全程跟踪一个 Bean 从 new 出来到被垃圾回收的12 个关键节点。准备好,我们要开始“接生”了!👶🏥

核心全景图:Bean 的“人生十二时辰”

     这 12 个节点,每一个都是你“搞事情”(插入自定义逻辑)的绝佳机会!一切的核心入口都在 AbstractAutowireCapableBeanFactory 类的 doCreateBean 方法中。让我们一段段拆开看

深度解析:关键节点的“内幕交易”

第一阶段:受孕与出生(实例化 & 属性填充)

1. 实例化 (Instantiation)
  • 动作:调用构造函数 new User()
  • 状态:此时对象是个“空壳”,属性全是 null
  • 如果检测到循环依赖,Spring 会立刻把一个 ObjectFactory 放入三级缓存,以便其他 Bean 急需时能拿到这个“半成品”。
  • 扩展点:通常不干预。除非你用 InstantiationAwareBeanPostProcessor 搞一些黑科技(比如返回一个代理对象代替真实对象,AOP 的雏形就在这)。

源码位置doCreateBean -> createBeanInstance

// AbstractAutowireCapableBeanFactory.java protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // ... 前置检查 ... // 1. 【实例化】调用构造函数 new Bean() // 如果是循环依赖,这里会提前暴露一个"早期引用" (Early Bean Reference) BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { // 清理工厂缓存 removeSingletonBeanDefinition(beanName); } // 核心:创建实例 (可能通过构造器推断,也可能通过工厂方法) instanceWrapper = createBeanInstance(beanName, mbd, args); // 获取刚new出来的原始对象 Object exposedObject = instanceWrapper.getWrappedInstance(); Class<?> exposedType = exposedObject.getClass(); // ... 合并 BeanDefinition ... // 【关键伏笔】如果是单例且允许循环依赖,提前暴露对象工厂 // 这就是解决循环依赖的第一步! boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { // 将对象工厂放入三级缓存 singletonFactories addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, exposedObject)); } // 继续后续流程... }
2. 属性填充 (Populating Bean Properties)
  • 动作:Spring 拿着 @Autowired@Value 的清单,把依赖塞进去。
  • 状态:对象有了依赖,但还没“觉醒”。

源码位置doCreateBean -> populateBean

// AbstractAutowireCapableBeanFactory.java protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { // ... 获取 PropertyValues ... // 【扩展点】InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation // 如果返回 false,将跳过属性填充 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; // 终止填充 } } } } PropertyValues pvs = mbd.getPropertyValues(); // 【核心】处理 @Autowired, @Value 注解 // 这里的处理器 AutowiredAnnotationBeanPostProcessor 实现了 InstantiationAwareBeanPostProcessor if (hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; // 关键:在这里解析注解并注入属性 PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { /* 兼容旧版本 */ } pvs = pvsToUse; }
http://www.jsqmd.com/news/504716/

相关文章:

  • 告别枯燥理论!用LabVIEW把2ASK、BPSK、QPSK调制波形‘画’出来,直观理解通信原理
  • 嵌入式C静态分析工具选型终极决策树(含MISRA-2012/2023、AUTOSAR C++14子集、IEC 61508 SIL3适配矩阵)
  • 【20年协议栈老兵亲授】:从TCP握手到MCP会话复用,5步榨干网络栈性能的最后一毫秒
  • DepthAnything(4): 基于TensorRT在Jetson平台实现DepthAnything模型的高效部署与性能优化
  • DeepAnalyze保姆级教程:阿里云ECS一键部署DeepAnalyze并绑定域名访问
  • Dify混合RAG召回率突然暴跌?3个被90%团队忽略的Chunking陷阱与实时监控SOP
  • 3分钟快速上手:NCMconverter让你的网易云音乐解锁播放自由
  • 万象熔炉·丹青幻境MySQL集成实战:生成内容的数据存储与管理
  • flask+python的农副产品商城交易平台的设计与开发
  • 单细胞多组学避坑指南:5个影响GRN推断准确性的关键因素(附GRETA测试数据)
  • Stable Fast 3D技术实战指南 - 从图片到3D模型的0.5秒魔法
  • 如何快速提升英雄联盟游戏体验:智能辅助工具的完整指南
  • 手把手拆解漫步者W820NB:BES2300芯片+驻极体麦克风,降噪原理全解析
  • Nacos高可用集群实战:从零搭建到微服务集成
  • Qwen2.5-VL-Ollama实战落地:政务办事截图理解+材料清单自动提取
  • Gerbv:免费开源的PCB制造文件终极验证工具
  • 【Matlab】MATLAB教程:数组拼接函数(案例:horzcat(A,B)、vertcat(A,B),聚焦批量数组拼接)
  • tts-vue离线语音合成四阶段优化指南:从环境搭建到性能倍增
  • Linux PCIe EPF驱动开发实战:从注册到DMA传输的完整流程(Kernel 5.15)
  • 循环卷积与线性卷积:从矩阵运算到信号处理实践
  • 边缘智算加速重构算力格局,微模块技术筑牢低延时基础设施底座
  • Z-Image-Turbo_UI界面保姆级教程:从启动到生成图片,手把手教你玩转AI绘画
  • 从零开始:如何用Python快速处理纹理识别数据集(FMD/DTD实战)
  • MATLAB代码解析:结合需求响应与动态热额定值,增强变压器储备及寿命
  • N8N与Dify:构建智能自动化工作流的黄金组合
  • 2026乐山地道油炸串串品牌优质推荐榜:乐山必吃的油炸、乐山本地人吃的油炸、乐山本地人小吃、乐山本地人推荐的小吃选择指南 - 优质品牌商家
  • 【Matlab】MATLAB教程:循环效率优化(案例:预分配数组 vs 动态扩展,聚焦提升循环速度)
  • Alist网盘美化实战:手把手教你打造个性化界面(附完整CSS代码)
  • Cadence实战手记(一):从零构建PCB封装库
  • 学校要求AI率低于20%,这几款软件都能达标