Spring框架第二章(基于XML管理bean)

文章目录

一、入门案例

①创建Maven项目
②引入依赖

c 复制代码
<dependencies>
	<!-- 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包 -->
	<dependency>
	  	<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
		<version>5.3.1</version>
	</dependency>
	<!-- junit测试 -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.12</version>
		<scope>test</scope>
 	</dependency>
</dependencies>

③创建类HelloWorld

c 复制代码
public class HelloWorld {
	public void sayHello(){
		System.out.println("helloworld");
	}
}

④创建Spring的配置文件(创建与resources文件下)

⑤在Spring的配置文件中配置bean

c 复制代码
<!--
配置HelloWorld所对应的bean,即将HelloWorld的对象交给Spring的IOC容器管理
通过bean标签配置IOC容器所管理的bean
属性:
id:设置bean的唯一标识
class:设置bean所对应类型的全类名
-->
<bean id="helloworld" class="com.atguigu.spring.bean.HelloWorld"></bean>

⑥创建测试类测试

c 复制代码
@Test
public void testHelloWorld(){
	ApplicationContext ac = new
	ClassPathXmlApplicationContext("applicationContext.xml");
	HelloWorld helloworld = (HelloWorld) ac.getBean("helloworld");
	helloworld.sayHello();
}

⑦思路

⑧注意

Spring 底层默认通过反射技术调用组件类的无参构造器来创建组件对象,这一点需要注意。如果在需要无参构造器时,没有无参构造器,则会抛出下面的异常:

c 复制代码
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'helloworld' defined in class path resource [applicationContext.xml]: Instantiation of bean
failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed
to instantiate [com.atguigu.spring.bean.HelloWorld]: No default constructor found; nested
exception is java.lang.NoSuchMethodException: com.atguigu.spring.bean.HelloWorld.<init>
()

二、获取bean的三种方式

①方式一:根据id获取

由于 id 属性指定了 bean 的唯一标识,所以根据 bean 标签的 id 属性可以精确获取到一个组件对象。

上个实验中我们使用的就是这种方式。

c 复制代码
@Test
public void testHelloWorld(){
	ApplicationContext ac = new
	ClassPathXmlApplicationContext("helloworld");
	HelloWorld bean = ac.getBean(HelloWorld.class);
bean.sayHello();
}

②方式二:根据类型获取

c 复制代码
@Test
public void testHelloWorld(){
	ApplicationContext ac = new
	ClassPathXmlApplicationContext("applicationContext.xml");
	HelloWorld bean = ac.getBean(HelloWorld.class);
bean.sayHello();
}

③方式三:根据id和类型

c 复制代码
@Test
public void testHelloWorld(){
 	ApplicationContext ac = new
	ClassPathXmlApplicationContext("applicationContext.xml");
	HelloWorld bean = ac.getBean("helloworld", HelloWorld.class);
bean.sayHello();
}

④注意

当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个

当IOC容器中一共配置了两个:

c 复制代码
根据类型获取时会抛出异常:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean
of type 'com.atguigu.spring.bean.HelloWorld' available: expected single matching bean but
found 2: helloworldOne,helloworldTwo

⑤扩展

如果组件类实现了接口,根据接口类型可以获取 bean 吗?

可以,前提是bean唯一

如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?

不行,因为bean不唯一

⑥结论

根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看:『对象 instanceof 指定的类

型』的返回结果,只要返回的是true就可以认定为和类型匹配,能够获取到。

三、依赖注入之setter注入

①创建学生类Student

c 复制代码
public class Student {
private Integer id;
private String name;
private Integer age;
private String sex;
public Student() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}

②配置bean时为属性赋值

c 复制代码
<bean id="studentOne" class="com.atguigu.spring.bean.Student">
<!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
<!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关)
-->
<!-- value属性:指定属性值 -->
<property name="id" value="1001"></property>
<property name="name" value="张三"></property>
<property name="age" value="23"></property>
<property name="sex" value="男"></property>
</bean>

③测试

c 复制代码
@Test
public void testDIBySet(){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-di.xml");
Student studentOne = ac.getBean("studentOne", Student.class);
System.out.println(studentOne);
}

四、依赖注入之构造器注入

①在Student类中添加有参构造

c 复制代码
public Student(Integer id, String name, Integer age, String sex) {
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
}

②配置bean

c 复制代码
<bean id="studentTwo" class="com.atguigu.spring.bean.Student">
<constructor-arg value="1002"></constructor-arg>
<constructor-arg value="李四"></constructor-arg>
<constructor-arg value="33"></constructor-arg>
<constructor-arg value="女"></constructor-arg>
</bean>

注意:

constructor-arg标签还有两个属性可以进一步描述构造器参数:

index属性:指定参数所在位置的索引(从0开始)

name属性:指定参数名
③测试

c 复制代码
@Test
public void testDIBySet(){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-di.xml");
Student studentOne = ac.getBean("studentTwo", Student.class);
System.out.println(studentOne);
}

五、特殊值处理

①字面量赋值

什么是字面量?

int a = 10;

声明一个变量a,初始化为10,此时a就不代表字母a了,而是作为一个变量的名字。当我们引用a

的时候,我们实际上拿到的值是10。

而如果a是带引号的:'a',那么它现在不是一个变量,它就是代表a这个字母本身,这就是字面

量。所以字面量没有引申含义,就是我们看到的这个数据本身。

c 复制代码
<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>

②null值

c 复制代码
<property name="name">
<null />
</property>

注意:

c 复制代码
<property name="name" value="null"></property>

以上写法,为name所赋的值是字符串null

③xml实体

c 复制代码
<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 解决方案一:使用XML实体来代替 -->
<property name="expression" value="a &lt; b"/>

④CDATA节

c 复制代码
<property name="expression">
<!-- 解决方案二:使用CDATA节 -->
<!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
<!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
<!-- 所以CDATA节中写什么符号都随意 -->
<value><![CDATA[a < b]]></value>
</property>

六、为类类型属性赋值

①创建班级类Clazz

c 复制代码
public class Clazz {
private Integer clazzId;
private String clazzName;
public Integer getClazzId() {
return clazzId;
}
public void setClazzId(Integer clazzId) {
this.clazzId = clazzId;
}
public String getClazzName() {
return clazzName;
}
public void setClazzName(String clazzName) {
this.clazzName = clazzName;
}
@Override
public String toString() {
return "Clazz{" +
"clazzId=" + clazzId +
", clazzName='" + clazzName + '\'' +
'}';
}
public Clazz() {
}
public Clazz(Integer clazzId, String clazzName) {
this.clazzId = clazzId;
this.clazzName = clazzName;
}
}

②修改Student类

在Student类中添加以下代码:

c 复制代码
private Clazz clazz;
public Clazz getClazz() {
return clazz;
}
public void setClazz(Clazz clazz) {
this.clazz = clazz;
}

③方式一:引用外部已声明的bean

配置Clazz类型的bean:

c 复制代码
<bean id="clazzOne" class="com.atguigu.spring.bean.Clazz">
<property name="clazzId" value="1111"></property>
<property name="clazzName" value="财源滚滚班"></property>
</bean>

为Student中的clazz属性赋值:

c 复制代码
<bean id="studentFour" class="com.atguigu.spring.bean.Student">
<property name="id" value="1004"></property>
<property name="name" value="赵六"></property>
<property name="age" value="26"></property>
<property name="sex" value="女"></property>
<!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
<property name="clazz" ref="clazzOne"></property>
</bean>

④方式二:内部bean

c 复制代码
<bean id="studentFour" class="com.atguigu.spring.bean.Student">
<property name="id" value="1004"></property>
<property name="name" value="赵六"></property>
<property name="age" value="26"></property>
<property name="sex" value="女"></property>
<property name="clazz">
<!-- 在一个bean中再声明一个bean就是内部bean -->
<!-- 内部bean只能用于给属性赋值,不能在外部通过IOC容器获取,因此可以省略id属性 -->
	<bean id="clazzInner" class="com.atguigu.spring.bean.Clazz">
		<property name="clazzId" value="2222"></property>
		<property name="clazzName" value="远大前程班"></property>
	</bean>
</property>
</bean>

⑤方式三:级联属性赋值

c 复制代码
<bean id="studentFour" class="com.atguigu.spring.bean.Student">
<property name="id" value="1004"></property>
<property name="name" value="赵六"></property>
<property name="age" value="26"></property>
<property name="sex" value="女"></property>
<!-- 一定先引用某个bean为属性赋值,才可以使用级联方式更新属性 -->
<property name="clazz" ref="clazzOne"></property>
<property name="clazz.clazzId" value="3333"></property>
<property name="clazz.clazzName" value="最强王者班"></property>
</bean>

七、为数组类型属性赋值

①修改Student类

在Student类中添加以下代码:

c 复制代码
private String[] hobbies;
public String[] getHobbies() {
return hobbies;
}
public void setHobbies(String[] hobbies) {
this.hobbies = hobbies;
}

②配置bean

c 复制代码
<bean id="studentFour" class="com.atguigu.spring.bean.Student">
	<property name="id" value="1004"></property>
	<property name="name" value="赵六"></property>
	<property name="age" value="26"></property>
	<property name="sex" value="女"></property>
	<!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
	<property name="clazz" ref="clazzOne"></property>
	<property name="hobbies">
		<array>
			<value>抽烟</value>
			<value>喝酒</value>
			<value>烫头</value>
		</array>
	</property>
</bean>

八、为集合类型属性赋值

①为List集合类型属性赋值

在Clazz类中添加以下代码:

c 复制代码
private List<Student> students;
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}

配置bean:

c 复制代码
<bean id="clazzTwo" class="com.atguigu.spring.bean.Clazz">
<property name="clazzId" value="4444"></property>
<property name="clazzName" value="Javaee0222"></property>
<property name="students">
<list>
<ref bean="studentOne"></ref>
<ref bean="studentTwo"></ref>
<ref bean="studentThree"></ref>
</list>
</property>
</bean>

若为Set集合类型属性赋值,只需要将其中的list标签改为set标签即可
②为Map集合类型属性赋值

创建教师类Teacher:

c 复制代码
public class Teacher {
private Integer teacherId;
private String teacherName;
public Integer getTeacherId() {
return teacherId;
}
public void setTeacherId(Integer teacherId) {
this.teacherId = teacherId;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
public Teacher(Integer teacherId, String teacherName) {
this.teacherId = teacherId;
this.teacherName = teacherName;
}
public Teacher() {
}
@Override
public String toString() {
return "Teacher{" +
"teacherId=" + teacherId +
", teacherName='" + teacherName + '\'' +
'}';
}
}

在Student类中添加以下代码:

c 复制代码
private Map<String, Teacher> teacherMap;
public Map<String, Teacher> getTeacherMap() {
return teacherMap;
}
public void setTeacherMap(Map<String, Teacher> teacherMap) {
this.teacherMap = teacherMap;
}

配置bean:

c 复制代码
<bean id="teacherOne" class="com.atguigu.spring.bean.Teacher">
<property name="teacherId" value="10010"></property>
<property name="teacherName" value="大宝"></property>
</bean>
<bean id="teacherTwo" class="com.atguigu.spring.bean.Teacher">
<property name="teacherId" value="10086"></property>
<property name="teacherName" value="二宝"></property>
</bean>
<bean id="studentFour" class="com.atguigu.spring.bean.Student">
<property name="id" value="1004"></property>
<property name="name" value="赵六"></property>
<property name="age" value="26"></property>
<property name="sex" value="女"></property>
<!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
<property name="clazz" ref="clazzOne"></property>
<property name="hobbies">
<array>
<value>抽烟</value>
<value>喝酒</value>
<value>烫头</value>
</array>
</property>
<property name="teacherMap">
<map>
<entry>
<key>
<value>10010</value>
</key>
<ref bean="teacherOne"></ref>
</entry>
<entry>
<key>
<value>10086</value>
</key>
<ref bean="teacherTwo"></ref>
</entry>
</map>
</property>
</bean>

③引用集合类型的bean

c 复制代码
<!--list集合类型的bean-->
	<util:list id="students">
		<ref bean="studentOne"></ref>
		<ref bean="studentTwo"></ref>
		<ref bean="studentThree"></ref>
	</util:list>
<!--map集合类型的bean-->
	<util:map id="teacherMap">
 		<entry>
			<key>
				<value>10010</value>
			</key>
			<ref bean="teacherOne"></ref>
		</entry>
		<entry>
			<key>
				<value>10086</value>
			</key>
			<ref bean="teacherTwo"></ref>
		</entry>
</util:map>
<bean id="clazzTwo" class="com.atguigu.spring.bean.Clazz">
  	<property name="clazzId" value="4444"></property>
	<property name="clazzName" value="Javaee0222"></property>
	<property name="students" ref="students"></property>
</bean>
<bean id="studentFour" class="com.atguigu.spring.bean.Student">
	<property name="id" value="1004"></property>
	<property name="name" value="赵六"></property>
	<property name="age" value="26"></property>
	<property name="sex" value="女"></property>
<!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
	<property name="clazz" ref="clazzOne"></property>
	<property name="hobbies">
		<array>
			<value>抽烟</value>
			<value>喝酒</value>
			<value>烫头</value>
		</array>
	</property>
	<property name="teacherMap" ref="teacherMap"></property>
使用util:list、util:map标签必须引入相应的命名空间,可以通过idea的提示功能选择

九、p命名空间

引入p命名空间后,可以通过以下方式为bean的各个属性赋值

c 复制代码
<bean id="studentSix" class="com.atguigu.spring.bean.Student"
p:id="1006" p:name="小明" p:clazz-ref="clazzOne" p:teacherMapref="teacherMap"></bean>
相关推荐
幽络源小助理21 分钟前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
Hello.Reader1 小时前
Redis 延迟排查与优化全攻略
数据库·redis·缓存
简佐义的博客2 小时前
破解非模式物种GO/KEGG注释难题
开发语言·数据库·后端·oracle·golang
爬山算法2 小时前
MySQL(116)如何监控负载均衡状态?
数据库·mysql·负载均衡
旷世奇才李先生2 小时前
XML Schema 安装使用教程
xml
wfsm4 小时前
spring事件使用
java·后端·spring
老纪的技术唠嗑局4 小时前
OceanBase PoC 经验总结(二)—— AP 业务
数据库
阿里云大数据AI技术5 小时前
OpenSearch 视频 RAG 实践
数据库·人工智能·llm
m0_623955667 小时前
Oracle使用SQL一次性向表中插入多行数据
数据库·sql·oracle
Exclusive_Cat7 小时前
SpringMVC参数接收与数据返回详解
spring·mvc