2.1、基于XML的DI注入
学习资源:动力节点的2020最新Spring框架教程【IDEA版】-Spring框架从入门到精通
Spring 容器在默认调用无参构造器创建对象后,就要对 bean 对象的属性进行初始化。属性初始化是由容器自动完成的,称为注入。
根据注入方式的不同,常用的有两类:
- set 注入
- 构造注入
0、XML配置常用到的标签
0.1、bean
该标签用于注册一个 Java bean 的实例对象。
标签属性:
- id:从容器获取该对象使用的标识符,自定义,要求具有唯一性
- class:容器中对象的类型,要求使用全限定名称,且不能是接口
- scope:用于设置从容器中获取到的对象的作用域,默认值为 singleton
- singleton:对象是单例的,在容器中只存在一个共享实例,所有对该类型 bean 的依赖都引用同一个实例;容器创建的同时这个共享实例就被自动创建完成了,只要容器不销毁或退出,该类型的单一实例就会一直存活。
- prototype:对象是多例的,容器创建启动后,并不会直接创建容器中的 bean 对象,而是出现请求时,容器才会新建一个对象,所以每次获取的对象都是不同的。
- request、session、global session:这三个只适用于 Web 应用程序
- request:
- session:
- global session:
- autowire:bean 对象自动装配
代码实例:School 的实例对象需要注入 Student 的实例对象
//创建两个类
public class Student {
private int age;
public void setAge(int age) {
this.age = age;
}
}
public class School {
// 学校里有个学生
private Student student;
private int area;
public void setStudent(Student student) {
this.student = student;
}
public void setArea(int area) {
this.area = area;
}
}
<bean id="student" class="com.chen.pojo.Student" >
<property name="age" value="张三" />
</bean>
<!-- 因为属性名是 student, 上面bean的 id 也是 student,可以完成自动装配 -->
<bean id="school" class="com.chen.pojo.School" autowire="byName">
<property name="area" value=3000 />
</bean>
---------------------------------------------------------------------------------
<bean id="stu" class="com.chen.pojo.Student" >
<property name="age" value="张三" />
</bean>
<!-- 因为属性的类型是 com.chen.pojo.Student, 上面bean的 class 也是 com.chen.pojo.Student,可以完成自动装配 -->
<bean id="school" class="com.chen.pojo.School" autowire="byType">
<property name="area" value=3000 />
</bean>
0.2、property
该标签在 <\bean> 标签内部使用,用于给容器中的 bean 对象的的属性初始化(赋值)。
0.3、constructor-arg
该标签在 <\bean> 标签内部使用,用于为容器中的 bean 对象的有参构造器传值。
0.4、alias
用于为容器中的 bean 设置别名,可设置多个别名。name= bean 的 id
, alias=自定义的别名[]
<alias name="student" alias="stu, stud"/>
0.5、import
用于导入其他 Spring 配置文件中的配置信息
<import resource="{path}/other-application-config.xml"/>
1、set 注入(常用)
set 注入也称作设值注入,它是指通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在 Spring 的依赖注入中大量使用。
要求:被注入的属性,类中必须创建 set 方法,set 方法的方法名由set + 属性首字母大写;如果某个属性是 boolean 类型,也可以创建它的 is 方法。
注意:实体类可以没有 getter,但是必须要有 setter;set 注入只是使用 setter
1.1、注入简单类型
使用 <\property> 的 value 属性
public class Student{
private String name;
private int age;
}
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="小明"/>
<property name="age" value="16"/>
</bean>
1.2、注入 bean 对象
1.2.1、手动注入
使用 <\property> 的 ref 属性,其值为其他容器中 bean 的 id
/创建两个类
public class Student {
private int age;
public void setAge(int age) {
this.age = age;
}
}
public class School {
// 学校里有个学生
private Student student;
private int area;
public void setStudent(Student student) {
this.student = student;
}
public void setArea(int area) {
this.area = area;
}
}
<bean id="stu" class="com.chen.pojo.Student" >
<property name="age" value="张三" />
</bean>
<!-- 不设置自动装配 -->
<bean id="school" class="com.chen.pojo.School">
<property name="student" ref="stu"/>
<property name="area" value="3000" />
</bean>
1.2.2、自动注入
通过设置 <\bean> 标签的 autowire 属性的值,可以实现引用类型属性的自动装配,该属性默认值为 no 。
属性值:
- byName:按引用类型的属性名自动注入
当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用 byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean 类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。 - byType:按引用类型的(数据)类型自动注入
要求:配置文件中被调用者 bean 的 class 属性指定的类,要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同,要么有 is-a 关系(子类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配哪一个了。
代码实例:School 的实例对象需要注入 Student 的实例对象
//创建两个类
public class Student {
private int age;
public void setAge(int age) {
this.age = age;
}
}
public class School {
private Student student;
private int area;
public void setStudent(Student student) {
this.student = student;
}
public void setArea(int area) {
this.area = area;
}
}
<bean id="student" class="com.chen.pojo.Student" >
<property name="age" value="张三" />
</bean>
<bean id="school" class="com.chen.pojo.School" autowire="byName">
<property name="area" value=3000 />
</bean>
---------------------------------------------------------------------------------
<bean id="stu" class="com.chen.pojo.Student" >
<property name="age" value="张三" />
</bean>
<bean id="school" class="com.chen.pojo.School" autowire="byType">
<property name="area" value=3000 />
</bean>
1.3、注入数组
使用 <\property> 的子标签 <\array>
public class Student {
private String[] hobbys;
public void setHobbys(String[] hobbys) {
this.hobbys = hobbys;
}
}
<bean id="stu" class="com.chen.pojo.Student" >
<property name="hobbys">
<array>
<value>听歌</value>
<value>看电影</value>
<value>打游戏</value>
</array>
</property>
</bean>
1.4、注入 List
使用 <\property> 的子标签 <\list>
public class Student {
private List hobbys;
public void setHobbys(List hobbys) {
this.hobbys = hobbys;
}
}
<bean id="stu" class="com.chen.pojo.Student" >
<property name="hobbys">
<list>
<value>听歌</value>
<value>看电影</value>
<value>打游戏</value>
</list>
</property>
</bean>
1.5、注入 Map
使用 <\property> 的子标签 <\map> ,<\map> 标签内部再使用子标签 <\entry>
public class Student {
// 快递单号
private Map<String, Integer> trackingNumbers;
public void setExpressPackages(Map<String, Integer> trackingNumbers) {
this.trackingNumbers = trackingNumbers;
}
}
<bean id="stu" class="com.chen.pojo.Student" >
<property name="card">
<map>
<entry key="邮政" value="474205742378723"/>
<entry key="顺丰" value="272782887272187"/>
</map>
</property>
<bean/>
1.6、注入 Set
使用 <\property> 的子标签 <\set>
public class Student {
// 学校的课程
private HashSet<String> courses;
public void setCourses(HashSet<String> courses) {
this.courses = courses;
}
}
<bean id="stu" class="com.chen.pojo.Student" >
<property name="courses">
<set>
<value>语文</value>
<value>数学</value>
<value>英语</value>
</set>
</property>
<bean/>
1.7、注入 NULL
属性值为 null 时
public class Student {
// 学校的课程
private Lover lover;
public void setLover(Lover lover) {
this.lover = lover;
}
}
<bean id="stu" class="com.chen.pojo.Student" >
<property name="lover"><null/></property>
<bean/>
1.8、注入 Properties
public class Student {
private Properties prop;
public void setProp(Properties prop) {
this.prop = prop;
}
}
<bean id="student" class="com.chen.pojo.Student" >
<property name="prop">
<props>
<prop key="name">张三</prop>
<prop key="age">17</prop>
</props>
</property>
</bean>
1.9、注入 properties 文件属性
对象属性可以从属性配置文件中注入
name=张三
age=16
public class Student {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
<!-- 先加载属性配置文件 -->
<context:property-placeholder location="classpath:student.properties"/>
<bean id="student" class="com.chen.pojo.Student">
<property name="name" value="${name}"></property>
<property name="age" value="${age}"></property>
</bean>
2、构造注入
set 注入:Spring 容器默认使用实体类的无参构造器创建实例对象,需要在 xml 中使用 <\property> 为其属性赋值。
构造注入:容器使用实体类的指定的有参构造器来创建对象的同时在有参构造器中为属性赋值,需要在 xml 中使用 <\constructor-arg> 为构造器的参数赋值。
<\constructor-arg> 是 <\bean> 的子标签,一个该标签表示有参构造器的一个参数,所以在实体类有多个有参构造器的情况下,容器可根据该标签的数目来使用指定的有参构造器完成创建实例对象,<\bean> 下两个 <\constructor-arg> 即表示容器要使用有两个参数的有参构造器。
<\constructor-arg> 标签属性:
- name:表示构造器的形参名,注意不是属性名!
- index:指明该参数对应着构造器的第几个参数。(从左往右是 0、1 ... 构造器如果有 3 个参数,index 就到是 [0, 1, 2] )
该属性不要也行,name 与形参名保持一致就行;但要注意,若参数类型相同,或之间有包含关系,则需要保证赋值顺序要与构造器中的参数顺序一致。 - value:简单类型的值
- ref:引用(bean)类型,对应容器中的其他对象
- type:表示根据构造器形参的类型(不能说基础类型)为其赋值,可与 name 一起使用,也可以单独使用
注意:只使用 type 来为形参赋值,若参数类型相同或之间有包含关系,则需要保证赋值顺序要与构造器中的参数顺序一致,或使用 index 标定顺序
通过构造注入,注入其他类型(非简单、非引用类型)的参数和上面 set 注入的参数类型一致,都要使用其他子标签 <\array>、<\list> 等子标签进行赋值。
public class Student {
private String name;
private String age;
private School school;
public Student() {
}
public Student(String stuName) {
this.name = stuName;
}
public Student(String stuName, String stuAge, School stuSchool) {
this.name = stuName;
this.age = stuAge;
this.school = stuSchool;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class School {
private int area;
}
<bean id="student" class="com.chen.pojo.Student" >
<constructor-arg name="stuAge" value="18"/>
<constructor-arg name="stuName" value="李四"/>
<constructor-arg name="stuSchool" ref="school"/>
</bean>
<bean id="school" class="com.chen.pojo.School">
<property name="area" value="1000"/>
</bean>