1. 写在前面
上一小节,对Spring的整体面了解一二,这一小节我们将要对Spring的第一个部分,IoC 容器,进行学习。
2. IoC 容器概述
spring 的核心,是提供一个 IoC 容器,管理所有轻量级的 javaBean 组件。
这里的管理包括组件的生命周期、配置组装、AOP支持、声明式事务
2.1 什么是容器
容器是一个软件环境。
为了运行某种特定组件而提供必要支持的软件环境。
通常来说,容器除了提供运行需要的环境之外,还会提供一些基础的服务。比如, servlet 容器,底层实现了TCP链接、解析HTTP等这些复杂的功能,让人们在开发时不用再重新写这些基础的、但是又繁琐的代码。
2.2 什么是 javaBean
// 满足这样条件的就叫做 javaBean
Class Person{
private String name;
private Long age;
public String setName(String name){
this.name = name
}
public void getName(){
this.name = name;
}
}
javaBean 就是满足 privete 实例字段、public方法获取字段 的类。
简单来说就是有 get/set 的类。
再简单理解就是类。
3. 依赖倒置
各种概念之间的关系在学习 IoC 之前,需要理解一下 “依赖倒置原则”。
这里参考 依赖倒置链接
“依赖倒置” 的核心是,要让下层依赖于上层。
因为一般来说,上层设计是不会改变的,下层设计可以做一些修改
这里有一个例子:
这时候如果要更改底层的轮胎,那么所有依赖于底层轮胎的顶层设计,都需要更改,这种设计根本无法维护。
Class Computer{
private Keyboard keyboard;
Computer(){
this.keyborad = new Keyboard();
}
public void play(){
}
}
Class Keyboard{
}
这就是上层Computer依赖于下层Keyboard,如果这里的Keyboard需要修改,那么Computer中的构造函数也要修改,这样一层一层往上都要修改,不可能搞定。
下层依赖上层// 这是典型的依赖注入
Class Computer{
private Keyboard keyboard;
Computer(Keyboard keyboard){
this.keyborad = keyboard;
}
public void run(){}
}
Class Keyboard{
}
此时,下层类 keyboard 作为一个参数,被注入了上层Computer。即 上层控制下层。而不是之前的上层依赖下层。
两者区别的核心在于,不是由 computer 类直接自己new 一个 keyboard实例,而是从外部直接注入一个实例化之后的对象。
之后在 main() 方法中,需要多次实例化,因为要有底层的实例对象传入上层
Keyborad keyborad = new Keyborad();
Computer computer = new Computer(keyboard);
事实上,采取注入这种方式,去使用上层的对象(比如 Computer)的时候,需要将控制的下层对象都实例化一次。
在 spring 中,这样的工作由 IoC Container 完成的。我们只需要写
Computer = new Computer()
就行了。
4. IoC控制反转
IoC(Inversion of Control,控制反转),这是Spring中非常重要的一个思想。
我们思考下面两个问题:
- 什么是控制
- 谁控制谁,反转之后呢
4.1 控制反转前
看下面这两张图就可以理解这个事情:
1 - 控制反转前的耦合对象
作为互相协作的一个系统,不同的组件之间难免互相依赖,产生强耦合。每个Object 就是类。
这种高耦合系统,会有“牵一发而动全身”的问题。
4.2 控制反转后
2- 控制反转后的耦合对象控制反转后,引入了第三方来专门管理相互之间的依赖关系。
那么什么是控制呢,又为什么反转了呢?
当对象A使用到对象B时候:
- 反转前,需要在A类主动创建一个B类的对象。
- 反转后,当A需要使用到B类的对象时,由第三方IoC容器来创建一个B对象并且注入到A中。
可以看到,A对于依赖B的获取,从 “主动” 变成了 “被动”。
到这里,我们就可以回答上面提出的两个问题了。
控制是:对耦合对象的控制;反转是:控制权交给了第三方的IoC容器。
5. IoC 容器
Spring 中是由 IoC 容器来完成组件实例化的。
所以IoC 容器需要知道这些组件之间的关系,一般都是通过XML文件做的。
<beans>
<bean id="dataSource" class="HikariDataSource" />
<bean id="bookService" class="BookService">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="userService" class="UserService">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
一般来说,依赖注入通过 set() 方法或者构造方法。Spring 支持两者的混用。
网友评论