Spring DI 解耦
什么是"解耦"
就是解开耦合的意思
既降低程序中的耦合性
什么是耦合性
所谓耦合性,就是两个类型的依赖关系是否可以替换
上次课程中关羽和青龙偃月刀的依赖关系就不能替换,这种情况就是紧耦合\高耦合
也因为不能替换带来了程序的扩展性降低
实现解耦的操作
如果想降低关羽和青龙偃月刀的耦合性,我们的做法是
声明一个接口或抽象类,作为青龙偃月刀的接口\父类
关羽不再依赖青龙偃月刀而依赖它的接口\父类,这个操作过程就能降低关羽和青龙偃月刀的耦合
首先编写一个武器(Weapon)接口
public interface Weapon {
public String getName();
}
青龙偃月刀类实现武器接口
@Component
public class DragonBlade implements Weapon {
private String name="青龙偃月刀";
//get set toString略
}
关羽类
@Component
public class GuanYu {
private String name="关云长";
//Weapon是一个接口,不能实例化
//@Autowired会自动从Spring容器中搜索实现了Weapon接口类型的对象
//例如现在得青龙偃月刀就是实现了Weapon接口的对象
@Autowired
private Weapon weapon;
public void fight(){
System.out.println(name+"使用"+weapon+"战斗");
}
//其它代码略
}
别忘了配置类
@ComponentScan("ouhe")
public class OuheConfig {
}
最后测试
@Test
public void ouheTest(){
GuanYu guanYu=acac.getBean("guanYu",GuanYu.class);
guanYu.fight();
}
输出:关云长使用青龙偃月刀战斗
我们看到输出结果是可以运行的
原因是虽然关羽类依赖Weapon接口,但是当前Spring容器中只有一把武器就是青龙偃月刀
下面我们再添加一把武器
方天画戟
@Component
public class SkyLancer implements Weapon{
private String name="方天画戟";
//set get toString 略
}
添加方天画戟之后,刚刚运行成功的测试类再运行,就会发生异常
原因是当前Spring容器有两个Weapon对象,id又没有匹配的,所以依赖注入失败
解决方案有两个
1.将关羽类中Weapon接口类型的属性名修改为其中一个对象的id
但是这个解决方案修改了属性名称,可能会引发一系列代码维护,比较不推荐
2.在@Autowired注解下添加一个注解
@Autowired
@Qualifier("skyLancer")
private Weapon weapon;
@Qualifier(“skyLancer”)表示下面的属性取值的Spring容器对象id为skyLancer
依赖注入解耦小结
1.耦合性是依赖关系产生的
2.依赖的类型如果是能够实例化对象的,就是高耦合
反之,依赖的类型如果不能实例化(接口或抽象类),这个依赖关系就是低耦合
我们追求低耦合的程序
3.今后我们在使用依赖注入时,类中的依赖类型尽量编写为接口或抽象类
保证程序良好的扩展性
@Bean和组件扫描混用
我们学习的@Bean注解将对象保存到Spring容器中和使用组件扫描保存到Spring容器中的对象都是互相可以使用的,并不隔离的
例如,我们再编写一个丈八蛇矛类(不适用@Component标记)
public class SnakeLancer implements Weapon {
private String name="丈八蛇矛";
}
在配置类中使用@Bean保存
@ComponentScan("ouhe")
public class OuheConfig {
@Bean
public Weapon snake(){
return new SnakeLancer();
}
}
实际上关羽类也是可以使用snake来获得丈八蛇矛来战斗的!
@Autowired
//使用@Bean保存到Spring容器中的武器snake
@Qualifier("snake")
private Weapon weapon;
测试类运行
输出:关云长使用丈八蛇矛战斗