Spring IOC的基本概念
- 控制反转(inversion of Control,IoC)是一个比较抽象的概念,是Spring框架的核心,用来消减计算机的耦合问题。依赖注入(DI)是IOC另一种说话,只是从不同的角度描述相同的概念。下面通过一个实际列子来解释Ioc和ID。
- 当人们需要一件东西的时候,第一反应是找东西,比如想吃面包。在没有面包店和有面包店俩种情况,您会怎么做?在没有面包店时,最直观的做法可能是您按照自己的口味制作面包,也就是一个面包需要主动制作。然而时至今日,各种网店丶实体店的盛行,已经没有必要自己制作面包了,去网店或实体店把自己的口味告诉店家,一会就可以吃到面包了。注意,您并没有制作面包,而是由店家制作,但是完全符合您的口味
- 当某个Java对象(调用者,例如您)需要调用调用另一个Java对象(被调用者,即被依赖对象,列入面包)时,在传统编程模式下,调用着通常会采用’new 被调用者的代码方式来创建对象(例如你自己制作面包)这种方法会增加调用者与被调用者的耦合性。不利于后期代码的升级与维护
当Spring框架出现后,对象的实例不再有调用者来创建,而是由Spring容器(列如面包店)来创建。Spring容器会负责控制程序之间的关系(列如面包店负责控制您与面包的关系),而不是由调用者的程序代码直接控制。这样,控制权由调用者转移到Spring容器,控制权发生了反转,这就是Spring的控制反转。
-
从Spring容器角度来看,Spring容器负责将被依赖的对象赋值给调用者的成员变量,相当于为调用者注入它所依赖的实例,这就是Spring
-
综上所示,控制反转的是一种通过描述(在Spring中可以是XML或注解)并通过第三种方式去产生或获取特定的对象的方式。在Spring种实现控制反转的是Ioc容器,其实现方法是依赖注入
-
依赖注入的类型
在Sprin中实现Ioc容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象(列如属性值)注入Bean的组件中。Spring框架的依赖注入通常由俩种实现方式,一种是使用构造方式注入,另外一种是使用属性的setter方式注入
使用构造方法注入
spring框架可以采用Java的反射机制,通过构造方法完成依赖注入。下面通过web应用ch2讲解构造方法注入的实现过程。
1 创建dao包
- 在ch2应用中创建dao包,并在该包中创建TestDIDao接口和接口实现类TestDIDaoImpl,创建dao包的目的在service中使用构造方法依赖注入TestDIDao接口对象。
- TestDIDaoImpl接口的代码如下
public interface TestDIDao {
public void sayHello();
}
- TestDIDaoImpl实现类的代码如下
package dao;
public class TestDIDaoImpl implements TestDIDao {
@Override
public void sayHello() {
System.out.println("TestDIDao say:Hello,Study hard");
}
}
2 创建serivce包*
并在该包创建TestDISerivce接口和接口实现类TestDISerivceImpl。使用构造方法依赖注入TestDIDao接口对象。
TestDISerivce接口代码如下:
package Serivce;
public interface TestDIService {
public void salHello();
}
- 实现类代码如下
package Serivce;
import dao.TestDIDao;
public class TestDIServiceImpl implements TestDIService{
private TestDIDao testDIDao;
//构造方法,用于实现依赖注入接口对象testDIDao
public TestDIServiceImpl(TestDIDao testDIDao){
super();
this.testDIDao=testDIDao;
}
@Override
public void salHello() {
//调用testDIDao种的sayHello方法
testDIDao.sayHello();
System.out.println("TestDIService构造方法注入say:Hello,Study hard!");
}
}
3 编写配置文件
src根目录下创建Spring配置文件applicationContext,xml 。在配置文件中首先将dao.TestDIDaoImpl类托管给Spring,让Spring创建其对象,然后将service.TestDIServiceImpl类托管给Spring,让Spring创建其对象,同时给构造方法传递实参。配置文件的具体代码如下
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--将指定类TestDIDaoImpl配置给Spring,让Spring配置文件-->
<bean id="myTestDIDao" class="dao.TestDIDaoImpl"/>
<!--使用构造方法注入-->
<bean id="testDiService" class="Serivce.TestDIServiceImpl">
<constructor-arg index="0" ref="myTestDIDao"/>
</bean>
</beans>
4创建test包
package test;
import Serivce.TestDIService;
import Serivce.TestDIServiceImpl1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDI {
public static void main(String[] args) {
//初始化Spring容器ApplicaationContext,加载配置文件
ApplicationContext appCon=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过容器获取testDIService实列,测试构造方法注入
TestDIService ts= (TestDIService) appCon.getBean("testDiService");
ts.salHello();
}
}
结果
1 使用属性的setter方式注入
使用setter方式注入是Spring框架中最流行的注入方式,它利用Java Bean规范所定义的setter方法来完成注入,灵活且可读性高。对于setter注入,Spring框架也是使用java反射机制实现的。
- 创建接口实现类TestDIServiceImpl1
在service包中创建接口实现类TestDIServiceImpl1,在TestDISerivceImpl1中使用属性的setter方法依赖注入TestDIDao接口对象,
package Serivce;
import dao.TestDIDao;
public class TestDIServiceImpl1 implements TestDIService {
private TestDIDao testDIDao;
//添加testDIdao属性的setter方法,用于依赖注入
public void setTestDIDao(TestDIDao testDIDao) {
this.testDIDao = testDIDao;
}
@Override
public void salHello() {
//调用testDiDao中的sayHello方法
testDIDao.sayHello();
System.out.println("TestDIService setter方法注入 say:Hello,Study hard!");
}
}
2. 将TestDIServiceImpl1类托管给Spring
将TestDIServiceImpl1类托管给Spring,让Spring创建其对象,同时调用TestDIServiceImpl1类的setter方法完成依赖注入。在配置文件中添加如下代码:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--将指定类TestDIDaoImpl配置给Spring,让Spring配置文件-->
<bean id="myTestDIDao" class="dao.TestDIDaoImpl"/>
<!--使用setter方法注入-->
<bean id="testDIService1" class="Serivce.TestDIServiceImpl1">
<!--调用TestDIServiceImpl1 类的setter方法 将myTestDIDao注入到TestDISerivceImp11类的属性testDiDao上-->
<property name="testDIDao" ref="myTestDIDao"/>
</bean>
</beans>
3.在test中测试setter方法注入
package test;
import Serivce.TestDIService;
import Serivce.TestDIServiceImpl1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDI {
public static void main(String[] args) {
//初始化Spring容器ApplicaationContext,加载配置文件
ApplicationContext appCon=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过容器获取testDIService实列,测试构造方法注入
TestDIServiceImpl1 ts1= (TestDIServiceImpl1) appCon.getBean("testDIService1");
ts1.salHello();
}
}