很多人一提ioc,便张口就来:控制反转。究竟哪些方面被反转了呢?答案是依赖对象的获得被反转了。很多时候,我们通过多个对象之间的协作来完成一个功能,如果获取所依赖对象靠自身来实现,这将导致代码的耦合度高和难以测试。当然,控制反转还有一个好听的名字:依赖注入。
IOC(Inverse of Control):
在每个框架的中都有一个容器的概念,所谓的容器就是将常用的服务,封装起来,然后,用户只需要遵循一定的规则,就可以达到统一、灵活、安全、方便、快速的目的。
IOC是一个依赖注入DI(Dependence Injection)的方式达到控制反转目的的框架。
控制反转:的优势在于将服务交给容器。
我们对比一下由我们的应用程序负责服务(对象)定位:
public class UserManagerImpl implements UserManager { public void addUser(String username, String password) { //由我们的应用程序负责服务(对象)定位 //UserDao userDao = new UserDao4MySqlImpl(); UserDao userDao = new UserDao4OracleImpl(); userDao.addUser(username, password); } }
public class UserManagerImpl implements UserManager { private UserDao userDao; public void addUser(String username, String password) { userDao.addUser(username, password); } public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
在spring ioc中有三种依赖注入,分别是:
- a、接口注入;
- b、setter方法注入;
- c、构造方法注入;
setter方法注入
setter注入模式在实际开发中有非常广泛的应用,setter方法更加直观,我们来看一下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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"> <!-- 使用spring管理对象的创建,还有对象的依赖关系 --> <bean id="userDao4Mysql" class="com.tgb.spring.dao.UserDao4MysqlImpl"/> <bean id="userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/> <bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl"> <!-- (1)userManager使用了userDao,Ioc是自动创建相应的UserDao实现,都是由容器管理--> <!-- (2)在UserManager中提供构造函数,让spring将UserDao实现注入(DI)过来 --> <!-- (3)让spring管理我们对象的创建和依赖关系,必须将依赖关系配置到spring的核心配置文件中 --> <property name="userDao" ref="userDao4Oracle"></property> </bean> </beans>
接着我们来看一下,setter表示依赖关系的写法
public class UserManagerImpl implements UserManager{ private UserDao userDao; //使用设值方式赋值 public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void addUser(String userName, String password) { userDao.addUser(userName, password); } }
构造器注入
构造器注入,即通过构造函数完成依赖关系的设定。我们看一下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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"> <!-- 使用spring管理对象的创建,还有对象的依赖关系 --> <bean id="userDao4Mysql" class="com.tgb.spring.dao.UserDao4MysqlImpl"/> <bean id="userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/> <bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl"> <!-- (1)userManager使用了userDao,Ioc是自动创建相应的UserDao实现,都是由容器管理--> <!-- (2)在UserManager中提供构造函数,让spring将UserDao实现注入(DI)过来 --> <!-- (3)让spring管理我们对象的创建和依赖关系,必须将依赖关系配置到spring的核心配置文件中 --> <constructor-arg ref="userDao4Oracle"/> </bean> </beans>
我们再来看一下,构造器表示依赖关系的写法,代码如下所示:
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); } }
spring ioc通过引入xml配置,由ioc容器来管理对象的生命周期,依赖关系等。
它的加载过程是什么样的呢?
BeanDefinition是一个接口,用于属性承载,比如<bean>元素标签拥有class、scope、lazy-init等配置。bean的定义方式有千千万万种,无论是何种标签,无论是何种资源定义,无论是何种容器,只要按照spring的规范编写xml配置文件,最终的bean定义内部表示都将转换为内部的唯一结构:BeanDefinition。当BeanDefinition注册完毕以后,spring的BeanFactory就可以随时根据需要进行实例化了。