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

每次面试都被问,说说你对Spring IoC 和 DI的理解

没有 Spring 的时候,我们怎么写代码

先回忆一下"远古"时代的 Java 开发。

假如你有个UserService,里面要调UserDao去查数据库:

publicclassUserService{privateUserDaouserDao=newUserDao();// 自己 newpublicUsergetUserById(intid){returnuserDao.findById(id);}}

看起来没毛病对吧?

问题在哪呢——UserServiceUserDao死死绑在一起了。哪天你要换一个UserDao的实现(比如原本是 MySQL 版,现在要换成带缓存的),你就得去改UserService的代码。

一个两个还好,一个项目几百上千个类这么互相new,那耦合度简直就是一坨缠绕的耳机线,牵一发而动全身。

这就是Spring IoC 要解决的问题


IoC 到底是什么

IoC,全称 Inversion of Control,控制反转。

名字很唬人,其实就一句话:创建对象的控制权不要攥在自己手里,交给容器去管。

没有 IoC 之前:你自己new,你说了算。

有了 IoC 之后:你告诉 Spring “我需要什么”,Spring 帮你造好,你要用的时候直接从容器里拿。

翻译成人话:以前你吃饭得自己去买菜洗菜切菜炒菜,现在你只要把菜单丢给食堂,等着端盘子就行。

代码就变成了这样:

publicclassUserService{@AutowiredprivateUserDaouserDao;// 不用 new,Spring 帮你注入publicUsergetUserById(intid){returnuserDao.findById(id);}}

UserService只管用,不管建。谁建的?Spring 建的。怎么进来的?依赖注入进来的。


DI 依赖注入:IoC 的具体实现

IoC 是一种思想,DI(Dependency Injection)是这个思想的具体实现方式。

Spring 怎么知道UserService依赖了UserDao?你告诉它的——通过注解或者配置文件。然后 Spring 在创建UserService的时候,自动把UserDao注入进去。

Spring 支持三种注入方式:

1. 字段注入(最常用)

@AutowiredprivateUserDaouserDao;

最简洁,写起来方便,所以大家最爱用。贴个注解就完事了。

底层原理不复杂:Spring 通过反射拿到这个字段的Field对象,然后调用field.set(bean, 依赖对象),直接给属性赋值。

2. Setter 注入

@AutowiredpublicvoidsetUserDao(UserDaouserDao){this.userDao=userDao;}

底层是通过反射获取 setter 方法的Method对象,然后method.invoke(bean, 依赖对象)调用 setter 完成注入。

3. 构造器注入

@AutowiredpublicUserService(UserDaouserDao){this.userDao=userDao;}

底层是拿到有参构造器的Constructor对象,然后constructor.newInstance(依赖1, 依赖2...),创建 Bean 的同时就把依赖注进去了。

构造器注入目前是 Spring 官方推荐的方式。好处显而易见:依赖在对象创建时就强制到位,不会出现空指针,而且对单元测试友好——你直接new UserService(mockDao)就能测,不需要搞什么反射注入。


Bean 到底是怎么造出来的:反射是核心

不管哪种注入方式,底层都逃不开一个东西——反射

Spring 启动时的大概流程是这样的:

  1. 扫描:扫包,找到所有带@Component@Service@Repository@Controller之类注解的类,拿到全类名。

  2. 反射创建实例Class.forName(全类名)加载类,然后通过反射创建对象。

  3. 检查生命周期注解:如果方法上标了@PostConstruct,创建完 Bean 后执行;标了@PreDestroy,销毁 Bean 前执行。

  4. 依赖注入:检查字段、setter 方法、构造器上的@Autowired@Resource注解,把依赖的 Bean 注入进去。

  5. 放进容器:Bean 创建好了、依赖也注入了,放进 IoC 容器里(本质就是一个大的 Map),等着你用。

整个过程,反射从头忙到尾。


工厂模式:IoC 容器的外壳

从设计模式的角度看,IoC 容器就是一个超级工厂

普通的工厂模式,一个工厂负责创建一类对象。Spring 的 IoC 容器负责创建、组装、管理应用中所有 Bean 的生命周期。

你要用的时候,不需要知道这个 Bean 是怎么来的:

ApplicationContextcontext=newClassPathXmlApplicationContext("applicationContext.xml");UserServiceuserService=context.getBean(UserService.class);

或者现在更常见的,直接@Autowired注入:

@AutowiredprivateUserServiceuserService;

这就是工厂模式的威力——使用者不关心创建细节,只管拿成品


总结:串起来想一想

整个 Spring IoC 的运转逻辑就是一条线:

  1. 你通过注解或 XML告诉 Spring 哪些类是 Bean、Bean 之间谁依赖谁
  2. Spring 启动时用反射扫描你的配置,动态创建 Bean 实例
  3. 根据依赖关系,用反射把被依赖的 Bean 注入进去(setter / 构造器 / 字段三种方式)
  4. 处理@PostConstruct@PreDestroy等生命周期回调
  5. 把创建好的 Bean 放进IoC 容器(工厂模式的体现)
  6. 你需要用的时候,从容器里取就行了

理解了这一套,Spring Boot 自动配置、条件装配那些高级特性,本质上也是基于 IoC 容器做的扩展——万变不离其宗。


我是小饼干,如果这篇帮你理清了 IoC 和 DI,点个赞吧!。

http://www.jsqmd.com/news/867863/

相关文章:

  • GEO获客工具如何选择?
  • 在nodejs后端服务中集成taotoken多模型api的配置与调用示例
  • TEMU怎么注册开店?从0到上架的完整流程,新手看这一篇就够了 - 麦克杰
  • 电脑端OpenClaw v2026.5.9一键安装部署指南,小白0基础搭建方法
  • 如何用N_m3u8DL-CLI-SimpleG三步下载M3U8视频:免费图形化工具完整指南
  • 第一周学习笔记
  • 通信电源系统架构解析与运维实战:从核心原理到故障排查
  • GPT-5.5 编程辅助技巧:高效生成可复用代码
  • 宁波添元水泥制品有限公司荣膺2026年连锁片钢模综合服务商首 - 2026年企业推荐榜
  • 智能供应链革命——AI重塑泳装产业全链路
  • 花大钱买了GPU,Token却跑飞了?AI Infra的新战场在Token管理
  • 程序员如何平衡工作与生活?我的“时间块”管理法
  • 2026年至今,昆明珠宝评估服务市场如何选择专业服务伙伴? - 2026年企业推荐榜
  • 【大白话说Java面试题 第68题】【JVM篇】第28题:对于 JDK 自带的监控和性能分析工具用过哪些?一般你怎么用的?
  • 预测编码算法:sPC与ePC在数字硬件中的实现与优化
  • Python数据可视化实战:从Matplotlib到Plotly的完整指南
  • 实测百度网盘提速:从pandownload老玩家的视角,聊聊百度网盘不限速下载与解析的那些事
  • 《墨香情》手游官网入口:限时BOSS攻略,蹲点打法与掉落福利解析
  • Python 异步编程核心原理与实践深度解析
  • 5分钟上手京东自动抢购工具:Python脚本让限量商品轻松到手
  • harmonyos-ai-skill:让 Cursor 按 ArkTS 规范写鸿蒙,不再瞎编 API
  • Rust宏编程详解:从声明式到过程宏的完整指南
  • (十)工业数据采集与断点续传
  • 信息论压缩算法--香农码
  • 边缘AI加速:CGRA架构与近似计算技术解析
  • 医院门生产厂家10大品牌排名表最新图片
  • Agent Framework:理解关键区别
  • 智能体Prompt工程核心技巧:让 AI Agent Harness Engineering 精准理解复杂指令
  • 2026年,写给所有还在迷茫的技术人:你的坚持终将闪耀
  • 2026年企业AI智能体培训:高性价比服务商推荐指南