控制反转是Spring框架的核心,用来消减计算机程序的耦合问题。依赖注入是IoC的另一种方法,只是从不同的角度上来描述的。
通过·面向对象思想讨论控制反转和依赖注入两个概念。
当某个java对象(调用者)需要调用另一个Java对象(被调用者,即被依赖对象)时,在传统编程模式下,调用者通常会采用”new 被调用者“的代码方式来创建对象。这种方式会增加调用者与被调用者之间的耦合性,不利于后期代码的升级与维护。
当spring框架出现后,对象的实例不再是由调用者来创建,而是由Spring框架来创建。Spring容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。这样控制权由调用者转移到了Spring容器,控制权发生了反转,这就是Spring的控制反转。
Spring IoC容器
实现控制反转的是Spring IoC容器。Spring IoC容器的设计主要是基于BeanFactory和ApplicationContext两个接口。
BeanFactory
BeanFactory是由org.springframework.beans.factory.BeanFactory接口定义,它提供了完整的IOC服务支持,其中比较常用的时org.springframework.beans.factory.xml.XmlBeanFactory,该类会根据XML配置文件的定义来装配Bean。
在装配BeanFactory实例时需要提供XML文件的绝对路径。
{
//初始化Spring容器ApplicationContext,加载配置文件
ApplicationContext appCon = new ClassPathXmlApplicationContext("D:\javaProject\com\zhizhi\src\resource\applicationContext.xml");
//通过容器获取test实例
TestDao tt = (TestDao) appCon.getBean("test");//test为配置文件中的id
tt.sayHello();
}
使用BeanFactory实例加载Spring配置文件在实际开发中并不多见。
ApplicationContext
ApplicationContext是bean的子接口,也称为应用上下文,由org.springframework.context.ApplicationContext接口定义。ApplicationContext接口除了包含BeanFactory的所有功能外,还添加了对国际化、资源访问、事件传播等内容的支持。
创建ApplicationContext接口的三种方法:
1. 通过ClassPathXmlApplicationContext创建
它是从类路径目录(src根目录)中寻找指定的XML
配置文件,如下:
public static void main(String[] args) {
//初始化Spring容器ApplicationContext,加载配置文件
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过容器获取test实例
TestDao tt = (TestDao) appCon.getBean("test");//test为配置文件中的id
tt.sayHello();
}
2. 通过FileSystemXmlApplicationContext创建
它是将从指定文件的绝对路径中寻找XML配置文件,找到并装在完成ApplicationContext的实例化工作。
public static void main(String[] args){
ApplicationContext appCon = new FileSystemApplicationContext("D:\javaProject\com\zhizhi\src\resource\applicationContext.xml");
//通过容器获取实例
TestDao tt = (TestDao)appCon.getBean("test");
tt.sayHello();
}
3 通过Web服务器实例化ApplicationContext容器
在web服务器实例化ApplicationContext容器时,一般使用基org.springframework.web.context.ContextLoaderLister的实现方法,此方法只需要在web.xml中添加如下代码:
<context-param>
<--加载src目录下的applicationContext文件-->
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
</param-value>
</context-param>
<--指定以ContextLoaderListenter方式启动Spring容器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
依赖注入类型
使用构造方法注入
采用Java反射机制,通过构造方法进行依赖注入
-
创建dao包
创建TestDao接口
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包
创建接口
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!");
}
}
- 编写配置文件
<!--将指定的类TestDIDaoImpl配置给Spring,让Spring创建其实例-->
<bean id="myTestDIDao" class="dao.TestDIDaoImpl"/>
<!--使用构造方法注入-->
<bean id="testDIService" class="service.TestDIServiceImpl">
<constructor-arg index="0" ref="myTestDIDao"/>
</bean>
创建测试类
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.TestDIService;
public class Test1 {
public static void main(String[] args) {
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
TestDIService ts = (TestDIService) appCon.getBean("testDIService");
TestDIService testDIService1 = (TestDIService) appCon.getBean("testDIService1");
ts.sayHello();
testDIService1.sayHello();
}
}
使用setter方法注入
创建接口实现类
package service;
import dao.TestDIDao;
public class TestDIServiceImpl1 implements TestDIService{
private TestDIDao testDIDao;
// 添加testDIDao属性的setter方法,用于实现依赖
public void setTestDIDao(TestDIDao testDIDao){
this.testDIDao = testDIDao;
}
@Override
public void sayHello() {
//调用testDIDao中的sayHello方法
testDIDao.sayHello();
System.out.println("使用setter注入的方法");
}
}
2、将类托管给spring
<!--使用setter方法注入-->
<bean id="testDIService1" class="service.TestDIServiceImpl1">
<property name="testDIDao" ref="myTestDIDao"/>
</bean>