1.6 Spring 依赖注入
在软件工程领域,依赖注入(Dependency Injection)是用于实现控制反转(Inversion of Control)的最常见的方式之一。spring动态的向某个对象提供它所需要的其他对象就是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。
简单来说什么是依赖注入,就是给属性赋值(包括基本数据类型和引用数据类型)下面的程序就说明了这种编程方式:
以下是依赖注入的程序,该程序共使用了6个程序文件UserDao.java,UserDaoImpl.java,UserService.java,UserServiceImpl.java,applicationContext.xml和Test.java文件,它们在项目中的包结构如下

其中UserDao是一个接口,其中定义了需要实现的方法say(),如下所示:
package dao; public interface UserDao { public void say(); } |
UserDaoImpl是接口UserDao的实现类,它实现了方法say(),代码如下所示:
package impl; import dao.UserDao; public class UserDaoImpl implements UserDao { public void say() { System.out.println("helloworld Spring!"); } } |
UserService是一个接口,里面定义了一个方法show(),其代码如下所示:
package dao;
public interface UserService { public void show(); } |
UserServiceImpl是接口UserService的实现类,它实现了show()方法,同时该类有一个UserDao类型的成员变量userDao。在show()方法里我们试图调用对象userDao的方法say()。如下代码所示:
| package impl; import dao.UserDao; import dao.UserService; public class UserServiceImpl implements UserService { private UserDao userDao; public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void show() { userDao.say(); System.out.println("userservice hello!"); } } |
这时候要注意,对象userDao的类型是接口类型UserDao,这个对象从UserServiceImpl的代码中是看不出来的。我们需要对对象userDao进行实例化。传统的实例化代码如下:
UserDao ud=new UserDaoImpl();
UserService us=new UserServiceImpl()
us.setUserDao(ud);
从上述实例化代码可以看出,当我们希望修改UserDao的实现类时,如将UserDaoImpl替换为一种新的实现时(比如改为ManageDaoImpl),我们不仅需要添加ManageDaoImpl类,还需要修改我们的实例化代码。
使用spring依赖注入方式实例化则是我们将装配UserServiceImpl对象的操作放在配置文件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.3.xsd"> <!-- 将指定类配置给Spring,让Spring创建其对象的实例 --> <bean id="userDao" class="impl.UserDaoImpl"></bean> <bean id="userService" class="impl.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean> </beans> |
文件第3行定义了一个bean对象,该bean对应的类是impl包中的UserDaoImpl。第4、5、6行定义了另一个bean对象userService该bean对应的类是impl包中的userServiceImpl。注意第5行<property>标记定义了bean对象userService的一个子成员,该子成员的属性的name的值“userDao”对应类userServiceImpl中的成员变量userDao,而该子成员的属性的ref的值“userDao”对应第3行定义的id为“userDao”的bean,表明用第3行定义的bean作为配件去装配bean对象userService。
由此我们编写测试类Test.java代码如下:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import dao.UserDao; import dao.UserService; import impl.UserDaoImpl;
public class Test { public static void main(String[] args) { //1.初始化spring容器,加载配置文件 ApplicationContext appc=new ClassPathXmlApplicationContext("applicationContext.xml"); //2.使用spring容器获取对象 UserService ud=(UserService)appc.getBean("userService"); ud.show(); } } |
运行程序结果如下:

操作视频如下:

