Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)
上QQ阅读APP看书,第一时间看更新

1.4 依赖注入

1.4.1 依赖注入的概念

依赖注入(Dependency Injection,简称DI)与控制反转(IoC)的含义相同,只不过这两个称呼是从两个角度描述的同一个概念。对于一个Spring初学者来说,这两种称呼很难理解,下面我们将通过简单的语言来描述这两个概念。

当某个Java对象(调用者)需要调用另一个Java对象(被调用者,即被依赖对象)时,在传统模式下,调用者通常会采用“new被调用者”的代码方式来创建对象,如图1-8所示。这种方式会导致调用者与被调用者之间的耦合性增加,不利于后期项目的升级和维护。

图1-8 调用者创建被调用者对象

在使用Spring框架之后,对象的实例不再由调用者来创建,而是由Spring容器来创建,Spring容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。这样,控制权由应用代码转移到了Spring容器,控制权发生了反转,这就是Spring的控制反转。

从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,这相当于为调用者注入了它依赖的实例,这就是Spring的依赖注入,如图1-9所示。

图1-9 将被调用者对象注入调用者对象

1.4.2 依赖注入的实现方式

依赖注入的作用就是在使用Spring框架创建对象时,动态地将其所依赖的对象注入Bean组件中,其实现方式通常有两种,一种是属性setter方法注入,另一种是构造方法注入,具体介绍如下。

· 属性setter方法注入:指IoC容器使用setter方法注入被依赖的实例。通过调用无参构造器或无参静态工厂方法实例化Bean后,调用该Bean的setter方法,即可实现基于setter方法的依赖注入。

· 构造方法注入:指IoC容器使用构造方法注入被依赖的实例。基于构造方法的依赖注入通过调用带参数的构造方法来实现,每个参数代表着一个依赖。

了解了两种注入方式后,下面以属性setter方法注入的方式为例,讲解一下Spring容器在应用中是如何实现依赖注入的。

(1)在com.itheima.ioc包中,创建接口UserService,在接口中编写一个say()方法,如文件1-5所示。

文件1-5 UserService.java

1  package com.itheima.ioc;
2  public interface UserService {3
public void say();
4  }

(2)在com.itheima.ioc包中,创建UserService接口的实现类UserServiceImpl,在类中声明userDao属性,并添加属性的setter方法,如文件1-6所示。

文件1-6 UserServiceImpl.java

1  package com.itheima.ioc;
2  public class UserServiceImpl implements UserService {
3      // 声明UserDao属性
4      private UserDao userDao;
5      // 添加UserDao属性的setter方法,用于实现依赖注入
6      public void setUserDao(UserDao userDao) {
7          this.userDao = userDao;
8      }
9      // 实现的接口中方法
10     public void say() {
11         //调用userDao中的say()方法,并执行输出语句
12         this.userDao.say();
13         System.out.println("userService say hello World ! ");
14     }
15 }

(3)在配置文件applicationContext.xml中,创建一个id为userService的Bean,该Bean用于实例化UserServiceImpl类的信息,并将userDao的实例注入到userService中,其代码如下所示。

<! --添加一个id为userService的实例 -->
<bean id="userService" class="com.itheima.ioc.UserServiceImpl">
  <! -- 将id为userDao的Bean实例注入到userService实例中 -->
  <property name="userDao" ref="userDao" />
</bean>

在上述代码中,<property>是<bean>元素的子元素,它用于调用Bean实例中的setUserDao()方法完成属性赋值,从而实现依赖注入。其name属性表示Bean实例中的相应属性名,ref属性用于指定其属性值。

(4)在com.itheima.ioc包中,创建测试类TestDI,来对程序进行测试,编辑后如文件1-7所示。

文件1-7 TestDI.java

1  package com.itheima.ioc;
2  import org.springframework.context.ApplicationContext;
3  import
4     org.springframework.context.support.ClassPathXmlApplicationContext;
5  public class TestDI {
6      public static void main(String[] args) {
7          //1.初始化spring容器,加载配置文件
8          ApplicationContext applicationContext =
9             new ClassPathXmlApplicationContext("applicationContext.xml");
10         //2.通过容器获取UserService实例
11         UserService userService =
12           (UserService) applicationContext.getBean("userService");
13         //3.调用实例中的say()方法
14         userService.say();
15     }
16 }

(5)执行程序后,控制台的输出结果如图1-10所示。

图1-10 运行结果

从图1-10可以看出,使用Spring容器通过UserService实现类中的say()方法,调用了UserDao实现类中的say()方法,并输出了结果。这就是Spring容器属性setter注入的方式,也是实际开发中最为常用的一种方式。