一、前言
在学习 Spring Boot 的过程中,我们几乎每天都会写:
java
@Autowired
private UserService userService;
但很多人会有疑问:
为什么不用 new?
为什么接口也能注入?
IoC 和 DI 到底是什么关系?
👉 本文将从直觉 → 原理 → 工程实践,彻底讲清楚:
IoC(控制反转)与 DI(依赖注入)
二、没有 IoC 的世界(传统写法)
先看最原始的代码:
java
UserService userService = new UserServiceImpl();
userService.register(dto);
你在做什么?
✔ 自己决定用哪个实现类
✔ 自己创建对象(new)
✔ 自己管理依赖关系
👉 本质:
程序员掌控一切(控制权在你)
问题在哪?
❌ 强耦合(绑定具体实现)
❌ 不易扩展(换实现要改代码)
❌ 不易测试(难 mock)
❌ 代码维护成本高
三、引入 IoC(控制反转)
在 Spring 中,我们写:
java
@Autowired
private UserService userService;
发生了什么?
✔ 没有 new
✔ 没有指定实现类
✔ 直接可以用
👉 实际上:
Spring 创建了对象
Spring 管理对象
Spring 把对象交给你
控制权发生了变化
❌ 之前
你 → 控制对象创建
✅ 现在
Spring → 控制对象创建
你 → 被动使用
👉 这就是:
控制反转(IoC:Inversion of Control)
四、IoC 到底是什么?
定义
IoC 是一种设计思想:将对象的创建与管理交给容器,而不是由程序员手动控制
核心思想
不自己 new,对象由框架管理
本质
控制权反转(你 → Spring)
五、DI(依赖注入)是什么?
定义
DI(Dependency Injection)是将对象依赖注入到使用方的一种机制
示例
java
@Autowired
private UserService userService;
👉 意味着:
Spring 把 UserServiceImpl 注入进来
通俗理解
你不创建对象,Spring 主动"塞给你"
六、IoC 与 DI 的关系(重点)
标准表述
IoC 是一种思想
DI 是实现 IoC 的一种方式
更严谨说法
DI 是 IoC 最常见的实现方式
关系图
IoC(思想)
├── DI(依赖注入)✔ 主流
└── DL(依赖查找)❌ 较少使用
七、DI 的两种方式(补充理解)
1️⃣ 依赖注入(DI)
java
@Autowired
UserService userService;
👉 Spring 自动给你对象 ✔
2️⃣ 依赖查找(DL)
java
UserService userService = context.getBean(UserService.class);
👉 自己去容器里拿 ❌(不推荐)
八、为什么要用 IoC / DI?
✔ 1️⃣ 解耦
只依赖接口,不依赖实现
✔ 2️⃣ 可扩展
随时替换实现类
✔ 3️⃣ 可测试
方便 Mock(测试替换)
✔ 4️⃣ 可维护
代码结构清晰
九、面向接口编程(关键补充)
为什么注入接口?
java
@Autowired
private UserService userService;
👉 而不是:
java
@Autowired
private UserServiceImpl userService;
原因:
✔ 解耦
✔ 灵活替换实现
✔ 企业级标准
👉 Spring 实际注入的是:
UserServiceImpl 对象 ✔
十、工程级理解
你写:
java
@Autowired
UserService userService;
👉 实际表达的是:
我只依赖"能力"(接口)
具体实现由 Spring 决定
👉 这背后是:
IoC + DI + 面向接口编程
十一、一句话总结
IoC 是控制权反转的思想,DI 是将依赖对象注入到使用方的一种实现方式,两者共同实现了低耦合的系统设计
十二、结语
很多人停留在:
会用 @Autowired
但真正的工程能力在于:
理解 IoC 背后的设计思想
从:手动控制对象 - > 到:交给框架管理对象
这是一次非常重要的认知跃迁。