简介
控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛。
IoC模式,系统中通过引入实现了IoC模式的IoC容器,即可由IoC容器来管理对象的生命周期、依赖关系等,从而使得应用程序的配置和依赖性规范与实际的应用程序代码分开。其中一个特点就是通过文本的配置文件进行应用程序组件间相互关系的配置,而不用重新修改并编译具体的代码。
如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:
●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
实例:
我们使用传统方式(即不使用Spring)来实现一个添加用户的实例,再同理使用Spring实现添加用户的实例,对比学习IoC的概念,以及为什么使用IoC等等,最后,简单总结。下面我们开始:
传统方式:
数据访问层:
UserDao接口:
public interface UserDao {
public void addUser(String userName,String password);
}
UserDao两种实现 :
public class UserDao4MySqlImpl implements UserDao {
public void addUser(String userName,String password){
System.out.println("UserDao4MySqlImpl.addUser()");
System.out.println("userName="+userName);
System.out.println("password="+password);
}
}
public class UserDao4OracleImpl implements UserDao {
public void addUser(String userName,String password){
System.out.println("UserDao4OracleImpl.addUser()");
System.out.println("userName="+userName);
System.out.println("password="+password);
}
}
业务逻辑层:
UserManager接口:添加用户的方法
public interface UserManager {
public void addUser(String userName,String password);
}
UserManager实现:
public class UserManagerImpl implements UserManager {
private UserDao userDao;
public UserManagerImpl(UserDao userDao) {
if(userDao instanceof UserDao4MySqlImpl){
this.userDao = new UserDao4MySqlImpl();
}
else if(userDao instanceof UserDao4OracleImpl){
this.userDao = new UserDao4OracleImpl();
}
else
System.exit(-1);
}
@Override
public void addUser(String userName, String password) {
userDao.addUser(userName, password);
}
}
客户端:
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
UserManagerImpl userManager = new UserManagerImpl(new UserDao4OracleImpl());
userManager.addUser("jiuqiyuliang", "123456");
}
}
运行效果图:
我们可以发现:传统方式,对象和对象之间发生严重的依赖关系,耦合度非常高而且依赖关系都写死在了UserManager实现代码里,项目不易修改和维护,必须要改代码。
Spring方式:
前面Userdao以及Userdao的实现都是一样的。
业务逻辑层:
UserManager实现:
UserManager实现:
public class UserManagerImpl implements UserManager{
private UserDao userDao;
//使用构造方式赋值
public UserManagerImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser(String userName, String password) {
userDao.addUser(userName, password);
}
}
客户端:
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
UserManager userManager =(UserManager)factory.getBean("userManager");
userManager.addUser("jiuqiyuliang", "123456");
}
}
Spring的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<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="userDao4Mysql" class="UserDao4MySqlImpl"></bean>
<bean id="userDao4Oracle" class="UserDao4OracleImpl"></bean>
<bean id="userManager" class="UserManagerImpl">
<constructor-arg ref="userDao4Mysql"></constructor-arg>
<!--或
<constructor-arg ref="userDao4Oracle"></constructor-arg>
-->
</bean>
</beans>
对比传统的实现方式,再看客户端和UserManager,我们可以发现:通过IoC或DI,我们只需要通过简单的配置,而无需任何代码就可以指定UserManager中所需的UserDao的具体实现。UserManager只需利用容器注入的UserDao实例,完成自身的业务逻辑,而不用关心具体实现来自哪、由谁实现。换句话说:
我们不再需要自己负责创建对象,管理对象生命周期以及维护对象的依赖关系,这些都有Spring替我们完成了。