一、先理解"传统方式"的痛点
假设你要开一家奶茶点,你需要杯子、吸管、奶茶粉、封口机......
传统写法(自己new对象)
java
public class MilkTeaShop {
private Cup cup = new Cup(); // 自己买杯子
private Straw straw = new Straw(); // 自己买吸管
private MilkTeaPowder powder = new MilkTeaPowder(); // 自己买奶茶粉
}
问题很明显:
- 每开一家奶茶店都要重新采购一遍,累
- 想换供应商(换实现类),要改代码
- 杯子、吸管、奶茶粉之间谁依赖谁,乱成一团
- 东西用完就扔,没法复用
二、IoC是什么?
IoC = Inversion of Control,控制反转。
简单说就是:把"创建对象、管理对象"的活儿,交给一个专门的"管家"去做,你只管用。
还是奶茶店,现在你雇了一个仓库管理员(Spring 容器) :
- 你告诉管理员:"我需要杯子、吸管、奶茶粉"
- 管理员提前把这些东西采购好、摆放好、维护好
- 你要用的时候,直接问管理员拿就行
"控制反转"反转的是什么?是"创建对象"的控制权------从你自己手里,反转到了 Spring 容器手里。
三、IoC 容器:Spring 的"大仓库"
Spring 的 IoC 容器就是一个对象仓库,它负责:
- 创建对象(不用你 new)
- 管理对象(存起来、复用)
- 装配依赖(A 需要 B,自动把 B 塞给 A)
这些被容器管理的对象,就叫 Bean。
四、Bean管理:三步走
第1步:告诉容器"我要管理哪些对象"
方式一:注解(最常用)
less
@Component // 告诉 Spring:这个类交给你管
public class Cup {
}
@Service // 业务层常用
public class MilkTeaService {
}
@Repository // 数据层常用
public class MilkTeaDao {
}
这几个注解本质一样,只是语义不同,方便区分层次。
方式二:配置类里手动注册
typescript
@Configuration
public class AppConfig {
@Bean // 手动告诉容器:这个方法返回的对象你管起来
public Cup cup() {
return new Cup();
}
}
第2步:告诉容器"谁需要谁"(依赖注入)
typescript
@Service
public class MilkTeaService {
@Autowired // 告诉 Spring:帮我自动把 Cup 塞进来
private Cup cup;
public void makeTea() {
cup.use(); // 直接用,不用自己 new
}
}
这叫依赖注入(DI,Dependency Injection) ,是 IoC 的具体实现方式。你不用管 Cup 从哪来,Spring 自动给你。
补充:现在更推荐构造器注入:
kotlin
@Service
public class MikeTeaService {
private final Cup cup;
public MilkTeaService(Cup cup) { // Spring 自动传进来
this.cup = cup;
}
}
第 3 步:从容器里拿对象用
arduino
@SpringBootApplication
public class App {
public static void main(String[] args) {
// 启动 Spring,创建容器
ApplicationContext ctx = SpringApplication.run(App.class, args);
// 从容器里拿 Bean
MilkTeaService service = ctx.getBean(MilkTeaService.class);
service.makeTea();
}
}
整个过程就这张图
你:@Component 标注 Cup → Spring:好,我管了,存起来
你:@Autowired 要 Cup → Spring:给你,拿去用
五、核心一句话
IoC 就是"别自己 new,让 Spring 帮你 new 并管好";Bean 就是被 Spring 管起来的那些对象;依赖注入就是 Spring 自动把对象之间需要的依赖"喂"进去。
好处:解耦、可复用、好测试、好维护------换实现、加功能,改配置就行,不用动业务代码。