②【Spring】一文精通:IOC - 基于XML方式管理Bean
个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~
个人主页:.29.的博客
学习社区:进去逛一逛~
IOC操作:基于XML管理Bean
- 一、🚀【基于XML创建Bean】
- - 依赖
- - 组件类
- - XML配置文件
- - 测试
- - 默认空参构造器
- 二、🚀【bean的属性赋值(setter注入)】
- - 组件类
- - XML配置文件
- - 测试
- 三、🚀【引用外部已声明的Bean】
- - 组件类
- - XML配置文件
- - 测试
- 四、🚀【内部Bean】
- - XML配置文件
- - 测试
- 五、🚀【Bean的级联属性赋值】
- - XML配置文件
- - 测试
- 六、🚀【bean的属性赋值 (构造方法注入)】
- - 组件类
- - XML配置文件
- - 测试
- 七、🚀【为bean的属性赋 特殊值】
- - 组件类
- - XML配置文件
- ⚪NULL值
- ⚪XML实体
- ⚪CDATA节
- 八、🚀【使用p名称空间 赋值Bean属性】
- - XML配置文件
- 九、🚀【Bean的集合属性赋值】
- - XML配置文件
- ⚪单列集合
- ⚪双列集合(Map集合)
- 十、🚀【Bean的自动装配】
- - 组件类
- -XML配置文件
- - 测试
- 十一、🚀【集合类型的Bean】
- -XML配置文件
- 十二、🚀【Bean属性赋值:引入外部属性文件】
- - 依赖
- - 文件
- - 测试
一、🚀【基于XML创建Bean】
- 依赖
准备
: 创建maven过程,引入相关依赖
注:普通java工程,导入相关jar包也可。
<dependencies>
<!-- 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
- 组件类
1. 首先创建一个类
package com.haojin.ioc.demo;
/**
* @author .29.
* @create 2023-01-12 11:22
*/
public class demo1 {
public void doWork(){
System.out.println("do.....work....");
}
}
- XML配置文件
2. 创建Spring的XML配置文件
3. 在配置文件中配置组件
- bean标签:通过配置bean标签告诉IOC容器需要创建对象的组件是什么
- id属性:bean的唯一标识
- class属性:组件类的全类名
<!-- 创建Bean -->
<!-- 通过配置bean标签告诉IOC容器需要创建对象的组件是什么 -->
<!-- id属性:bean的唯一标识 -->
<!-- class属性:组件类的全类名 -->
<bean id="demo1" class="com.haojin.ioc.demo.demo1"></bean>
注意:
当多个不同id的bean指向同一个类型class时,会报异常
<bean id="demo1" class="com.haojin.ioc.demo.demo1"></bean>
<bean id="demo11" class="com.haojin.ioc.demo.demo1"></bean>
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No
qualifying bean of type ‘com.haojin.ioc.demo.demo1’ available:
expected single matching bean but found 2: demo1,demo11
- 测试
4. 测试
-
这里ApplicationContext方式实现IOC容器,在配置文件被读取时,就会将类的对象创建好
-
ClassPathXmlApplicationContext :通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
-
通过getBean()获取对象
-
getBean()获取对象的方式 :
-
方式一:根据id获取
-
方式二:根据类型获取
-
方式三:同时根据id和类型获取
import com.haojin.ioc.demo.demo1;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author .29.
* @create 2023-01-12 13:47
*/
public class testDemo1 {
//ApplicationContext方式实现IOC容器,在配置文件被读取时,就会将类的对象创建好
//ClassPathXmlApplicationContext 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("demo1_bean.xml");
@Test
public void test1(){
//通过getBean()获取对象:
//1.根据id获取
demo1 demo1 = (demo1)context.getBean("demo1");
//2.根据类型获取
demo1 demo11 = context.getBean(demo1.class);
//3.同时根据id和类型获取
demo1 demo111 = context.getBean("demo1",demo1.class);
demo1.doWork();
demo11.doWork();
demo111.doWork();
System.out.println(demo1);
System.out.println(demo11);
System.out.println(demo111);
}
}
- 默认空参构造器
注意
:XML配置文件中bean标签创建对象默认调用空参的构造方法
无法调用到空参构造方法,将会报异常
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name ‘demo1’ defined in class path resource
[demo1_bean.xml]: Instantiation of bean failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate [com.haojin.ioc.demo.demo1]: No default constructor found;
nested exception is java.lang.NoSuchMethodException:
com.haojin.ioc.demo.demo1.<init>()
二、🚀【bean的属性赋值(setter注入)】
- 组件类
1. 组件类增加属性,准备Get,Set方法
package com.haojin.ioc.demo;
/**
* @author .29.
* @create 2023-01-12 11:22
*/
public class demo1 {
//添加的属性
String str;
//Get方法
public String getStr() {
return str;
}
//Set方法
public void setStr(String str) {
this.str = str;
}
public void doWork(){
System.out.println("do.....work....");
}
}
- XML配置文件
2. 通过property
标签配置的属性值
- property标签:通过组件类的setXxx()方法给组件对象设置属性
- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关)
- value属性:指定属性值
<bean id="demo1" class="com.haojin.ioc.demo.demo1">
<!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
<!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
<!-- value属性:指定属性值 -->
<property name="str" value="--这里是注入的内容--"></property>
</bean>
注入的属性值为:--这里是注入的内容--
- 测试
- 测试类中调用Get()方法,验证是否以及为属性赋值。
import com.haojin.ioc.demo.demo1;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author .29.
* @create 2023-01-12 13:47
*/
public class testDemo1 {
//ApplicationContext方式实现IOC容器,在配置文件被读取时,就会将类的对象创建好
//ClassPathXmlApplicationContext 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("demo1_bean.xml");
@Test
public void test1(){
demo1 demo1 = context.getBean("demo1", demo1.class);
String str = demo1.getStr();
System.out.println(str);
}
}
三、🚀【引用外部已声明的Bean】
- 组件类
1. 声明新的组件类
准备一个属性,以及Get() 和 Set() 方法
package com.haojin.ioc.demo;
/**
* @author .29.
* @create 2023-01-13 16:16
*/
public class demo2 {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2. 原组件引用新组件
package com.haojin.ioc.demo;
/**
* @author .29.
* @create 2023-01-12 11:22
*/
public class demo1 {
//********** 原组件引用新组件 **********
demo2 demo2;
public com.haojin.ioc.demo.demo2 getDemo2() {
return demo2;
}
public void setDemo2(com.haojin.ioc.demo.demo2 demo2) {
this.demo2 = demo2;
}
//********** 原组件引用新组件 **********
String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public void doWork(){
System.out.println("do.....work....");
}
}
- XML配置文件
3. 新组件配置Bean
<bean id="demo2" class="com.haojin.ioc.demo.demo2">
<property name="name" value="my name is demo2"> </property>
</bean>
4. 原组件Bean 引用 新组件Bean
- ref 属性:通过 bean 的 id 引用另一个 bean
- 注意:这里ref属性不能写成value属性,会报异常
<bean id="demo1" class="com.haojin.ioc.demo.demo1">
<property name="str" value="--这里是注入的内容--"></property>
<!--在原组件的 bean 中引用新组件的 bean-->
<!--ref 属性:通过 bean 的 id 引用另一个 bean-->
<property name="demo2" ref="demo2"></property>
</bean>
- 测试
5. 测试
import com.haojin.ioc.demo.demo1;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author .29.
* @create 2023-01-12 13:47
*/
public class testDemo1 {
//ApplicationContext方式实现IOC容器,在配置文件被读取时,就会将类的对象创建好
//ClassPathXmlApplicationContext 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("ioc_bean.xml");
@Test
public void test2(){
//获取demo1对象
demo1 demo1 = context.getBean("demo1", demo1.class);
//通过demo1获取demo2对象及其属性
String name = demo1.getDemo2().getName();
System.out.println("demo2.name = " + name);
}
}
四、🚀【内部Bean】
- XML配置文件
1. 重新配置XML文件,设置内部Bean
- 在一个 bean 中再声明一个 bean 就是内部 bean
- 内部 bean 可以直接用于给属性赋值,可以省略 id 属性
<bean id="demo1" class="com.haojin.ioc.demo.demo1">
<property name="str" value="--这里是注入的内容--"></property>
<!-- 在一个 bean 中再声明一个 bean 就是内部 bean -->
<!-- 内部 bean 可以直接用于给属性赋值,可以省略 id 属性 -->
<property name="demo2">
<bean class="com.haojin.ioc.demo.demo2">
<property name="name" value="this is 内部Bean赋值的demo2"/>
</bean>
</property>
</bean>
- 测试
2. 测试
import com.haojin.ioc.demo.demo1;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author .29.
* @create 2023-01-12 13:47
*/
public class testDemo1 {
//ApplicationContext方式实现IOC容器,在配置文件被读取时,就会将类的对象创建好
//ClassPathXmlApplicationContext 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("ioc_bean.xml");
@Test
public void test2(){
//获取demo1对象
demo1 demo1 = context.getBean("demo1", demo1.class);
//通过demo1获取demo2对象及其属性
String name = demo1.getDemo2().getName();
System.out.println("demo2.name = " + name);
}
}
五、🚀【Bean的级联属性赋值】
- XML配置文件
1. 配置关联对象的Bean
<bean id="demo2" class="com.haojin.ioc.demo.demo2"></bean>
2. 装配关联对象 赋值级联对象
-关联对象:demo2
-级联属性:demo2.name
<bean id="demo1" class="com.haojin.ioc.demo.demo1">
<!--装配关联对象-->
<property name="demo2" ref="demo2"></property>
<!-- 对于demo1来说,demo2的name属性就是 关联对象的级联属性 -->
<property name="demo2.name" value="this is 级联属性赋值的demo2"></property>
</bean>
- 测试
3. 测试
import com.haojin.ioc.demo.demo1;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author .29.
* @create 2023-01-12 13:47
*/
public class testDemo1 {
//ApplicationContext方式实现IOC容器,在配置文件被读取时,就会将类的对象创建好
//ClassPathXmlApplicationContext 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("ioc_bean.xml");
@Test
public void test2(){
//获取demo1对象
demo1 demo1 = context.getBean("demo1", demo1.class);
//通过demo1获取demo2对象及其属性
String name = demo1.getDemo2().getName();
System.out.println("demo2.name = " + name);
}
}
六、🚀【bean的属性赋值 (构造方法注入)】
- 组件类
1. 准备一个新的组件类,含:构造器,Gettet,Setter,toString()
package com.haojin.ioc.demo;
/**
* @author .29.
* @create 2023-01-13 20:37
*/
public class demo3 {
private String name;
private Integer age;
private Double salary;
public demo3(){}
public demo3(String name, Integer age, Double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
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 Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "demo3{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
- XML配置文件
2. 配置组件类demo3的bean标签
- 使用
constructor-arg
标签进行构造器注入 index
属性 :指定参数所在位置的索引(从0开始)name
属性:指定参数名- 不指定 index 和 name 就按照构造器的参数顺序赋值
<bean id="demo3" class="com.haojin.ioc.demo.demo3">
<constructor-arg index="0" name="name" value="zero"></constructor-arg>
<constructor-arg index="1" name="age" value="18"></constructor-arg>
<constructor-arg index="2" name="salary" value="29000.99"></constructor-arg>
</bean>
- 测试
3. 测试
import com.haojin.ioc.demo.demo3;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author .29.
* @create 2023-01-12 13:47
*/
public class testDemo1 {
ApplicationContext context = new ClassPathXmlApplicationContext("ioc_bean.xml");
@Test
public void test3(){
demo3 demo3 = context.getBean("demo3", demo3.class);
System.out.println("demo3 = "+ demo3);
}
}
七、🚀【为bean的属性赋 特殊值】
- 组件类
1. 设置一个类来演示 特殊值 的赋值
package com.haojin.ioc.demo;
/**
* @author .29.
* @create 2023-01-14 11:30
*/
public class demo4 {
String demoValue;
String comment;
public demo4() {
}
public demo4(String demoValue, String comment) {
this.demoValue = demoValue;
this.comment = comment;
}
public String getDemoValue() {
return demoValue;
}
public void setDemoValue(String demoValue) {
this.demoValue = demoValue;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
@Override
public String toString() {
return "demo4{" +
"demoValue='" + demoValue + '\'' +
", comment='" + comment + '\'' +
'}';
}
}
- XML配置文件
⚪NULL值
- property标签:通过组件类的setXxx()方法给组件对象设置属性
- null标签:将一个属性明确设定为null
- name属性:指定属性名
<bean id="demo4" class="com.haojin.ioc.demo.demo4">
<property name="demoValue">
<!-- null标签:将一个属性明确设定为null -->
<null/>
</property>
<property name="comment" value="这是一个空值"/>
</bean>
⚪XML实体
为什么使用XML实体?
在Spring配置文件中,">" "<" 等符号用于定义标签,不能随意用于赋值。
- XML实体:
XML实体 | 实体字符 | 十进制表示 | 十六进制表示 |
---|---|---|---|
quot; | " | " | " |
amp; | & | & | & |
apos; | ' | ' | ' |
lt; | < | < | < |
gt; | > | > | > |
例子
:
<bean id="demo4" class="com.haojin.ioc.demo.demo4">
<!-- "<" ">" 在XML文档中用来定义标签,不能随便使用 -->
<!-- 解决方案一:使用XML实体来代替 -->
<property name="demoValue" value="a < b"/>
<property name="comment" value="b > a"/>
</bean>
⚪CDATA节
- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据
- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析
- value标签:指定属性值
使用方式
: <![CDATA[文本内容]]>
<bean id="demo4" class="com.haojin.ioc.demo.demo4">
<property name="demoValue">
<value><![CDATA[a < b = c & ' "]]></value>
</property>
<property name="comment">
<value><![CDATA[CDATA的演示]]></value>
</property>
</bean>
八、🚀【使用p名称空间 赋值Bean属性】
- XML配置文件
准备
:导入相关的 XML 约束,在 IDEA 的协助下导入:
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
导入完成:
<?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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
</beans>
使用 p 名称空间的方式可以省略子标签 property,将组件属性的设置作为 bean 标签的属性来完成。
使用方式
: p:属性名=“属性值”
<bean id="demo4" class="com.haojin.ioc.demo.demo4"
p:demoValue="p名称空间命名的值"
p:comment="省略了property标签">
</bean>
注意
:刚开始 p:
会爆红,需要根据IDEA提示,按下对应组合按键从而导入:
九、🚀【Bean的集合属性赋值】
- XML配置文件
⚪单列集合
list
标签:准备一组集合类型的数据,给集合属性赋值
<bean id="id" class="类目录">
<property name="属性名">
<!-- list标签:准备一组集合类型的数据,给集合属性赋值 -->
<list>
<value>member01</value>
<value>member02</value>
<value>member03</value>
</list>
</property>
</bean>
set
标签:使用 set 标签也能实现list标签效果,同时附带去重功能
<!-- 使用set标签也能实现list标签效果,只是附带了去重功能 -->
<set>
<value>member01</value>
<value>member02</value>
<value>member02</value>
</set>
array
标签:使用 array 标签也能实现list标签效果
<array>
<value>member01</value>
<value>member02</value>
<value>member02</value>
</array>
⚪双列集合(Map集合)
map
标签 \props
标签- 给Map类型的属性赋值
<map>
<entry key="财务部" value="张三"/>
<entry key="行政部" value="李四"/>
<entry key="销售部" value="王麻子"/>
</map>
&
<props>
<prop key="财务部">张三</prop>
<prop key="行政部">李四</prop>
<prop key="销售部">王麻子</prop>
</props>
十、🚀【Bean的自动装配】
自动装配
:当一个组件需要其他组件时,由 IOC 容器负责找到那个需要的组件,并装配进去。
- 组件类
1. 准备两个组件类 controller 和 service(随意命名)
controller组件
:
package com.haojin.ioc.demo;
/**
* @author .29.
* @create 2023-01-16 14:30
*
* 用来演示IOC容器的自动装配
*/
public class controller {
service service;
public service getService() {
return service;
}
public void setService(service service) {
this.service = service;
}
}
service组件
:
package com.haojin.ioc.demo;
/**
* @author .29.
* @create 2023-01-16 14:30
*
* 用来演示IOC容器的自动装配
*/
public class service {
}
controller类中包含service类型的属性及其Getter和Setter;
controller组件自动装配时,IOC容器负责找到service组件,并装配进去。
-XML配置文件
2. 使用bean标签
的autowire属性
设置自动装配
- 自动装配效果有
byType
和byName
<!--配置service组件的Bean-->
<bean id="service" class="com.haojin.ioc.demo.service"></bean>
<!--配置controller组件的Bean,使用autowire属性自动装配-->
<bean id="controller"
class="com.haojin.ioc.demo.controller"
autowire="byName">
</bean>
注意
:
1、byType表示根据类型进行装配,此时如果类型匹配的bean不止一个,那么会抛NoUniqueBeanDefinitionException;
2、byName表示根据bean的id进行匹配。而bean的id是根据需要装配组件的属性的属性名来确定的;
- 测试
3.使用测试类,验证自动装配效果。
public class testDemo1 {
//ApplicationContext方式实现IOC容器,在配置文件被读取时,就会将类的对象创建好
//ClassPathXmlApplicationContext 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("ioc_bean.xml");
@Test
public void testAutowire(){
controller controller = context.getBean("controller", controller.class);
service service = controller.getService();
System.out.println("service = " + service);
}
若结果为null,说明没有装配成功
十一、🚀【集合类型的Bean】
-XML配置文件
- 使用
util:list标签
及其内部的多个bean
标签为集合属性赋值 - 规律:util:list标签中多个bean标签的class属性及name属性一致
<util:list id="集合的id">
<bean class="集合所在的类目录">
<property name="集合的属性名" value="machineOne"/>
</bean>
<bean class="集合所在的类目录">
<property name="集合的属性名" value="machineTwo"/>
</bean>
<bean class="集合所在的类目录">
<property name="集合的属性名" value="machineThree"/>
</bean>
</util:list>
给bean的属性赋值:集合属性
十二、🚀【Bean属性赋值:引入外部属性文件】
- 依赖
1. 导入连接数据库相关的依赖
<!-- MySQL驱动,注:版本不匹配会出现异常 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<!-- 数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.31</version>
</dependency>
- 文件
2. 在配置bean时,引入外部属性文件
外部属性文件
:jdbc.properties
jdbc.username=root
jdbc.password=abc123
jdbc.url=jdbc:mysql://localhost:3306/school?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
mysql 8.0及以上版本,需要用驱动器 : com.mysql.cj.jdbc.Driver
XML配置文件
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--bean标签和property标签读取外部属性文件-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
- 测试
3. 在测试类中,尝试通过bean获取数据库连接
public class testDemo1 {
//ApplicationContext方式实现IOC容器,在配置文件被读取时,就会将类的对象创建好
//ClassPathXmlApplicationContext 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("ioc_bean.xml");
@Test
public void testSQL() throws SQLException {
DruidDataSource dataSource = context.getBean("druidDataSource", DruidDataSource.class);
Connection connection = dataSource.getConnection();
System.out.println("connection = " + connection);
}
成功获取连接