控制反转IOC
例子:
你想吃面包,这时候有两种情况:
1 你家附近没有面包店,你就要自己买原材料自己做面包(传统编程模式:需要自己new对象)
2 你家附近有面包店,那么你只要把你想要吃的口味告诉店家,一会你就可以吃到面包了(控制反转:自己不new对象,对象由框架交给你)
注意:你没有制作面包,而是由店家制作面包,但是完全符合你的口味
控制反转:就是对象由Spring容器创建和管理,调用者只负责使用,降低耦合度,控制权由调用者转移到Spring容器,控制权产生了反转。
依赖注入:从Spring容器角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,相当于为调用者注入它所依赖的实例。
所以,控制反转是一种通过描述(Spring中可以是XML文件或注解)并通过第三方去产生或获取特定对象的方式。
Spring中实现控制反转的是IOC容器,其实现方式是依赖注入(DI)
IOC容器的设计主要是基于BeanFactory和ApplicationContext两个接口
applicationContext.xml
<bean id="test" class="dao.TestDaoImpl" />
dao/ITestDao.java(接口)
package dao; public interface ITestDao { public void sayHello(); }
dao/TestDaoImpl.java(实现类)
package dao; public class TestDaoImpl implements ITestDao{ public void sayHello() { // TODO Auto-generated method stub System.out.println("Hello,Study hard!"); } }
test/Tests.java(测试类)
package test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import dao.ITestDao; public class Tests { @Test public void test1() { //初始化spring容器ApplicationContext,加载配置文件 ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml"); //通过容器获取test实例 ITestDao tt = (ITestDao) appCon.getBean("test"); tt.sayHello(); } }
依赖注入(DI):
依赖注入是Spring中实现IOC容器的方法,其作用是在使用spring框架创建对象时动态的将其所依赖的对象或属性值注入bean组件中
依赖注入通常使用两种方式实现:构造方法注入和setter方法注入
1.构造方法注入
applicationContext.xml内容
<!-- 将指定类DIServiceImpl配置给spring,让spring创建其实例 -->
<bean id="myTestDao" class="dao.TestDaoImpl"></bean>
<!-- 使用构造方法注入 -->
<bean id="diService" class="service.DIServiceImpl">
<!-- 将myTestDao注入到DIServiceImpl类的属性ITestDao上 -->
<constructor-arg index="0" ref="myTestDao" />
</bean>
service.IDIService.java
package service;
/**
* 使用构造方法依赖注入ITestDao接口对象
*
* Title: IDIService
*
* Description:
*
* @author Ethan * * @date 2019年6月25日 * */ public interface IDIService { public void sayHello(); }
service.DIServiceImpl.java
package service;
/**
* IDIService接口的实现类
*
* Title: DIServiceImpl
*
* Description:
*
* @author Ethan * * @date 2019年6月25日 * */ import dao.ITestDao; public class DIServiceImpl implements IDIService{ private ITestDao iTestDao; //构造方法,用于实现依赖注入接口对象iTestDao public DIServiceImpl(ITestDao iTestDao) { super(); this.iTestDao = iTestDao; } public void sayHello() { //调用iTestDao中的sayHello方法 iTestDao.sayHello(); System.out.println("IDIService构造方法注入"); } }
测试类:
test.Tests2.java
package test;
import org.junit.Test;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import service.IDIService; public class Tests2 { /** * 构造方法注入测试类 * * Title: Test1 * * Description: * * */ @Test public void Test1() { ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml"); IDIService ts = (IDIService) appCon.getBean("diService"); ts.sayHello(); } }
运行结果:
Hello,Study hard!
IDIService构造方法注入
2 setter方法注入
在上面的结构中加入service.DIServiceImpl.java
package service;
import dao.ITestDao;
public class DIServiceImpl1 implements IDIService{ private ITestDao iTestDao; //添加iTestDao的setter方法,用于实现依赖注入 public ITestDao getiTestDao() { return iTestDao; } public void setiTestDao(ITestDao iTestDao) { this.iTestDao = iTestDao; } public void sayHello() { // TODO Auto-generated method stub //调用iTestDao中的sayHello方法 iTestDao.sayHello(); System.out.println("TestDaoImpl setter方法注入"); } }
applicationContext.xml加入
<!-- 使用setter方法的注入 -->
<bean id="testDIService1" class="service.DIServiceImpl1">
<!-- 调用DIServiceImpl1类的setter方法,将myTestDao注入到DIServiceImpl1类的属性iTestDao上 -->
<property name="iTestDao" ref="myTestDao" />
</bean>
测试类:Tests2.java中加入
/**
* 使用setter方式注入测试类
*
* Title: Test2
*
* Description:
*
*
*/
@Test
public void Test2() { ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml"); IDIService ts = (IDIService) appCon.getBean("testDIService1"); ts.sayHello(); }
运行结果:
Hello,Study hard!
TestDaoImpl setter方法注入
思考:
1 IOC容器的实现方式有哪些?
2 在spring框架中什么是控制反转?什么是依赖注入?使用控制反转与依赖注入有什么优点?
3 spring框架采用java的什么机制进行依赖注入