Spring的IOC控制反转和依赖注入
Spring的IOC控制反转和依赖注入
重点-spring核心之一
IoC:Inverse of Control(控制反转):
读作“反转控制”,更好理解,不是什么技术,而是一种设计思想,好比于MVC。就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。
正控:若调用者需要使用某个对象,其自身就得负责该对象的创建。
反控:调用者只管负责从Spring容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了Spring框架。
(Don’t call me ,I’ll call you)
DI:Dependency Injection(依赖注入)
从字面上分析:
IoC:指将对象的创建权,反转给了Spring容器;
DI :指Spring创建对象的过程中,将对象依赖属性(简单值,集合,对象)通过配置设值给该对象。
IoC和DI其实是同一个概念的不同角度描述,DI相对IoC而言,明确描述了“被注入对象依赖IoC容器配置依赖对象”。
Container:容器,在生活中容器就是一种盛放东西的器皿,从程序设计角度看作是装对象的对象,因为存在对对象的存入、取出等操作,所以容器还要管理对象的生命周期。
IoC(控制反转)的概述
Spring号称是一个可以实现模块可插拔的JavaEE开发框架。那么它是如何实现程序的可插拔的呢?
实现程序可以插拔的核心理念就是,控制反转(Inversion of Control,英文缩写为IoC)
所谓的控制反转,就是将代码的调用权从调用方转移给被调用方(服务提供方)。
如图所示:
- 强耦合调用方式
将A调用B的对象修改为C类的对象,修改的是调用方的代码,所以我们认为代码的调用权在调用方。
- 基于IoC(控制反转)的调用方式
将上图的需求,修改为使用Ioc的调用代码方式。就是将代码的控制权从调用方修改为被调用方,意味着,代码的调用权转移给被调用方(我们也称为服务方),不用修改调用方的的代码
只要修改配置文件就实现对象的切换。
如下图:将A类调用B类的对象修改为C类的对象,修改的是被调用方的配置文件的代码,所以代码的调用权转移到了被调用方。通过控制反转,我们可以实现增加模块或者移除模块统一由配置文件关联,增加或者移除模块,配置XML配置文件即可。
我们将代码的调用权(控制权)从调用方转移给被调用方(服务提供方)的设计模式称为控制反转(IoC)
根据上图可以的得出,实现一个IoC的框架,必须要解决两个问题:
1.被调用方(服务方),在程序启动时就要创建好对象,放在一个容器里面。
2.调用方使用一个接口或类的引用(不用使用new),就可以创建获得对象。
我们将这种不用new,而是根据接口或者类的引用就可以从被调用的容器里获得创建的对象的方式称为依赖注入。
所以,控制反转(Ioc),就是依赖注入加上面向接口的编程思想的实现。
在这里,我们首先抓住一个重点:Spring之所以可以实现可插拔程序,是实现了不用new,使用类或接口就可以获得获得对象!
项目目录结构
示例代码
CustomerService接口代码
package cn.xc.spring.service;
public interface CustomService {
/**
* 保存方法
*/
public void save();
}
CustomerServiceImpl子类
package cn.xc.spring.service.impl;
import cn.xc.spring.service.CustomService;
public class CustomServiceImpl1 implements CustomService {
@Override
public void save() {
System.out.println("CustomServiceImpl1.save()");
}
}
CustomerServiceImpl2子类
package cn.xc.spring.service.impl;
public class CustomServiceImpl2 implements cn.xc.spring.service.CustomService {
@Override
public void save() {
System.out.println("CustomServiceImpl2.save()");
}
}
CustomerClient类(调用方)
package cn.xc.spring.client;
import cn.xc.spring.service.CustomService;
public class CustomClient {
private CustomService service;
public void save() {
service.save();
}
//此set方法是给Spring 依赖注入使用的方法(set方法注入,属性注入
public void setCustomService(CustomService service) {
this.service = service;
}
}
配置文件applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
<bean id="" class=""></bean>
Spring管理对象的标签,只要那个类在Spring配置,就被Spring框架管理
id:唯一标识
class :被管理类(对象)的全限定名
-->
<!-- 配置 CustomClient -->
<!--
IOC : 将对象的创建权交个Spring
Class<CustomClient> clz = Class.forName("cn.xc.spring.client.CustomClient")
CustomClient obj = clz.newInstance();
-->
<bean id="client" class="cn.xc.spring.client.CustomClient">
<!-- DI :依赖注入(sett方法注入,属性注入)
<property name=""></property>
name:要注入的属性名称
注意:属性不是成员变量,属性是由get或者set方法去掉set/get前缀,剩余部分首字母小写
value :值类型的设置(字符串,基本数据类型)
ref: 引用类型的设置,直接写对应数据类型在Spring中配置的id即可
-->
<property name="customService" ref="service1"></property>
</bean>
<!-- 配置CustomServiceImpl1 -->
<bean id="service1" class="cn.xc.spring.service.impl.CustomServiceImpl1"></bean>
<!-- 配置CustomServiceImpl2 -->
<bean id="service2" class="cn.xc.spring.service.impl.CustomServiceImpl2"></bean>
</beans>
测试代码
package cn.xc.spring.test;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.xc.spring.client.CustomClient;
public class SpringTest {
@Test
public void testName() throws Exception {
// 1.读取Spring配置文件,启动Spring框架,创建Spring容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2.从容器获取 CustomClient
CustomClient customClient = context.getBean("client", CustomClient.class);
customClient.save();
}
}