浅析Spring——控制反转IoC
目录
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
如果我们要实现业务二,就必须修改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)
7. 总结
控制反转IoC是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。
在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
了解IoC以前,我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全写死子在程序中,对象的创建由程序自己控制
控制反转后将对象的创建转移给第三方,所谓控制反转就是:获得依赖对象的方式反转了。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC:
可以使用XML配置
也可以使用注解
新版本的Spring也可以零配置实现IoC
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
作者:Baret H ~
来源:CSDN