spring-IOC(控制反转)
1.IOC是什么?
IOC(Inversion of Control, 控制反转)
●控制:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而Ioc是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建以及外部资源获取(不只是对象包括比如文件等)。
●反转:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象:由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转,依赖对象的获取被反转了。
IOC也叫依赖注入- DI
依赖注入:组件不做定位查询,让容器去决定依赖关系。容器全权负责的组件的装配,它会把符合依赖关系的对象通过属性或者构造函数传递给需要的对象。
常见的依赖注入实现有三种:构造方法注入、setter方法注入、接口注入等。
(1) 构造方法注入:即被注入对象可以通过在其构造方法中声明依赖对象的参数列表,让外部(通常是IOC容器)知道它需要哪些依赖对象,然后IOC容器会检查被注入对象的构造方法,取得其所需要的依赖对象列表,进而为其注入相应对象。
(2) setter方法注入:即当前对象只需要为其依赖对象所对应的属性添加setter方法,IOC容器通过此setter方法将相应的依赖对象设置到被注入对象的方式即setter方法注入。
(3) 接口注入:被注入对象如果想要IOC容器为其注入依赖对象,就必须实现某个接口,这个接口提供一个方法,用来为被注入对象注入依赖对象,IOC容器通过接口方法将依赖对象注入到被注入对象中去。相对于前两种注入方式,接口注入比繁琐和死板,被注入对象必须声明和实现另外的接口。
2.IOC是做什么的?
Ioc不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。
解耦:
解耦,是降低程序耦合度,也就是减少程序代码之间的依赖性,如果代码之间的依赖性很高,修改一处代码会影响很多其他的代码,这就给项目的稳定性带来的问题,不利于代码的扩展和维护。
没有IOC的程序中,我们使用new来完成对象的创建,如果需要的对象的类型发生改变,就需要手动修改代码。
有了IOC后,对象的创建由第三方(Spring容器)完成,由Spring来管理应用中所有对象的生命周期,开发者只需要关注自己的业务逻辑,代码更利于扩展和维护。
3.IOC容器
1.容器概念
IOC容器是 Spring 框架的核心。容器将创建对象,配置对象,并管理对象的整个生命周期。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。
2.容器的分类
Spring的IOC容器分为两种:
1.BeanFactory
最简单的容器,给 DI 提供了基本的支持,它用org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的与 Spring 整合的第三方框架的反向兼容性的目的。
2.ApplicationContext
继承了BeanFactory,添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。该容器是由 org.springframework.context.ApplicationContext 接口定义。通常推荐使用 ApplicationContext。
ApplicationContext 接口的主要实现:
- FileSystemXmlApplicationContext
基于文件系统中XML文件配置的应用程序上下文 - ClassPathXmlApplicationContext
基于ClassPath路径中XML文件配置的应用程序上下文 - AnnotationConfigApplicationConext
基于注解配置的应用程序上下文
4.IOC的应用
1.配置版
模拟电脑的装配,定义Cpu和Memory(内存)接口,Cpu接口有IntelCpu和AMDCpu两个实现类,Memory接口有KingstonMemory和SumsungMemory两个实现类,Computer类中定义了Cpu和Memory类型的两个属性
案例实现
1.创建Maven项目
2.导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
3.编写代码
/**
* CPU接口
*/
public interface Cpu {
void run();
}
public class AMDCpu implements Cpu {
public void run() {
System.out.println("AMD的CPU在运行。。。");
}
}
public class IntelCpu implements Cpu {
public void run() {
System.out.println("英特尔CPU在运行。。。");
}
}
/**
* 内存
*/
public interface Memory {
void read();
void write();
}
public class KingstonMemory implements Memory {
public void read() {
System.out.println("金士顿内存读取数据");
}
public void write() {
System.out.println("金士顿内存写入数据");
}
}
public class SumsungMemory implements Memory {
public void read() {
System.out.println("三星内存读取数据");
}
public void write() {
System.out.println("三星内存写入数据");
}
}
/**
* 电脑
*/
public class Computer {
private String brand;
private Cpu cpu;
private Memory memory;
public Cpu getCpu() {
return cpu;
}
public void setCpu(Cpu cpu) {
this.cpu = cpu;
}
public Memory getMemory() {
return memory;
}
public void setMemory(Memory memory) {
this.memory = memory;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void start(){
System.out.println(brand + "电脑启动了!");
cpu.run();
memory.read();
memory.write();
}
}
- 添加Spring配置文件
在resources目录下,添加Spring配置文件
<?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">
<bean id="cpu" class="com.blb.ioc_demo.AMDCpu"></bean>
<bean id="memory" class="com.blb.ioc_demo.KingstonMemory"></bean>
<!--Java对象配置-->
<bean id="computer" class="com.blb.ioc_demo.Computer">
<property name="brand" value="联想"></property>
<property name="cpu" ref="cpu"></property>
<property name="memory" ref="memory"></property>
</bean>
</beans>
结果展示
2.注解版
-
@Component 组件,被标记的类会被Spring扫描到,交给Spring容器进行管理
-
@ComponentScan 组件扫描,标记在配置类上,用于扫描某一个包下带@Component的类
-
@Configuration 配置类,标记在类上,该类作为配置类代替XML
-
@Value 注入值类型数据,配置属性或set方法上
-
@Autowried 自动装配,默认按类型进行注入
-
@Qualifier 标记名称,配置在类和注入属性上,用于区分类型相同的对象
-
@Resource 自动装配,类似Autowired,默认按名称注入,名称没有再按类型注入
-
@Repository 类似@Component,标记DAO实现类
-
@Service 类似@Component,标记Service实现类
-
@Controller 类似@Component,标记Controller类
修改上面的案例:
@Component
public class AMDCpu implements Cpu {
public void run() {
System.out.println("AMD的CPU在运行。。。");
}
}
@Component
public class KingstonMemory implements Memory {
public void read() {
System.out.println("金士顿内存读取数据");
}
public void write() {
System.out.println("金士顿内存写入数据");
}
}
@Component
public class Computer {
@Value("戴尔")
private String brand;
@Autowired
private Cpu cpu;
@Autowired
private Memory memory;
/**
* 配置类
*/
@ComponentScan(basePackages = "com.blb.ioc_demo")
@Configuration
public class ComputerConfig {
public static void main(String[] args) {
//创建注解应用程序上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ComputerConfig.class);
//获得对象
Computer computer = context.getBean(Computer.class);
computer.start();
}
}