IOC(依赖注入DI及两种注入方式)
一、概念
① IoC的直译是控制反转。
在IoC模式下,控制权限从应用程序转移到了IoC容器中。组件不是由应用程序负责创建和配置,而是由IoC容器负责。
使用IoC的情况下,对象是被动地接收依赖类而不是主动地查找。对象不是从容器中查找他的依赖类,而是容器在实例化对象时,主动地将他所依赖的对象注入给他。
应用程序只需要直接使用已经创建并且配置好的组件即可,而不必自己负责创建和配置。
在实际的工作中人们发现使用IoC来表述这种机制,并不是很准确甚至有些晦涩,于是引发了另外一个概念:DI(依赖注入)
② DI解析
之所以会产生组件调用,是为了获取被调用组件的功能,调用者将自己应该做的事情,委派给了被调用的对象。也就是说,调用者要完成自身的任务,必须依赖被调用的对象。这种关系实际上就是一般依赖关系(通俗点说,就是一个组件内部包含另外一个组件的实例,把该自己干的事交给自己包含的组件去完成)。因此IoC所表述的机制,实际上就是将调用者对接口实现类的依赖关系,从程序中移除,转交第三方管理实例。并且,由第三方在运行期间将调用者依赖的具体类填充进来。也就是说组件之间的依赖关系,是在程序运行期间由第三方来管理的。这个就是依赖注入的概念(DI),基于上述分析,DI比IoC更准确。
实际上就是将调用者为完成功能所依赖的实现类,在程序运行期间,由容器自动填充给调用者,这个就是依赖注入的核心思想。在依赖注入的应用中,组件并不关心被注入的对象是谁,只关系这个对象能完成的功能,也就是这个对象是哪个接口的具体类实例。
ApplicationContext.xml:构造函数注入
<?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-4.1.xsd">
<!--
构造函数注入:constructor-arg
index:可省略,构造函数参数的下标,从0开始
name:可省略,构造函数参数的名称,例如:public UserService(IUserDao userDao,String userName) userDao与userName
ref:表示在容器中需要引用的bean的ID的属性值
value:给基本属性数据类型或String赋值
注意:
1、参数个数必须一致
2、两边参数的类型必须一致
3、建议保留默认的无参构造函数
4、建议不要省略name
-->
<bean id="userService" class="spring.UserService">
<constructor-arg index=0 name="userDao" ref="userDao"></constructor-arg>
<constructor-arg index=1 name="userName" value="给基础类型赋值"></constructor-arg>
</bean>
<bean id="userDao" class="spring.UserDaoImpl"></bean>
</beans>
UserService:
package spring;
public class UserService {
private IUserDao userDao;
private String userName;
//无参构造函数
public UserService()
{
System.out.println("new UserService() 实例化");
}
//有参构造函数
public UserService(IUserDao userDao,String userName)
{
this.userDao = userDao;
this.userName=userName;
}
public void findUsers()
{
userDao.selectUser();
}
}
测试类:
public static void main(String[] args) {
//加载并解析ApplicationContext.xml
ClassPathXmlApplicationContext factory= new ClassPathXmlApplicationContext("applicationContext.xml");
//获取工厂中的IUseDao对象
IUserDao userDao= (IUserDao)factory.getBean("userDao");
//调用方法
userDao.selectUser();
//销毁对象
factory.close();
}
set属性注入:
UserService:
package spring;
public class UserService {
private IUserDao userDao;
private String userName;
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void findUsers()
{
userDao.selectUser();
}
}
ApplicationContext.xml:
<!-- set属性注入:property
name:必须为set方法后面的属性值,例如:public void setUserDao(IUserDao userDao),name值为set后面的UserDao,都是首字母必须小写即为userDao
ref:表示在容器中需要引用的bean的ID的属性值
value:给基本属性数据类型或String赋值
平时调用时的使用:
UserService userService = new UserService();
userService.setUserDao(userDao);
userService.setUserName(userName);
-->
<bean id="userService" class="spring.UserService">
<property name="userDao" ref="userDao"></property>
<property name="userName" value="李四"></property>
</bean>
<bean id="userDao" class="spring.UserDaoImpl"></bean>
其实还有一种注入方式:接口注入(Spring不支持)
这两种方式是原生的:手动装配,非注解方法注入,后面会讲到,手动方式装配,注解方式注入和自动装配