首先看一个例子,如果一个皇帝需要打仗,那他首先得让士兵去打仗
public class emperor implements king {
//引入了士兵的实例化对象
private Soldier soldier;
public emperor () {
this.soldier = new Soldier();
}
public void fight() {
//让士兵去打仗
soldier.doFight();
}
}
可以看到士兵和皇帝紧密的联系到了一起,当然这个在打仗的需求下是没问题的,但是当皇帝需要吃饭,上朝或者其他活动的情况下,那么这个皇帝类中引用的士兵实例是不是冗余没有作用的?这就导致这样的代码难以测试,难以理解,难以服用的问题,所以这就是DI要解决的问题。
DI的方式之一:
public class emperor implements king {
//引入了总的事务接口的实例
private Transaction transaction;
//通过构造器注入的方式注入实例,而且传入的类型对象是Transaction接口类型(皇帝吩咐的事情必须要实现Transaction接口,比如Soldier士兵类)
public emperor (Transaction transaction) {
this.transaction = transaction;
}
public void fight() {
//同样可以像上面的例子一样调用打仗函数
transaction.doFight();
}
}
这里Transaction接口是所有的事务(比如打仗,吃饭等等)必须要实现的接口,所在在这里运用java多态机制通过接口实例动态决定调用哪个对应实现类的方法。所以在这里我既可以调用士兵类去打仗,又可以调用宫女类去吃饭等等~ ~ ~
接下来我们再来看看如何将一个类注入到上面的皇帝类呢?我们来实现以下皇帝吃饭的类
//请注意,这里我们实现了Transaction接口
public class Eating implements Transaction {
//引入了总的事务接口(任何事务包括打仗等都需要实现该Transaction接口)
private PrintStream stream;
public emperor (PrintStream stream) {
this.stream = stream;
}
public void eat() {
//实现吃饭功能
stream.println("皇帝该吃饭了!!!");
}
}
ok,这里我写好了一个准备注入的类,那么有一个问题,之前我们是直接在皇帝类中实例化的对象,显然实际中这样肯定不行,那实际中我们如何将Eating吃饭动能交给皇帝呢?好吧,这个通过装配bean的方式来实现(xml配置或者基于java配置都可以),下面给出java的配置:
@Configuration
public class EmperorConfig {
@Bean
public King king () {
//实例化Emperor对象
return new Emperor(transaction());
}
@Bean
public Transaction transaction() {
//实例化Eating对象
return new Eating(System.out);
}
}
基于这个配置文件就是为了声明这个配置,spring会把之后的对象装配和组装完成的。内部实现原理暂时我们先不研究。。。
在spring程序调用使其工作起来:
public class EmperorMain {
public static void main(String[] args) {
ApplicationContext ctx =
new
AnnotationConfigApplicationContext(EmperorConfig.class);
Emperor emperor = ctx.getBean(Emperor.class);
emperor.eat();
ctx.close();
}
}
这样就彻底用spring依赖注入的方式实现了将士兵打仗和吃饭注入到皇帝类中,与最开始的例子相比就是这样做不是紧密耦合,而且复用性更好,我擦,java果然出了名的啰嗦(也可能我之前接触脚本语言更多),不过自己梳理了一下,理解棒棒哒的了~ ~ ~