Spring依赖注入
Spring依赖注入
Spring的IOC(Inversion Of Control 控制反转)
是通过DI(Dependency Injection 依赖注入)
实现的,依赖注入在Spring主要有以下几种方式:

一、基于XML的依赖注入
基于XML的依赖注入,指的是修改XML配置文件来实现依赖注入,主要包括setter设值注入和构造注入,另外还有一种自动注入,自动注入主要是针对引用类型属性的注入。
我们对XML依赖注入的讨论基于以下类和测试:
public class Staff {
private String name;
private int age;
private Company company;
public Staff() { }
public Staff(String name, int age, Company company) {
this.name = name;
this.age = age;
this.company = company;
}
public void setName(String name) { this.name = name; }
public void setAge(int age) { this.age = age; }
public void setCompany(Company company) { this.company = company; }
@Override
public String toString() {
return "Staff{" +
"name=‘" + name + ‘\‘‘ +
", age=" + age +
", company=" + company +
‘}‘;
}
}
public class Company {
private String name;
private String address;
public Company() { }
public Company(String name, String address) {
this.name = name;
this.address = address;
}
public void setName(String name) { this.name = name; }
public void setAddress(String address) { this.address = address; }
@Override
public String toString() {
return "Company{" +
"name=‘" + name + ‘\‘‘ +
", address=‘" + address + ‘\‘‘ +
‘}‘;
}
}
public class AppTest {
@Test
public void Test() {
String resource = "ApplicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(resource);
Staff staff = (Staff) context.getBean("Staff");
System.out.println(staff);
}
}
1、设值注入
使用
设值注入通过name
、value
和ref
属性。
name
: 属性名
value
: 简单类型值
ref
: 引用类型值
-
对简单类型(基本类型 + String)的属性,使用
name
和value
属性:<property name="属性名" value="属性值"/>
-
对引用类型的属性,使用
name
和ref
属性:<property name="属性名" ref="引用类型<bean>id属性值"/>
示例

测试

原理
我们在Staff
和Company
的无参构造函数和各属性setter方法中打印一些提示信息,以便于我们观察整个注入流程:
public class Staff {
private String name;
private int age;
private Company company;
public Staff() {
System.out.println("Staff‘s non-arg constructor."); //提示信息
}
public Staff(String name, int age, Company company) {
this.name = name;
this.age = age;
this.company = company;
}
public void setName(String name) {
System.out.println("Staff‘s setName " + name); //提示信息
this.name = name;
}
public void setAge(int age) {
System.out.println("Staff‘s setAge " + age); //提示信息
this.age = age;
}
public void setCompany(Company company) {
System.out.println("Staff‘s setCompany " + company); //提示信息
this.company = company;
}
@Override
public String toString() {
return "Staff{" +
"name=‘" + name + ‘\‘‘ +
", age=" + age +
", company=" + company +
‘}‘;
}
}
public class Company {
private String name;
private String address;
public Company() {
System.out.println("Company‘s non-arg constructor."); //提示信息
}
public Company(String name, String address) {
this.name = name;
this.address = address;
}
public void setName(String name) {
System.out.println("Company‘s setName " + name); //提示信息
this.name = name;
}
public void setAddress(String address) {
System.out.println("Company‘s setAddress " + address); //提示信息
this.address = address;
}
@Override
public String toString() {
return "Company{" +
"name=‘" + name + ‘\‘‘ +
", address=‘" + address + ‘\‘‘ +
‘}‘;
}
}
- Spring会先调用bean的无参构造函数,然后调用属性的setter方法,完成注入
运行观察:

TODO:至于对象的创建顺序,这里挖一个坑,以后再填。
- Spring是通过将"set"和
标签中的 name
属性(首字符变大写)拼接形成的方法名来调用setter方法,例如:
<property name="age" value="19"/> <!--调用setAge方法-->
<property name="company" ref="Company"/> <!--调用setCompany方法-->
此时我们向Staff的

向Staff
类中增加setAny
方法(但没有any
属性):

运行观察:

2、构造注入
使用
构造注入通过name
、index
、value
和ref
属性。
name
: 形参名
index
: 形参位置, 从0开始
value
: 简单类型值
ref
: 引用类型值
-
对简单类型:
<constructor-arg name="形参名" value="形参值"/>
<constructor-arg index="形参位置,从0开始" value="形参值"/>
-
对引用类型:
<constructor-arg name="形参名" ref="引用类型<bean>id属性值"/>
<constructor-arg index="形参位置,从0开始" ref="引用类型<bean>id属性值"/>
示例

测试

原理
我们在Staff
和Company
的有参构造函数中打印一些提示信息,以便于我们观察整个注入流程:
public class Staff {
private String name;
private int age;
private Company company;
public Staff() { }
public Staff(String name, int age, Company company) {
System.out.println("Staff‘s arg constructor."); //提示信息
this.name = name;
this.age = age;
this.company = company;
}
public void setName(String name) { this.name = name; }
public void setAge(int age) { this.age = age; }
public void setCompany(Company company) { this.company = company; }
@Override
public String toString() {
return "Staff{" +
"name=‘" + name + ‘\‘‘ +
", age=" + age +
", company=" + company +
‘}‘;
}
}
public class Company {
private String name;
private String address;
public Company() { }
public Company(String name, String address) {
System.out.println("Company‘s arg constructor."); //提示信息
this.name = name;
this.address = address;
}
public void setName(String name) { this.name = name; }
public void setAddress(String address) { this.address = address; }
@Override
public String toString() {
return "Company{" +
"name=‘" + name + ‘\‘‘ +
", address=‘" + address + ‘\‘‘ +
‘}‘;
}
}
- Spring会调用对应的有参构造函数,完成注入
运行观察:

TODO:至于对象的创建顺序,这里挖一个坑,以后再填。
3、自动注入
自动注入是针对引用类型属性的注入。当我们的bean中引用类型的数据过多时,就会出现下面这种画风:
<?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="xxx" class="xxx.xxx.xxx">
<property name="..." ref="..."/>
<property name="..." ref="..."/>
<property name="..." ref="..."/>
<property name="..." ref="..."/>
...
</bean>
<bean id="xxx" class="xxx.xxx.xxx">
...
</bean>
<bean id="xxx" class="xxx.xxx.xxx">
...
</bean>
<bean id="xxx" class="xxx.xxx.xxx">
...
</bean>
...
</beans>
ref
引用的都是其他byName
和byType
两种方法。
准备工作
-
为了完成此部分的分析,我们添加一个
Company
的子类InternetCompany
:public class InternetCompany extends Company { public InternetCompany() { System.out.println("InternetCompany‘s non-arg constructor"); } public InternetCompany(String name, String address) { super(name, address); System.out.println("InternetCompany‘s arg constructor"); } }
-
类型同源:
- 相同类型
- A是B的父类
- A是接口,B是其实现类
使用
-
byName
byName通过在
标签中将 autowire
属性设为byName
实现,Spring会查找和属性同名的标签,如果类型同源则注入。因为有 标签id属性和类属性同名的限制,所以如果有多个同源 也无所谓。 -
byType
byType通过在
标签中将 autowire
属性设为byType
实现,Spring会查找同源bean,并注入。不可以有多个同源标签。
示例
- byName

- byType

测试
- byName

- byType

二、基于注解的依赖注入
TODO:填个坑