Spring的核心机制——依赖注入(DI),也称为控制反转。所谓依赖注入,就是指要调用另一个对象协助时,无须在代码中创建被调用者,而且依赖于外部的注入。依赖注入通常有两种:设置注入与构造注入。
设置注入
设置注入是通过setter方法注入被调用者的实例,这种方式简单、直观
例子:
首先定义两个接口
Human接口
package Interface;
public interface Human {
void speak();
}
Language接口
package Interface;
public interface Language {
public String kind();
}
从两个接口分别继承出两个类
Chinese类
package Class;
import Interface.Human;
import Interface.Language;
public class Chinese implements Human {
private Language lan;
@Override
public void speak() {
// TODO 自动生成的方法存根
System.out.println(lan.kind());
}
public void setLan(Language lan){
this.lan=lan;
}
}
English类
package Class;
import Interface.Language;
public class English implements Language {
@Override
public String kind() {
// TODO 自动生成的方法存根
return "中国人也会说英语!";
}
}
可以看到,在Chinese类中,要用到English类,可以通过配置Spring的配置文件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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<!--定义第一个Bean,注入Chinese类对象-->
<bean id="chinese" class="Class.Chinese">
<!--property元素用来指定需要容器注入的属性,lan属性需要容器注入,ref就指向lan注入的Id-->
<property name="lan" ref="english"></property>
</bean>
<!--注入English-->
<bean id="english" class="Class.English"></bean>
</beans>
在配置文件中,各个Bean之间的依赖关系放在配置文件中完成,而不是用代码来体现,减少了耦合度。注意,配置文件的Bean的class属性值不能是接口,必须是真正的实现类。
Spring会自动接管每个Bean定义里的property元素定义。Spring会在执行无参数的构造器并创建默认的Bean实例后,调用对应的set方法为程序注入属性值。
每个Bean的id属性是该Bean的唯一标识,程序通过id属性访问Bean,而且各个Bean之间的依赖关系也通过id属性关联。
测试代码如下:
package Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import Interface.Human;
public class test {
public static void main(String[] args) {
// TODO 自动生成的方法存根
//ApplicationContext继承自BeanFactory,
//调用FileSystemXmlApplicationContext可以从指定的文件系统路径中寻找指定的XML配置文件,找到并装载完成ApplicationContext的实例化工作。
ApplicationContext applicationContext=new FileSystemXmlApplicationContext("src/applicationContext.xml");
Human human=null;
human=(Human)applicationContext.getBean("chinese");//获取叫做"chinese"的Bean
human.speak();
}
}
构造注入
利用构造函数来设置依赖注入的方式,称为构造注入。这种方式在构造实例时,就已经为其完成了属性的初始化。
例如,只需要对Chinese类进行简单的修改
package Class;
import Interface.Human;
import Interface.Language;
public class Chinese implements Human {
private Language lan;
public Chinese(Language lan) {
super();
this.lan = lan;
}
@Override
public void speak() {
// TODO 自动生成的方法存根
System.out.println(lan.kind());
}
}
此时,Chinese类无须lan属性的set方法
配置文件也需要简单的修改
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<!--定义第一个Bean,注入Chinese类对象-->
<bean id="chinese" class="Class.Chinese">
<!--使用构造注入,为Chinese实例注入Language实例-->
<constructor-arg ref="english"></constructor-arg>
</bean>
<!--注入English-->
<bean id="english" class="Class.English"></bean>
</beans>
两种依赖注入的方法区别在于创建Human实例中的Language属性的时间不同。设置注入是先创建一个默认的Bean实例,然后调用对应的set方法注入依赖关系,而构造注入则是在创建Bean实例时,已经完成了依赖关系的注入。