【Spring进阶】Spring IOC实现原理是什么?容器创建和对象创建的时机是什么?

【Spring进阶】Spring IOC实现原理是什么?容器创建和对象创建的时机是什么?



👨‍💻程序员三明治个人主页
🔥 个人专栏: 《设计模式精解》《重学数据结构》

🤞先做到 再看见!


Bean的生命周期

在这里插入图片描述

1️⃣** 初始化容器**

ApplicationContext ctx =newClassPathXmlApplicationContext("applicationContext.xml");
  • ApplicationContextBeanFactory 的子接口;
  • 它在启动(refresh())时会完成 配置加载 + Bean 注册 + Bean 实例化
  • 这是一个预加载容器(启动即创建 Bean)。

⚠️ 与之相对的 BeanFactory 是延迟加载容器,只有在第一次调用 getBean() 时才会创建对象。

2️⃣** 解析配置并生成 BeanDefinition**

Spring 首先会读取配置文件(如 XML 或注解),解析 <bean> 标签中的定义,例如:

<beanid="myBean"class="com.example.MyBean"scope="singleton"/>

这些信息会被封装成 BeanDefinition 对象,描述 Bean 的元数据,包括:

属性说明
idBean 的唯一名称
classBean 的全类名
scope作用域(singleton / prototype)
constructor args / properties依赖信息

BeanDefinition 不是 Bean 实例,而是告诉容器“如何创建 Bean”的蓝图。


3️⃣** 注册 BeanDefinition**

Spring 将所有的 BeanDefinition 注册到一个全局的注册表中:

Map<String,BeanDefinition> beanDefinitionMap =newConcurrentHashMap<>(); beanDefinitionMap.put("myBean",BeanDefinition@1234);

📘 这一步只完成定义注册,还没有实例化对象。

当容器启动(ApplicationContext)或首次 getBean()BeanFactory)时,Spring 开始真正创建对象。
无论触发方式如何,最终都会进入相同的调用链:

MyBean bean = ctx.getBean("myBean");getBean() └── doGetBean() ├── getSingleton()// 从缓存中查找是否已创建 ├── createBean()// 未创建则进入创建流程 │ ├── createBeanInstance()// 反射实例化对象 │ ├── populateBean()// 依赖注入 │ └── initializeBean()// 初始化回调 └── addSingleton()// 放入缓存池

1️⃣** createBeanInstance():反射创建对象**

Class<?> clazz =Class.forName(beanDefinition.getBeanClassName());Object bean = clazz.getDeclaredConstructor().newInstance();
  • Spring 使用 反射 动态创建 Bean 实例;
  • 这一步只负责实例化,不注入依赖;
  • 对象创建后暂存在缓存中,等待依赖注入。

2️⃣** populateBean():执行依赖注入**

Spring 会根据 BeanDefinition 或注解信息完成依赖注入。
常见的三种方式:

注入方式示例实现方式
构造器注入<constructor-arg>反射调用构造器
Setter 注入<property>反射调用 setter 方法
字段注入@Autowired
/ @Resource
反射直接设置字段值

示例:

@ComponentpublicclassMyBean{@AutowiredprivateMyService myService;}

底层反射逻辑:

Field field = clazz.getDeclaredField("myService"); field.setAccessible(true); field.set(bean, context.getBean("myService"));

3️⃣** initializeBean():初始化与回调**

依赖注入完成后,Spring 会执行初始化回调,包含:

  1. 调用 BeanNameAwareApplicationContextAware 等接口;
  2. 执行 InitializingBean.afterPropertiesSet()
  3. 调用 init-method
  4. 触发 BeanPostProcessor(如 AOP 代理增强)。

4️⃣** addSingleton():放入单例缓存**

当 Bean 完全创建完毕后,Spring 会将其放入一级缓存:

singletonObjects.put(beanName, bean);

这样之后再次 getBean("myBean"),会直接从缓存中取,不再重新创建。

1️⃣ 读取配置文件或扫描注解 ↓ 2️⃣ 生成 BeanDefinition(Bean 蓝图) ↓ 3️⃣ 注册到 beanDefinitionMap(定义注册) ↓ 4️⃣ 调用 getBean() 或 容器启动触发创建 ↓ 5️⃣ createBean() → 反射创建对象 ↓ 6️⃣ populateBean() → 执行依赖注入 ↓ 7️⃣ initializeBean() → 初始化与增强 ↓ 8️⃣ addSingleton() → 缓存单例 Bean ↓ 9️⃣ 返回 Bean 实例 

说说BeanFactory和ApplicantContext?

可以这么形容,BeanFactory是Spring的“心脏”,ApplicantContext是完整的“身躯”。

  • BeanFactory(Bean工厂)是Spring框架的基础设施,面向Spring本身。
  • ApplicantContext(应用上下文)建立在BeanFactoty基础上,面向使用Spring框架的开发者。

Spring为BeanFactory提供了很多种实现,最常用的是XmlBeanFactory,但在Spring3.2中已被废弃,建议使用XmlBeanDefinitionReader、DefaultListableBeanFactory。

BeanFactory接口位于类结构树的顶端,它最主要的方法就是getBean(String var1),这个方法从容器中返回特定名称的Bean。

BeanFactory的功能通过其它的接口得到了不断的扩展,比如AbstractAutowireCapableBeanFactory定义了将容器中的Bean按照某种规则(比如按名字匹配、按类型匹配等)进行自动装配的方法。

这里看一个 XMLBeanFactory(已过期) 获取bean 的例子:

ApplicationContext 接口

ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。可以这么说,使用BeanFactory就是手动档,使用ApplicationContext就是自动档。

ApplicationContext 继承了HierachicalBeanFactory和ListableBeanFactory接口,在此基础上,还通过其他的接口扩展了ApplicationContext的功能,包括:

  • Bean instantiation/wiring
  • Bean 的实例化/串联
  • 自动的 BeanPostProcessor 注册
  • 自动的 BeanFactoryPostProcessor 注册
  • 方便的 MessageSource 访问(i18n)
  • ApplicationEvent 的发布与 BeanFactory 懒加载的方式不同,它是预加载,所以,每一个 bean 都在 ApplicationContext 启动之后实例化

这是 ApplicationContext 的使用例子:

ApplicationContext 包含 BeanFactory 的所有特性,通常推荐使用前者。

如果我的内容对你有帮助,请辛苦动动您的手指为我点赞,评论,收藏。感谢大家!!

在这里插入图片描述


我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=h70g0sv71wz

Read more

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

摘要:本文聚焦OpenClaw从测试环境走向生产环境的核心痛点,围绕“性能优化、安全加固、监控运维”三大维度展开实操讲解。先明确生产环境硬件/系统选型标准,再通过硬件层资源管控、模型调度策略、缓存优化等手段提升响应速度(实测响应效率提升50%+);接着从网络、权限、数据三层构建安全防护体系,集成火山引擎安全方案拦截高危操作;最后落地TenacitOS可视化监控与Prometheus告警体系,配套完整故障排查清单和虚拟实战案例。全文所有配置、代码均经实测验证,兼顾新手入门实操性和进阶读者的生产级部署需求,帮助开发者真正实现OpenClaw从“能用”到“放心用”的跨越。 优质专栏欢迎订阅! 【DeepSeek深度应用】【Python高阶开发:AI自动化与数据工程实战】【YOLOv11工业级实战】 【机器视觉:C# + HALCON】【大模型微调实战:平民级微调技术全解】 【人工智能之深度学习】【AI 赋能:Python 人工智能应用实战】【数字孪生与仿真技术实战指南】 【AI工程化落地与YOLOv8/v9实战】【C#工业上位机高级应用:高并发通信+性能优化】 【Java生产级避坑指南:

By Ne0inhk
ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

🎬 渡水无言:个人主页渡水无言 ❄专栏传送门: 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》 ❄专栏传送门: 《freertos专栏》《STM32 HAL库专栏》 ⭐️流水不争先,争的是滔滔不绝  📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生 | 省级优秀毕业生获得者 | ZEEKLOG新星杯TOP18 | 半导纵横专栏博主 | 211在读研究生 在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连 目录 前言  一、实验基础说明 1.1、互斥体简介 1.2 本次实验设计思路 二、硬件原理分析(看过之前博客的可以忽略) 三、实验程序编写 3.1 互斥体 LED 驱动代码(mutex.c) 3.2.1、设备结构体定义(28-39

By Ne0inhk
Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 后端工程师扔给你一个 Swagger (OpenAPI) 文档地址,你会怎么做? 1. 对着文档,手写 Dart Model 类(容易写错字段类型)。 2. 手写 Retrofit/Dio 的 API 接口定义(容易拼错 URL)。 3. 当后端修改了字段名,你对着报错修半天。 这是重复劳动的地狱。 swagger_dart_code_generator 可以将 Swagger (JSON/YAML) 文件直接转换为高质量的 Dart 代码,包括: * Model 类:支持 json_serializable,带 fromJson/

By Ne0inhk
Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

文章目录 * 前言 * make/makefile * 文件的三个时间 * Linux第一个小程序-进度条 * 回车和换行 * 缓冲区 * 程序的代码展示 * git指令 * 关于gitee * Linux调试器-gdb使用 * 作业部分 前言 做 Linux 开发时,你是不是也遇到过这些 “卡脖子” 时刻?写 makefile 时,明明语法没错却报错,最后发现是依赖方法行没加 Tab;想提交代码到 gitee,记不清 git add/commit/push 的 “三板斧”,还得反复搜教程;用 gdb 调试程序,输了命令没反应,才想起编译时没加-g生成 debug 版本;甚至连写个进度条,都搞不懂\r和\n的区别,导致进度条乱跳…… 其实这些问题,

By Ne0inhk