在传统的编程模式下,当一个java对象需要调用另一个Java对象时,调用者会通过"new" 的方式来创建一个实例对象,这样的方式会增加调用者和被调用者的耦合性。在Spring框架中,对象的实例不再由调用者来创建,而是交由Spring容器来创建。Spring容器负责控制程序之间的关系,而不是调用者的代码直接控制。创建对象的控制权由调用者转移到Spring 容器,控制权发生反转,这就是Spring 的控制反转。
从Spring 容器角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,相当于为调用者注入它所依赖的实例,这就是Spring 的依赖注入。在Spring 中实现控制反转的是IoC容器,其实现方法是依赖注入。
Spring IoC 容器的设计主要基于BeanFactory
和ApplicationContext
两个接口。
BeanFactory 由org.springframework.beans.factory.BeanFactory
接口定义,它提供了完整的IoC服务支持,是一个管理Bean的工厂名主要负责初始化各种Bean。常用的实现类是org.springframework.beans.factory..xml.XmlBeanFactory
,该类主要根据XML配置文件中的定义来装配Bean。
ApplicationContext是BeanFactory的子接口,由org.springframework.context.ApplicationContext
接口定义。该接口除了包含BeanFactoy的所有功能以外,还添加了国际化、资源访问、事件传播等内容的支持。
创建ApplicationContext
接口的实例有以下三种方式:
ClassPathXMLApplicationContext
创建该类将从类路径目录(src根目录)下寻找指定的XML配置文件。
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
FileSystemXMLApplicationContext
创建该类将从指定文件的绝对路径获取XML配置文件,找到并装载完成ApplicationContext
的实例化工作。
ApplicationContext appCon = new FileSystemXmlApplicationContext("H:\\workspace-spring\\SpringDemo\\src\\applicationContext.xml");
ApplicationContext
容器在web应用中,ApplicationContext
容器的实例化工作交由Web服务器完成。一般使用基于org.springframework.web.context.ContextLoaderListener
的方式实现(需要导入Spring-web-RELEASE.jar包),只需在web.xml上配置:
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
无论是构造方法注入,还是属性的setter方法注入,Spring 框架都是通过java的反射机制实现的。
创建dao包
TestDIDao
接口代码如下:
public interface TesDIDao {
public void sayHello();
}
TestDIDaoImpl
实现类代码如下:
public class TestDIDaoImpl implements TesDIDao {
@Override
public void sayHello() {
System.out.println("TestDao say: Hello,Study hard!");
}
}
创建service包
TestDIService
接口代码如下:
public interface TestDIService {
public void sayHello();
}
TestDIServiceImpl
实现类代码如下:
import gzc.dao.TesDIDao;
public class TestDIServiceImpl implements TestDIService {
private TesDIDao testDIDao;
public TestDIServiceImpl() {
}
// 构造方法,用于实现依赖注入接口对象testDIDao
public TestDIServiceImpl(TesDIDao testDIDao) {
super();
this.testDIDao = testDIDao;
}
@Override
public void sayHello() {
testDIDao.sayHello();
}
}
编写配置文件
applicationContext.xml
内容如下:
<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="myTestDIDao" class="gzc.dao.TestDIDaoImpl"/>
<bean id="testDIService" class="gzc.service.TestDIServiceImpl">
<constructor-arg index="0" ref="myTestDIDao"/>
bean>
beans>
在配置文件中,constructor-arg
元素用于定义类构造方法的参数,index
代表的是参数的位置,ref
指定某个实例的引用(这里指向的是bean的id
),如果参数是常量,则用value
。
修改上面的TestDIServiceImpl
实现类,为其添加setter
、getter
方法以及无参构造方法(由于前面已定义了带参构造方法,JVM不在为该类提供默认的无参构造方法,所以需要手动添加,否则在会报错,原因可能是Spring IoC容器实例初始化是通过java 反射机制实现的,而反射需要通过类的无参构造方法进行的)
public class TestDIServiceImpl implements TestDIService {
private TesDIDao testDIDao;
public TestDIServiceImpl() {
}
// 构造方法,用于实现依赖注入接口对象testDIDao
public TestDIServiceImpl(TesDIDao testDIDao) {
super();
this.testDIDao = testDIDao;
}
public TesDIDao getTestDIDao() {
return testDIDao;
}
public void setTestDIDao(TesDIDao testDIDao) {
this.testDIDao = testDIDao;
}
@Override
public void sayHello() {
// TODO Auto-generated method stub
testDIDao.sayHello();
}
}
更改配置文件
<bean id="myTestDIDao" class="gzc.dao.TestDIDaoImpl"/>
<bean id="testDIService" class="gzc.service.TestDIServiceImpl">
<property name="testDIDao" ref="myTestDIDao"/>
bean>
测试
public class Test {
public static void main(String[] args) {
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
TestDIService diService = (TestDIService) appCon.getBean("testDIService");
diService.sayHello();
}
}