Spring框架从入门到入土(二):Spring之基于XML的DI(依赖注入)
di的实现语法有两种,表示创建对象,给属性赋值。
di的实现有两种:
- 在spring的配置文件中,使用标签和属性完成,叫做基于xml的di实现。
- 使用spring中的注解,完成属性赋值,叫做基于注解的di实现
注入分类
di的语法分类有两种:
- set注入(设置注入):spring调用类的set方法,在set方法可以实现属性的赋值。
- 构造注入:spring调用类的有参数构造方法,创建对象,在构造方法中完成。
set注入(掌握)
简单类型的设置注入
- 编写配置文件
<!--声明student对象
注入:就是赋值的意思
简单类型:spring规定,java的基本数据类型和String类型都是简单类型
di:给属性赋值
1. set注入(设置注入):spring调用类的set方法,可以在set方法中完成赋值。
①简单类型的set注入
<property name = "属性名字" value = "此属性的值"/>
一个property只能给一个属性赋值
<property....../>
-->
<bean id="student" class="com.liar.ba01.Student">
<property name="name" value="张三"/>
<property name="age" value="20"/>
</bean>
- 测试方法
@Test
public void test01(){
String config = "ba01/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
//从容器中获取某个对象,调用对象的方法
Student stu = (Student)ac.getBean("student");
//使用创建好的对象
System.out.println(stu);
}
- 测试结果,赋值成功
注意事项:
-
spring先执行无参构造,创建对象,再调用set方法进行赋值。
-
如果没有set方法,spring会报错。
-
set方法不一定会赋值,因为spring只负责调用set方法,不负责检查set方法中是否赋值。
-
属性名对应的属性值即使是整形也必须要带上双引号
<property name="age" value="20"/>
引用类型的设置注入
- 编写一个学校对象
package com.liar.ba02;
/**
* @author liar
* @date 编写时间: 2022/3/23 14:40
*/
public class School {
private String name;
private String address;
public School() {
}
public School(String name, String address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "School{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
- 编写一个含有school对象的Student对象
package com.liar.ba02;
/**
* @author liar
* @date 编写时间: 2022/3/23 12:58
*/
public class Student {
private String name;
private int age;
/*
* 声明一个引用类型
*/
private School school;
public Student() {
System.out.println("spring会调用类的无参数构造方法创建对象!!");
}
public Student(String name, int age, School school) {
this.name = name;
this.age = age;
this.school = school;
}
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", school=" + school +
'}';
}
}
- 编写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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
②引用类型的注入:spring调用类的set方法
<bean id="xxx" class="xxx">
<property name="属性名" ref="bean的id(对象的名称)"/>
</bean>
-->
<!--声明School对象-->
<bean id="mySchool" class="com.liar.ba02.School">
<property name="name" value="北京大学"/>
<property name="address" value="北京"/>
</bean>
<!--给student对象赋值-->
<bean id="myStudent" class="com.liar.ba02.Student">
<property name="name" value="李四"/>
<property name="age" value="18"/>
<!--赋值school-->
<property name="school" ref="mySchool"/>
</bean>
</beans>
- 编写测试方法
@Test
public void test02(){
String config = "ba02/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
//从容器中获取某个对象,调用对象的方法
Student stu = (Student)ac.getBean("myStudent");
//使用创建好的对象
System.out.println(stu);
}
- 测试结果
构造注入(理解)
使用name属性实现构造注入
- 编写xml文件
<!--声明School对象-->
<bean id="mySchool" class="com.liar.ba02.School">
<property name="name" value="北京大学"/>
<property name="address" value="北京"/>
</bean>
<!--构造注入: spring调用类的有参数构造方法,在创建对象的同时,在构造方法中给属性赋值
构造注入使用<constructor-arg>标签
标签属性:
name:表示构造方法的形参名
index:表示构造方法的参数位置,参数从左到右位置是0,1,2....
value:构造方法是简单类型的用value
ref:构造方法是引用类型的,用ref
-->
<bean id="myStudent" class="com.liar.ba02.Student">
<constructor-arg name="name" value="王五"/>
<constructor-arg name="age" value="19"/>
<constructor-arg name="school" ref="mySchool"/>
</bean>
- 测试方法不变,测试结果如下
使用index属性实现构造注入
<!--声明School对象-->
<bean id="mySchool" class="com.liar.ba02.School">
<property name="name" value="清华大学"/>
<property name="address" value="北京海淀区"/>
</bean>
<bean id="myStudent" class="com.liar.ba02.Student">
<constructor-arg index="0" value="赵六"/>
<constructor-arg index="1" value="29"/>
<constructor-arg index="2" ref="mySchool"/>
</bean>
构造注入创建文件对象
<!--创建file,使用构造注入-->
<bean id="myFile" class="java.io.File">
<constructor-arg name="parent" value="E:\Workplace\JWorkPlace\spring-course\spring-01-hello"/>
<constructor-arg name="child" value="readme.txt"/>
</bean>
@Test
public void test04(){
String config = "ba02/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
//创建文件
File file = (File)ac.getBean("myFile");
//读取文件名
System.out.println(file.getName());
//读取文件内容
BufferedReader reader = null;
StringBuffer sbf = new StringBuffer();
try {
reader = new BufferedReader(new FileReader(file));
String tempStr;
while ((tempStr = reader.readLine()) != null) {
sbf.append(tempStr);
}
reader.close();
System.out.println(sbf.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
测试结果
引用类型属性自动注入
对于引用类型属性的注入,可以不在配置文件中显式注入,可以通过为<bean/>表签设置autowire属性值,为引用类型属性进行隐式自动注入(默认是不注入属性)。根据自动注入的判断标准不同,可以分为两种:
byName:根据名称自动注入
byType:根据类型自动注入
byName自动注入
- xml文件
<!--
引用类型的自动注入:spring框架可以根据某些规则给引用类型进行赋值
byName:java类中引用属性名和spring容器中(配置文件)<bean>的id名称一样,且数据类型是一致的
这样的容器中的bean,spring可以赋值给引用类
语法:
<bean id="xx" class="yyy" autowire="byName">
简单属性赋值
</bean>
-->
<!-- 声明School对象-->
<bean id="school" class="com.liar.ba03.School">
<property name="name" value="清华大学"/>
<property name="address" value="海淀区"/>
</bean>
<bean id="myStudent" class="com.liar.ba03.Student" autowire="byName">
<property name="name" value="小梁"/>
<property name="age" value="20"/>
</bean>
- 测试
@Test
public void test01(){
String config = "ba03/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
//从容器中获取某个对象,调用对象的方法
Student stu = (Student)ac.getBean("myStudent");
//使用创建好的对象
System.out.println(stu);
}
byType自动注入
测试同源的第二类:
byType: java类中引用类型的数据类型和spring容器中(配置文件)<bean>的class属性是同源关系。
这样的bean可以赋值给引用类型
同源就是同一类的意思:
1. java类中引用类型的数据类型和bean的class的值是一样的。
2. java类中引用类型的数据类型和bean的class的值是父子类关系。
2. java类中引用类型的数据类型和bean的class的值是接口和实现类的关系。
编写一个子类继承School
package com.liar.ba03;
/**
* @author liar
* @date 编写时间: 2022/3/23 17:14
*/
public class PrimarySchool extends School{
}
<!--声明一个学校的子类-->
<bean id="primary" class="com.liar.ba03.PrimarySchool">
<property name="name" value="北京小学"/>
<property name="address" value="大兴区"/>
</bean>
<bean id="myStudent" class="com.liar.ba03.Student" autowire="byType">
<property name="name" value="小梁"/>
<property name="age" value="20"/>
</bean>
注意:在bytype中声明bean的时候,只能有一个符合条件的,多于两个会报错。
多配置文件
优势:
- 每个文件的大小比一个文件要小很多。效率高
- 避免多人竞争带来的冲突
多文件的配置方式:
- 按照功能模块:一个模块一个配置文件。
- 按照类的功能:数据库相关配置一个文件配置文件,做事务的一个配置文件,做service功能的一个配置文件。
包含关系的配置文件:
- 学生模块的配置文件
<?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="myStudent" class="com.liar.ba03.Student" autowire="byType">
<property name="name" value="小梁"/>
<property name="age" value="20"/>
</bean>
</beans>
- 学校模块的配置文件
<?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">
<!--声明School对象-->
<bean id="school" class="com.liar.ba03.School">
<property name="name" value="清华大学"/>
<property name="address" value="海淀区"/>
</bean>
</beans>
- 主配置文件
<?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">
<!--
主配置文件:包含其他的配置文件的,主配置文件一般不定义对象.
语法:<import resource="其他配置文件的路径"/>
关键字:"classpath:"表示类路径(class文件所在的目录),在spring的配置文件中要指定其他文件的位置,
需要使用classpath,告诉spring到哪去加载读取文件.
-->
<import resource="classpath:ba03/spring-school.xml"/>
<import resource="classpath:ba03/spring-student.xml"/>
<!--也可以使用通配符号
注意:主配置文件名称不能包含在通配符范围内
-->
<import resource="classpath:ba03/spring-*.xml"/>
</beans>