Spring 依赖注入
上文介绍了如何在 spring.xml 文件中配置一个 bean
对象,但是当时所使用的属性都是基本数据类型和 String 字符串类型,那么如何将一个类的实例化对象注入到另一个类的对象中呢?这就是依赖注入(Dependency Injection)的问题,本文主要讲解的是如何在 XML 文件中完成对象的依赖注入。
1. 依赖注入(DI)
假如现在有这样的一个应用场景,建立学生信息类与家庭住址类的关联,我们很直观会想到创建 Student 类和 Address 类,然后会在 Student 类中新增一个 Address 类型的私有属性,最后在创建 student 对象之前,先创建 address 对象,然后通过有参构造或者 setAddress()
方法来完成对象的注入。
但现在我们知道:在Spring 框架中,对象只通过 XML 文件来配置,不需要开发者自己 new
来创建,那么如何在 XML 配置文件中绑定两个对象呢?下面通过实例代码来说明。
1、创建实体类 Address 和 Student
package com.trainingl.entity;
import lombok.Data;
@Data
public class Address {
private Integer id;
private String city;
}
package com.trainingl.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private Integer id;
private String name;
private Double score;
private Address address;
}
2、在 spring.xml 中配置 Student 和 Address 的 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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<bean id="student" class="com.trainingl.entity.Student">
<property name="id" value="1"></property>
<property name="name" value="小明"></property>
<property name="score" value="90"></property>
<property name="address" ref="addr"></property>
</bean>
<bean id="addr" class="com.trainingl.entity.Address">
<property name="id" value="1"></property>
<property name="city" value="武汉"></property>
</bean>
</beans>
- 通过配置
bean
标签完成对象的管理;id
:对象标识符(唯一)class
:对象的模板类(所有交给 IoC容器来管理的类必须有无参构造方法,因为 Spring 底层是通过反射机制来创建对象,调用的是无参构造方法)
- 对象的成员变量通过
property
标签完成对象属性的赋值操作;name
:成员变量名value
:成员变量值(基本数据类型、String 可以直接赋值,如果是其他引用类型,不能通过 value 赋值)ref
:将 IoC 中的另外一个 bean 赋值给当前 bean 的成员变量(被称为依赖注入)
这样就可以将 Address 的实例化对象与 student 对象关联起来,也可以说是将 address 对象注入到了 student 对象中,其实只需要使用到 ref 属性 id 即可。
3、测试类中获取 student 对象
package com.trainingl.test;
import com.trainingl.entity.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test2 {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Student student = (Student)applicationContext.getBean("student");
System.out.println(student);
}
}
2. IOC 自动装载
依赖注入的方式,除了通过配置 property 的 ref 属性将 bean 进行注入外,Spring 还提供了另外一种更加简便的方式——自动装置,不需要手动配置 property,IOC容器会自动选择 bean 完成依赖注入。
自动装置有两种方式:
- byName:通过属性名自动装载;
- byType:通过属性对应的数据类型自动装载;
1、创建实体类 Car 和 Student
package com.trainingl.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Car {
private int num;
private String brand;
}
package com.trainingl.entity;
import lombok.Data;
@Data
public class Person {
private Integer id;
private String name;
private Car car;
}
2、spring.xml 中配置 Car 和 Person 的 bean
标签,并通过自动装载进行依赖注入
byName:通过属性名自动装载
<?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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<!--自动装载-->
<bean id="car" class="com.trainingl.entity.Car">
<property name="num" value="22"></property>
<property name="brand" value="本田"></property>
</bean>
<bean id="person" class="com.trainingl.entity.Person" autowire="byName">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<!--创建person对象时,没有在property中配置car属性,所以IOC容器会自动进行装载-->
</bean>
</beans>
创建 person 对象时,没有在 property 中配置 car 属性,所以 IOC 容器会自动进行装载,autowire = "byName"
表示匹配属性名的方式去装载对应的 bean,Person 实体类中有 car 属性,所以就将 id=car
的 bean 注入到 person 对应的 bean中。
注意:通过 property 标签手动进行 car 的注入优先级更高,即:<property name="car" ref="car"></property>
也存在时,以 property 的配置为准。
3、测试类中获取 person 对象
package com.trainingl.test;
import com.trainingl.entity.Car;
import com.trainingl.entity.Person;
import com.trainingl.entity.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test2 {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Person person = (Person)applicationContext.getBean("person");
System.out.println(person);
}
}
当然,也可以通过 byType 即属性的数据类型来配置
<?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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<!--自动装载-->
<bean id="car1" class="com.trainingl.entity.Car">
<property name="num" value="22"></property>
<property name="brand" value="本田"></property>
</bean>
<bean id="car2" class="com.trainingl.entity.Car">
<property name="num" value="23"></property>
<property name="brand" value="丰田"></property>
</bean>
<bean id="person" class="com.trainingl.entity.Person" autowire="byType">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<!--创建person对象时,没有在property中配置car属性,所以IOC容器会自动进行装载-->
</bean>
</beans>
但需要注意的是,使用 byType 进行自动装载时,如果在 spring.xml 中配置两个或以上 Car 类型的 bean时,IOC容器就不知道应该将哪个 bean 装载到 person 对象中,所以会有如下的报错提示:
因此,使用 byType 进行自动装载时,spring.xml 中只能配置一个指定数据类型装载的 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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<!--自动装载-->
<bean id="car1" class="com.trainingl.entity.Car">
<property name="num" value="22"></property>
<property name="brand" value="本田"></property>
</bean>
<bean id="person" class="com.trainingl.entity.Person" autowire="byType">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<!--创建person对象时,没有在property中配置car属性,所以IOC容器会自动进行装载-->
</bean>
</beans>
同样地,在测试类中获取 person 对象。
本文通过实例介绍了XML配置文件两种依赖注入,一个是基于 ref
的 JavaBean 注入,另外一个是基于 autowire
的自动装载,可能因为注解的出现,以上两种方式并不常用了,但是对于理解和学习都是很有帮助的。