2. IOC
2.1. IOC基础
IOC: 控制反转. Inversion of Control, 需要明白谁控制谁, 控制什么, 为什么是反转, 反转了哪些方面
- 控制: IOC控制对象的创建, 控制了外部资源获取比如文件
- 反转: 容器来创建注入依赖对象, 对象被动的接收依赖对象, 所以是反转, 依赖对象的获取被反转了
IOC能做什么
- IOC是一种思想, 实现代码的解耦, 是的系统体系更加灵活, 由IOC来找到相应的依赖对象并且注入
IOC和DI
- DI—Dependency Injection,即 “依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
- 理解 DI 的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
- 谁依赖于谁:当然是某个容器管理对象依赖于 IoC 容器;“被注入对象的对象” 依赖于 “依赖对象”;
- 为什么需要依赖:容器管理对象需要 IoC 容器来提供对象需要的外部资源;
- 谁注入谁:很明显是 IoC 容器注入某个对象,也就是注入 “依赖对象”;
- 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
- IoC 和 DI 由什么关系呢?
- 其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以 2004 年大师级人物 Martin Fowler 又给出了一个新的名字:“依赖注入”,相对 IoC 而言,“依赖注入” 明确描述了 “被注入对象依赖 IoC 容器配置依赖对象”。
2.2. IOC容器基本原理
- IOC容器和Bean的概念:
- IOC容器:具有依赖注入功能的容器, 负责实例化, 定位, 配置应用程序中的对象和简历这些对象之间的依赖
- Spring中BeanFactory是IOC容器的实际代表
- Bean:IOC容器管理的对象统统叫做bean
- IOC容器:具有依赖注入功能的容器, 负责实例化, 定位, 配置应用程序中的对象和简历这些对象之间的依赖
- Spring中的IOC: BeanFactory接口
- BeanFactory接口提供IOC容器最基本的功能
- ApplicationContext接口拓展了BeanFactory接口
- 工作原理:
- 准备配置文件: 配置bean id 和对应class, 或许还有相关属性
- IOC容器解析元数据: 读取并解析配置文件, 根据配置文件实例化, 配置, 组装bean
- 实例化IOC: 由客户端实例化容器, 获取Bean
2.3. IOC配置使用
1. 配置xml文件: spring-ioc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- id为标识符, 用于区分bean, class指定bean的全限定名-->
<!-- 不指定 id,只配置必须的全限定类名,
由 IoC 容器为其生成一个标识,
客户端必须通过接口 “T getBean(Class<T> requiredType)” 获取 Bean;
-->
<bean class="cn.kuang.spring_example.ioc.bean.Bean1" />
<!-- 指定id, id在ioc容器中必须唯一 -->
<bean id="bean2" class="cn.kuang.spring_example.ioc.bean.Bean2" />
<!-- 指定name, name 就是标识符, 在IOC容器中唯一
同时指定id 和 name, id就是标识符, name就是别名, 都得唯一
如果id 和 name 一样, IOC能检测并且消除冲突
-->
<bean id="bean3" name="bean3" class="cn.kuang.spring_example.ioc.bean.Bean3" />
<bean id="bean4" name="bean,s,d,as,f,w,a" class="cn.kuang.spring_example.ioc.bean.Bean4" />
</beans>
2. bean类:
其他Bean也差不多, Bean名字换一下就行
使用lombok的@Data注解自动生成set, get, toString
@Data
public class Bean1 {
private String s = "Hello Bean1";
}
3. 测试类:
public class Test {
BeanFactory factory = new ClassPathXmlApplicationContext("spring-ioc.xml");
//测试没有设置id获取bean1
@org.junit.Test
public void test1(){
//根据类型获取
Bean1 b = factory.getBean(Bean1.class);
System.out.println(b);
}
//测试通过id获取bean2
@org.junit.Test
public void test2(){
Bean2 b = (Bean2) factory.getBean("bean2");
System.out.println(b);
}
}