控制反转与依赖注入
# 控制反转与依赖注入
先只介绍概念,更深入的东西以后有时间在研究。
# 控制反转概念
在传统的方式中,如果我们要用到一个类的对象,需要自己 new
一个出来,例如:
public void testMaster() {
// 自己 new 一个对象
Master master = new Master();
master.sayHello();
}
1
2
3
4
5
2
3
4
5
而在 Spring 中,我们看不到 new Master()
的操作,而是通过 Spring 的 ApplicationContext 获得,例如:
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// 不是自己 new 的对象,而是从 ApplicationContext 中获得
// 其中,getBean 方法的参数值是 "master",对应的是 xml 中 bean 的 id
Master master = (Master) context.getBean("master");
1
2
3
4
2
3
4
可见:
- 在传统的方式中,
master
对象的创建和销毁是由应用程序负责的,其控制权属于应用程序(上面的testMaster
方法)。 - 而在 Spring 中,
master
对象的创建和销毁是由 Spring 负责的,其控制权属于 Spring 而不属于控制者。
这个过程就叫做控制反转(Inversion of Control,缩写为 IoC)。
# 依赖注入概念
下面的代码是使用 Spring 框架时很常见的:
@Resource
private Master master;
1
2
2
这里我们没有手动使用 getBean()
,而是通过注解的形式获得了这个 bean。对于应用程序来说,我所使用的这个对象不是我创建的,是 Spring 帮我创建的,并且我能从 Spring 中得到它。
这个过程就叫做依赖注入(Dependency Injection,简称 DI)。
# 区别
控制反转与依赖注入其实说的是一回事,即:Spring 容器帮我们去管理对象。
区别在于它们站的角度不同:
- 控制反转指的是被创建的对象,它的控制权交给了 Spring。
- 依赖注入指的是在应用程序的角度,我们用到的对象不是自己创建的,而是 Spring 给我们的。
这样会带来很多好处,比如数据库相关的场景,数据是怎么打开的、怎么关闭的、怎么放回到连接池的、怎么提交事务的,这些东西应用程序都不用管,Spring 都会帮我们去做。
# 为什么要控制反转
IoC 把对象生成放在了 XML 里定义,所以当我们需要换一个实现子类时将会变得很简单(一般这样的对象都是实现于某种接口的),只要修改 XML 就可以了。
举个例子:
猫和狗都是宠物,猫是喵喵叫,狗是汪汪叫。在 pojo 包下有三个类,Pet,Dog,Cat:
package pojo;
public abstract class Pet {
// 动物都会叫,可叫声不同,所以方法是抽象的
public abstract void shout();
}
1
2
3
4
5
6
2
3
4
5
6
package pojo;
public class Cat extends Pet {
@override
public void shout() {
System.out.println("喵喵");
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
package pojo;
public class Dog extends Pet {
@override
public void shout() {
System.out.println("汪汪");
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
现在的应用程序代码中,是听猫叫:
@Test
public void testPet() {
Pet pet = new Cat();
pet.shout();
}
1
2
3
4
5
2
3
4
5
如果需求更改,要听狗叫了,那么业务代码就要修改:
@Test
public void testPet() {
Pet pet = new Dog();
pet.shout();
}
1
2
3
4
5
2
3
4
5
这种情况下,Cat 类和 Dog 类就和业务是紧密耦合的。用 Spring 可以降低这种耦合,如果需求变更,只需要修改 xml 文件:
<bean id="pet" class="pojo.Cat"></bean>
1
修改为
<bean id="pet" class="pojo.Dog"></bean>
1
而业务代码不需要修改:
@Test
public void testPet() {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
Pet pet = context.getBean(Pet.class);
pet.shout();
}
1
2
3
4
5
6
2
3
4
5
6
# 优缺点
IoC 的缺点是:
- 生成一个对象的步骤变复杂了,对于不习惯这种方式的人,会觉得有些别扭和不直观。
- 对象生成因为是使用反射编程,在效率上有些损耗。但相对于 IoC 提高的维护性和灵活性来说,这点损耗是微不足道的,除非某个对象的生成对效率要求特别高。
(完)