依赖注入的概念
Spring的核心机制就是IoC(控制反转容器),IoC的另外一个称呼就是依赖注入(DI),这两个称呼是
从两个角度描述的同一个概念。通过依赖注入,JavaEE应用中的各种组件不需要一硬编码的方法进行耦合,当
一个Java实例需要其他Java实例时,系统自动提供需要的实例,无需程序显示获取。因此,依赖注入实现了组
件之间的耦合。
依赖注入和控制反转的含义相同,当某个Java对象(调用者)需要调用另一个Java对象(被调用者,即
被依赖对象)时,传统的方法是由调用者采用“new 被调用者”的方式来创建对象,这种方式会导致调用者和被
调用者之间的耦合性增加,对项目后期的升级和维护不利。
在使用Spring框架后,对象的实例不再由调用者创建,而是由Spring容器来创建,Spring容器会负责
控制程序之间的关系,而不是由调用者的程序代码直接控制。这样,控制权由应用程序代码转移到了Spring容
器,控制器发生了反转,这就是Spring的控制反转。
从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,这就相当于为调用
者注入了他依赖的实例,这就是Spring的依赖注入。
Spring提倡面向接口的编程,依赖注入的基本思想:明确地定义组件接口,独立开发各个组件,然后根
据组件的依赖关系组装运行。
依赖注入的类型
依赖注入的作用就是使用Spring框架创建对象时,动态地将其所依赖的对象注入到Bean组件中,其实现
方式主要有两种,一种是构造方法注入,另一种是属性setter方法注入。
1.构造方法注入
构造方法注入是指Spring容器使用构造方法注入被依赖的实例,构造方法可以是有参的或是无参的。大
多数情况下,我们都是通过构造方法来创建类对象,Spring也可以采用反射的方式,通过使用带参数的构造
方法来完成注入,每个参数代表一个依赖,这就是构造方法注入的原理。
package com.lsn.domain;
public class Account {
private Integer id;
private Integer uid;
private Double money;
public Account() {
}
public Account(Integer id, Integer uid, Double money) {
this.id = id;
this.uid = uid;
this.money = money;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
<?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.xsd">
<bean id="accountService4" class="com.lsn.domain.Account">
<constructor-arg name="name" value="test"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
</bean>
</beans>
2.属性setter方法注入
属性setter方法注入是指Spring容器使用setter方法注入被依赖的值或对象,是常见的一种依赖注入
的方式,这种注入方式具有高度的灵活性。属性setter方法注入要求Bean提供一个默认的构造方法,并为需
要注入的属性提供对应的setter方法。Spring先调用Bean的默认构造方法实例化Bean,然后通过反射的方式
调用setter方法注入属性值。
<?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.xsd">
<bean id="accountService2" class="com.lsn.domain.Account">
<property name="name" value="test"></property>
<property name="age" value="19"></property>
<property name="birthday" ref="now"></property>
</bean>
</beans>
两种依赖注入方式的对比
Spring同时支持构造方法注入和属性setter方法注入两种方式,它们各有优缺点,开发中可以根据实际
需要灵活选择,两种方式的特点总结如下:
1.使用setter方法时,与传统的JavaBean写法更类似,程序开发人员更容易了解和接受,通过setter
方法设定依赖关系显得更加直观、自然。
2、对于复杂的依赖关系,如果采用构造方法注入,会导致构造器过于臃肿,难以阅读。尤其是在某些属
性可选的情况下,多参数的构造器更加笨重。
3、构造方法注入可以在构造器中决定依赖关系的注入顺序,当某些属性的赋值操作有先后顺序时,这点
尤为重要。
4.对于依赖关系无须变化的Bean,构造方法注入更有用处。如果没有setter方法,所以的依赖关系全部
在构造器内部设定,后续代码不会对依赖产生破坏。依赖关系只能在构造器中设定,所以只有组件的创建者才
能改变组件的依赖关系。而对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。