目录
- 1. IoC理论推导
- 2. 什么是IoC?
- 3. 引入DI
- 4. IoC容器
- 5. 注入对象的四种方法
- 1、基于接口
- 2、基于setter
- 3、基于构造函数
- 4、基于注解
- 6. 两种IoC实现方式
- 1、依赖查找
- 2、依赖注入
- 7. 总结
1. IoC理论推导
IoC
:Inversion of Control(控制反转)
接下来我们以一个示例,讲述Ioc
的本质
程序结构图:
dao
:数据访问层service
:服务层,用来调用dao层
1、编写UserDao接口
package dao;
public interface UserDao {
public void getUser();
}
2、编写UserDao接口
实现类UserDaoImpl
package dao;
//业务一:默认获取用户数据
public class UserDaoImpl implements UserDao {
public void getUser() {
System.out.println("默认获取用户的数据");
}
}
3、编写UserService接口
package service;
public interface UserService {
public void getUser();
}
4、编写UserService接口
业务实现类UserServiceImpl
package service;
import dao.UserDao;
import dao.UserDaoImpl;
public class UserServiceImpl implements UserService {
//内置UserDaoImpl实例化对象
private UserDao userDao = new UserDaoImpl();
public void getUser() {
userDao.getUser();
}
}
5、编写测试类,实现业务一
import dao.UserDaoImpl;
import service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
//用户实际调用的是业务层,dao层不需要接触
UserServiceImpl userService = new UserServiceImpl();
userService.getUser();
}
}
6、新增业务:新增业务二
:MySQL获取用户数据
新增
UserDao接口
实现类UserDaoMysqlImpl
package dao;
public class UserDaoMysqlImpl implements UserDao{
public void getUser() {
System.out.println("MySQL获取用户数据");
}
}
如果我们要实现业务二
,就必须修改UserServiceImpl
业务实现类里的代码为:
package service;
import dao.UserDao;
import dao.UserDaoImpl;
public class UserServiceImpl implements UserService {
//将对象变为UserDaoMysqlImpl实例化的对象
private UserDao userDao = new UserDaoMysqlImpl();
public void getUser() {
userDao.getUser();
}
}
-
如果我们要增加其他的业务,就得增加对应的Dao层实现类,就需要去
UserServiceImpl
业务实现类里面修改对应的代码 -
业务需求量非常大的情况下 , 每次变动 , 都需要修改大量代码,耦合性太高
解决问题:在UserServiceImpl
业务实现类中增加set方法
import dao.UserDao;
import dao.UserDaoImpl;
public class UserServiceImpl implements UserService {
private UserDao userDao;
//利用set进行动态实现值的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
此后,我们需要用到什么业务的时候,只需要在测试类中选择对应的业务实现类对象注入即可
import dao.UserDaoImpl;
import service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
//用户实际调用的是业务层,dao层不需要接触
UserServiceImpl userService = new UserServiceImpl();
//选择业务二
userService.setUserDao(new UserDaoImpl());
//选择业务一
userService.getUser();
}
}
这就是Ioc
的本质:控制反转
- 移交了主动权,大大降低了系统的耦合性,更加专注于业务的实现
通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的
引用
传递给它。也可以说,依赖被注入到对象中。
- 改进前,主动权在程序员手中,程序员修改相关代码来实例化不同的业务实现类对象,以此来调用不同的业务
- 改进后,主动权掌握在用户手中,用户可以选择不同的业务实现类实例对象直接进行注入,直接进行调用,而不需要程序员进行代码的修改
2. 什么是IoC?
控制反转(Inversion of Control,缩写为
IoC
)
- 是
面向对象编程中
的一种设计原则,可以用来减低计算机代码之间的耦合度
- 有两种常见的实现方式:
- 最常见:
依赖注入
(Dependency Injection,简称DI) 依赖查找
(Dependency Lookup)
- 最常见:
- IoC可以认为是一种全新的
设计模式
,但是理论和时间成熟相对较晚,并没有包含在GoF
中。 - IoC中最基本的Java技术就是“
反射
”编程,根据给出的类名(字符串)来生成对象
3. 引入DI
上述理论推导例子在一定程度上缓解了问题,但实质上这种代码耦合并没有改变!
这就引入了我们接下来的Ioc模式
的实现方式之一:DI
就是最常见的一种方式
依赖注入(DI)
:把耦合从代码中移出去,放到统一的XML
文件中,通过一个容器在需要的时候把这个依赖关系形成,即把需要的接口实现注入到需要它的类中
- 这里的容器就是
IoC容器
- 可以把
IoC模式
看作工厂模式的升华,把IoC容器
看作是一个大工厂,只不过这个大工厂里要生成的对象都是在XML
文件中给出定义的
4. IoC容器
IoC模式,系统中通过引入实现了IoC模式的
IoC容器
IoC容器
用来来管理对象的生命周期、依赖关系等,从而使得应用程序的配置和依赖性规范与实际的应用程序代码分离。- **特点:**就是通过文本的配置文件进行应用程序组件间相互关系的配置,而不用重新修改并编译具体的代码。
- 常见的
IoC容器
:Pico Container、Avalon 、Spring、JBoss、HiveMind、EJB等。
5. 注入对象的四种方法
使用IoC模式后,我们不用再写死创建指定对象的代码,而是灵活的动态注入所需的对象,有三种常见的注入方式:
1、基于接口
- 可服务的对象需要实现一个专门的接口,该接口提供了一个对象,可以重用这个对象查找依赖(其它服务)。
- 早期的容器Excalibur使用这种模式。
- 接口方式注入显得比较霸道,因为它需要被依赖的对象实现不必要的接口,带有侵入性。一般都不推荐这种方式
2、基于setter
- 通过JavaBean的属性(setter方法)为可服务对象指定服务。(上述例子就是通过此形式注入)
HiveMind
和Spring
采用这种方式。
3、基于构造函数
- 通过构造函数的参数为可服务对象指定服务。
PicoContainer
只使用这种方式,HiveMind
和Spring
也使用这种方式。
4、基于注解
Spring2.5
开始支持注解,从此我们可以通过注解简单高效的实现注入- 这是我们开发中最常使用的方法
6. 两种IoC实现方式
1、依赖查找
- 容器提供
回调接口
和上下文条件
给组件。 - 组件使用容器提供的API来查找资源和协作对象,仅有的控制反转只体现在那些回调方法上(基于接口):容器将调用这些回调方法,从而让应用代码获得相关资源。
2、依赖注入
- 组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。
- 容器全权负责的组件的装配,它会把符合依赖关系的对象通过JavaBean属性或者构造函数传递给需要的对象。
- 通过JavaBean属性注射依赖关系的做法称为
设值方法注入
(Setter Injection) - 将依赖关系作为构造函数参数传入的做法称
为构造器注入
(Constructor Injection)
- 通过JavaBean属性注射依赖关系的做法称为
7. 总结
控制反转IoC
是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
-
了解IoC以前,我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全写死子在程序中,对象的创建由程序自己控制
-
控制反转后将对象的创建转移给第三方,所谓控制反转就是:获得依赖对象的方式反转了。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC
:
- 可以使用
XML配置
- 也可以使用
注解
- 新版本的Spring也可以零配置实现IoC
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。