1.Spring IOC的概念
控制反转(Inversion of Control,IOC)是Spring框架的核心,用来消减计算机程序的耦合问题。依赖注入(DependencyInjection,DI)是IOC的另一种说法,只是从不同的角度描述相同的概念。
当某个Java对象需要调用另一个Java对象时,通常会采用new的方式来创建对象。这种方式会增加调用者和被调用者之间的耦合性,不利于代码的升级和维护。
Spring框架出现之后,对象的实例不再由调用者来创建,而是由spring容器来创建。Spring容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制,这样,控制权由调用者转移到Spring容器,控制权就发生的反转,这就是Spring的控制反转。
从Spring容器的角度来看,Spring容器将被依赖的对象赋值给调用者的成员变量,相当于为调用者注入它所依赖的实例,这就是Spring的依赖注入。综上所述,控制反转是一种通过描述并通过第三方去产生或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入。
2.Spring IOC容器
实现控制反转的是Spring IOC容器,Spring IOC容器的设计主要基于两种方式,一种是BeanFactory接口,另一种是ApplicationContext接口。在创建BeanFactory接口的实例时需要提供XML文件的绝对路径,所以这种方式比较少用。最常用的就是ApplicationContext,ApplicationContext是BeanFactory的子接口,也称为应用上下文。创建ApplicationContext接口的实例:
ApplicationContext appCon=new ClassPathXmlApplicationContext(“applicationContext.xml”);
3.依赖注入的类型
在Spring中实现IOC容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象注入Bean组件中。Spring框架的依赖注入通常有两种实现方式,一种是使用构造方法注入,另一种是使用属性的setter方法注入。
3.1构造方法注入
dao包中有TestDIDO接口,其实现类TestDIDaoImpl。
package dao;
public interface TestDIDao {
public void sayHello();
}
package dao;
public class TestDIDaoImpl implements TestDIDao{
@Override
public void sayHello() {
System.out.println("TestDIDao say:hello,study hard!");
}
}
service包中有TestDIService接口,其实现类TestDIServiceImpl.
package service;
public interface TestDIService {
public void sayHello();
}
package service;
import dao.TestDIDao;
public class TestDIServiceImpl implements TestDIService{
private TestDIDao testDIDao;//类属性
//构造方法,用于实现依赖注入接口对象testDIDao
public TestDIServiceImpl(TestDIDao testDIDao) {
super();
this.testDIDao=testDIDao;
}
@Override
public void sayHello() {
testDIDao.sayHello();
System.out.println("TestDIService构造方法注入say:hello,study hard!");
}
}
在配置文件applicationContext.xml中,Spring创建了dao.TestDIDaoImpl类的对象,然后创建service.TestDIServiceImpl类的对象,同时给构造方法传递实参。
<?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">
<!-- 将指定类TestDIDaoImpl配置给spring,让spring创建其实例 -->
<bean id="myTestDIDao" class="dao.TestDIDaoImpl"/>
<!-- 使用构造方法注入 -->
<bean id="testDIService" class="service.TestDIServiceImpl">
<!--调用构造方法, 将myTestDIDao注入到TestDIServiceImpl类的属性testDIDao上 -->
<constructor-arg index="0" ref="myTestDIDao"/>
</bean>
</beans>
constructor-arg元素用于定义类构造方法的参数,index定义参数的位置,ref是某个实例的引用,如果参数是常量值,ref由value代替。
测试类:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.TestDIService;
public class TestDI {
public static void main(String[] args) {
//初始化Spring 容器ApplicationContext,加载配置文件
ApplicationContext appCon=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过容器获取testDIService实例,测试构造方法注入
TestDIService ts=(TestDIService)appCon.getBean("testDIService");
ts.sayHello();
}
}
运行结果:
TestDIDao say:hello,study hard!
TestDIService构造方法注入say:hello,study hard!
总的来说,就是在配置文件中,把容器生成的对象myTestDIDao注入到TestDIServiceImpl类的类属性testDIDao上,否则调用TestDIServiceImpl的sayHello()函数时,testDIDao.sayHello();会出错,必须用构造方法注入接口对象testDIDao.
3.2属性的setter方法注入
service包中的实现类TestDIServiceImpl1
package service;
import dao.TestDIDao;
public class TestDIServiceImpl1 implements TestDIService{
private TestDIDao testDIDao;
public void setTestDIDao(TestDIDao testDIDao) {
this.testDIDao=testDIDao;
}
@Override
public void sayHello() {
testDIDao.sayHello();
System.out.print("TestDIService setter 方法注入say:Hello,Study hard!");
}
}
配置文件:
<?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">
<!-- 将指定类TestDIDaoImpl配置给spring,让spring创建其实例 -->
<bean id="myTestDIDao" class="dao.TestDIDaoImpl"/>
<!-- 使用setter方法注入 -->
<!-- 调用TestDIServiceImpl1类的setter方法,将myTestDIDao注入到TestDIServiceImpl1的类属性testDIDao上-->
<bean id="testDIService1" class="service.TestDIServiceImpl1">
<property name="testDIDao" ref="myTestDIDao"/>
</bean>
</beans>
测试代码:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.TestDIService;
public class TestDI {
public static void main(String[] args) {
//初始化Spring 容器ApplicationContext,加载配置文件
ApplicationContext appCon=new ClassPathXmlApplicationContext("applicationContext.xml");
TestDIService ts1=(TestDIService)appCon.getBean("testDIService1");
ts1.sayHello();
}
}
测试结果:
TestDIDao say:hello,study hard!
TestDIService setter 方法注入say:Hello,Study hard!