Spring 依赖注入(Dependency Injection,DI)和控制反转含义相同,它们是从两个角度描述的同一个概念。使用依赖注入可以更轻松的管理和测试应用程序。
当某个 Java 实例需要另一个 Java 实例时,传统的方法是由调用者创建被调用者的实例(例如,使用 new 关键字获得被调用者实例),而使用 Spring 框架后,被调用者的实例不再由调用者创建,而是由 Spring 容器创建,这称为控制反转。
Spring 容器在创建被调用者的实例时,会自动将调用者需要的对象实例注入给调用者,调用者通过 Spring 容器获得被调用者实例,这称为依赖注入。
依赖注入主要有两种实现方式,分别是 setter 注入(又称设值注入)和构造函数注入。具体介绍如下。
1)构造函数注入
指 IoC 容器使用构造函数注入被依赖的实例。可以通过调用带参数的构造函数实现依赖注入,每个参数代表一个依赖。
2)setter 注入
指 IoC 容器使用 setter 方法注入被依赖的实例。通过调用无参构造器或无参 static 工厂方法实例化 Bean 后,调用该 Bean 的 setter 方法,即可实现基于 setter 的 DI。
在 Spring 实例化 Bean 的过程中,首先会调用默认的构造方法实例化 Bean 对象,然后通过 Java 的反射机制调用 setXxx() 方法进行属性的注入。因此,setter 注入要求 Bean 的对应类必须满足以下两点要求。
- 必须提供一个默认的无参构造方法。
- 必须为需要注入的属性提供对应的 setter 方法。
使用 setter 注入时,在 Spring 配置文件中,需要使用 <bean> 元素的子元素 <property>
为每个属性注入值。而使用构造注入时,在配置文件中,主要使用 <constructor-arg> 标签定义构造方法的参数,使用其
value 属性(或子元素)设置该参数的值。
构造函数注入
下面使用 <constructor-arg> 标签实现构造函数注入。
在 <constructor-arg> 标签中,包含 ref、value、type、index 等属性。value
属性用于注入基本数据类型以及字符串类型的值;ref 属性用于注入已经定义好的 Bean;type
属性用来指定对应的构造函数,当构造函数有多个参数时,可以使用 index 属性指定参数的位置,index 属性值从 0 开始。
例 1
下面使用 Eclipse IDE 演示通过构造函数注入依赖项,步骤如下:
- 创建 SpringDemo 项目,并在 src 目录下创建 net.biancheng 包。
- 添加相应的 jar 包,可以参考《第一个Spring程序》一节。
- 在 net.biancheng 包下创建 Person、Man 和 MainApp 类。
- 在 src 目录下创建 Spring 配置文件 Beans.xml。
- 运行 SpringDemo 项目。
Person 类代码如下。
package net.biancheng; public class Person { private Man man; public Person(Man man) { System.out.println("在Person的构造函数内"); this.man = man; } public void man() { man.show(); } }
Man 类代码如下。
package net.biancheng; public class Man { private String name; private int age; public Man() { System.out.println("在man的构造函数内"); } public Man(String name, int age) { System.out.println("在man的有参构造函数内"); this.name = name; this.age = age; } public void show() { System.out.println("名称:" + name + "\n年龄:" + age); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
Beans.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-3.0.xsd"> <bean id="man" class="net.biancheng.Man"> <constructor-arg value="bianchengbang" /> <constructor-arg value="12" type="int" /> </bean> <bean id="person" class="net.biancheng.Person"> <constructor-arg ref="man" type="java.lang.String"/> </bean> </beans>
MainApp 类代码如下。
package net.biancheng; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); Person person = (Person) context.getBean("person"); person.man(); } }
运行结果如下。
在man的有参构造函数内
在Person的构造函数内
名称:bianchengbang
年龄:12
setter注入
下面使用 <property> 标签实现 setter 注入。
在 <property> 标签中,包含 name、ref、value 等属性。name 用于指定参数名称;value 属性用于注入基本数据类型以及字符串类型的值;ref 属性用于注入已经定义好的 Bean。
例 2
在例 1 的基础上修改 Man 类的内容,代码如下。
格式化复制
package net.biancheng; public class Man { private String name; private int age; public Man() { System.out.println("在man的构造函数内"); } public Man(String name, int age) { System.out.println("在man的有参构造函数内"); this.name = name; this.age = age; } public void show() { System.out.println("名称:" + name + "\n年龄:" + age); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
Beans.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-3.0.xsd"> <bean id="person" class="net.biancheng.Person"> <property name="man" ref="man" /> </bean> <bean id="man" class="net.biancheng.Man"> <property name="name" value="bianchengbang" /> <property name="age" value="12" /> </bean> </beans>
运行结果如下。
在man的构造函数内
在setMan方法内
名称:bianchengbang
年龄:12
来源:
http://c.biancheng.net/spring/di.html