1. IOC思想
IOC: Inversion of Control,即控制反转的意思。
传统方式: 主动从容器中获取所需资源。比如需要一个对象实例时候,需要手动去new一个。
控制反转:只需要说明需要什么资源即可。
DI:Dependency Injection,翻译过来是依赖注入。
以一些预先定义好的方式(例如:setter 方法, 构造函数)接受来自于容器的资源注入。相对于IOC而言,这种表述更直接。也就是说,使用的时候不需要自己手动去new。
IOC 就是一种反转控制的思想, 而 DI 是对 IOC 的一种具体实现。IOC创建对象,DI来给创建出来的对象属性赋值。
2. IOC 在Spring中的实现
Ctrl + H查看当前接口子类以及继承关系。
- BeanFactory
这是 IOC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用。 - ApplicationContext
BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用
ApplicationContext 而不是底层的 BeanFactory。 - ApplicationContext的主要实现类
类型名 简介
ClassPathXmlApplicationContext 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
FileSystemXmlApplicationContext 通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象
ConfigurableApplicationContext
ApplicationContext 的子接口,包含一些扩展方法refresh() 和 close() ,让 ApplicationContext 具有启动、关闭和刷新上下文的能力。
WebApplicationContext 专门为 Web 应用准备,基于 Web 环境创建 IOC 容器对象,并将对象引入存入 ServletContext 域中。
3、IOC创建对象方法
测试步骤
step1: 创建Module;
step2:pom中引入依赖
<packaging>jar</packaging>
<dependencies>
<!-- 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.1</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
step3: 项目中创建一个bean
package com.lucky.spring.bean;
public class HelloWorld {
public void sayHello() {
System.out.println("hello lucky");
}
}
step4:创建spring配置文件
xml文件中配置bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
配置HelloWorld所对应的bean,即将HelloWorld的对象交给Spring的IOC容器管理
通过bean标签配置IOC容器所管理的bean
属性:
id:设置bean的唯一标识
class:设置bean所对应类型的全类名
-->
<bean id="helloWord" class="com.lucky.spring.bean.HelloWorld"></bean>
<bean id="helloWord1" class="com.lucky.spring.bean.HelloWorld"></bean>
</beans>
step5: 构建测试类进行测试
@Test
public void helloTest() {
// ClassPathXmlApplicationContext 从工程目录获取资源
// 可以使用applicationContext.xml作为路径,是因为打包之后,resource路径下的文件和java文件下都被打包到了类路径
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
// 1、通过配置文件中id获取bean
HelloWorld helloWorld = (HelloWorld) ac.getBean("helloWord");
}
通过反射的方法,调用无参构造,删除无参构造,报错。
4、获取bean的三种方式
1、根据bean的id
// ApplicationContext 是一个接口,new一个该接口的实现类,来使用,这个接口还有一个实现类,是从磁盘目录来加载资源的
// ClassPathXmlApplicationContext 从工程目录获取资源
// 可以使用applicationContext.xml作为路径,是因为打包之后,resource路径下的文件和java文件下都被打包到了类路径
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
// 1、通过配置文件中id获取bean
HelloWorld helloWorld = (HelloWorld) ac.getBean("helloWord");
2、根据bean类型
HelloWorld helloWorld1 = ac.getBean(HelloWorld.class);
如果xml里面配置了两个不同id,针对同一个类型HelloWorld.class,如下:
<bean id="helloWord" class="com.lucky.spring.bean.HelloWorld"></bean>
<bean id="helloWord1" class="com.lucky.spring.bean.HelloWorld"></bean>
会报错,找到了两个,不唯一
配置文件不配置也会报错找不到
因此当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个。这种方法用的比较多,因为之后每种类型的bean一般情况下只配置一个id。
3. 通过类型和id一起获取
这个时候xml文件同一类型配置两个不同id也是可行的。
注意:
1、如果组件类实现了接口,根据接口类型可以获取 bean 吗?
可以,前提是bean唯一
2、如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?
不行,因为bean不唯一
根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看:『对象 instanceof 指定的类
型』的返回结果,只要返回的是true就可以认定为和类型匹配,能够获取到。