我们可以用一个"自动玩具工厂"的比喻来理解IoC容器的工作原理,这样会更加形象易懂。
想象你要开一家玩具工厂,首先需要:
在Spring中,这个阶段就是:
<!-- 相当于玩具设计图纸 -->
<bean id="teddyBear" class="com.example.TeddyBear">
<property name="eye" ref="blackEye"/> <!-- 需要黑色眼睛 -->
<property name="stuffing" ref="cotton"/> <!-- 需要棉花填充 -->
</bean>工厂需要:
现在开始生产玩具:
组装完成后:
public class TeddyBear implements InitializingBean {
@PostConstruct
public void addRibbon() {
System.out.println("给小熊系上蝴蝶结");
}
@Override
public void afterPropertiesSet() {
System.out.println("检查小熊缝线是否牢固");
}
}生产好的玩具会被:
当顾客想要小熊时,直接从展示柜拿样品,不用每次都重新生产(Spring默认返回同一个实例)
有些特殊需求:
当工厂关门时:
public class TeddyBear implements DisposableBean {
@PreDestroy
public void removeRibbon() {
System.out.println("解下蝴蝶结回收利用");
}
@Override
public void destroy() {
System.out.println("拆解小熊回收棉花");
}
}工厂步骤 | Spring IoC对应概念 | 具体表现 |
|---|---|---|
设计图纸 | Bean定义配置 | XML/注解声明哪些类需要被管理 |
原材料采购 | 组件扫描 | @ComponentScan扫描包路径 |
组装顺序 | 依赖解决 | 先实例化没有依赖的Bean,再逐步组装复杂对象 |
质检流程 | 生命周期回调 | @PostConstruct、InitializingBean、@PreDestroy、DisposableBean |
展示柜样品 | 单例池(Singleton Pool) | 默认情况下每个Bean只有一个实例 |
定制生产 | 作用域(Scope) | prototype/request/session等不同作用域 |
清洁工 | 容器关闭回调 | 调用所有Bean的销毁方法 |
假设我们要做一个游戏角色系统:
// 定义武器接口
public interface Weapon {
void attack();
}
// 具体武器实现
@Component // 放入工厂的"设计图纸"
public class Sword implements Weapon {
@Override
public void attack() {
System.out.println("剑击!");
}
}
// 角色类
@Component
public class GameCharacter {
private final Weapon weapon;
// 工厂会自动找到合适的Weapon实现注入
@Autowired
public GameCharacter(Weapon weapon) {
this.weapon = weapon;
}
public void fight() {
weapon.attack();
}
}工作流程:
就像玩具工厂自动完成了:
这样的设计让各个组件像积木一样可以灵活替换,比如把Sword换成Gun只需要改配置,不需要修改GameCharacter的代码。这就是IoC容器的魔力所在!