Bean
- 概述
- 配置方式
- 自动装配
- 继承与依赖
- 作用域
- 外部属性文件的使用
概述
Spring 容器负责管理依赖注入,它将被管理的对象都称为 bean 。我们通过 xml 文件配置方式进行对 bean 的声明和管理。
写法如下:
<beans>
<bean id="bean的唯一标识符" class="对应bean的全路径类名">
<!-- Setter注入标签,进行对象属性赋值 -->
<property />
<!-- 构造器注入标签,进行对象属性赋值 -->
<constructor-arg />
</bean>
</beans>
获取 Spring 配置文件:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("配置文件1.xml","配置文件2.xml"...);
//通过 getBean() 获取容器中的对象实例,一般使用 getBean("id")
配置方式
下面简单介绍 Bean 配置 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"
xmlns:util="http://www.springframework.org/schema/util"
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/util https://www.springframework.org/schema/util/spring-util.xsd">
<!-- property标签的value/ref属性写法 -->
<!-- <bean id="admin" class="cn.edu.springdemo.model.Admin"> -->
<!-- 第一种写法 -->
<!-- <property name="username" value="admin" /> -->
<!-- 第二种写法 -->
<!-- <property name="password"> -->
<!-- 另外,当其value属性值使用特殊字符(如:<>),需要在这个写法下利用<![CDATA[value值]]> -->
<!-- <value><![CDATA[<admin>]]></value> -->
<!-- </property> -->
<!-- 引用 -->
<!-- <property name="map" ref="CommonMap" /> -->
<!-- <property name="set" ref="CommonSet" /> -->
<!-- <property name="list" ref="CommonList" /> -->
<!-- </bean> -->
<!-- 独立配置集合bean(如map、set、list等),方便重复引用 -->
<util:map id="CommonMap">
<entry key="曹操" value="20230408"></entry>
<entry key="刘备" value="20230409"></entry>
<entry key="孙权" value="20230410"></entry>
</util:map>
<util:set id="CommonSet">
<value>魏</value>
<value>蜀</value>
<value>吴</value>
</util:set>
<util:list id="CommonList">
<value>15936287401</value>
<value>15936287402</value>
<value>15936287403</value>
</util:list>
<!-- 使用p命名空间简化bean的配置(与注释的配置一样的效果) -->
<bean id="admin" class="cn.edu.springdemo.model.Admin"
p:username="admin" p:password="admin"
p:map-ref="CommonMap" p:set-ref="CommonSet" p:list-ref="CommonList" />
</beans>
自动装配
自动装配(AutoWiring),指 Spring 可以自动向 Bean 注入依赖。其中使用自动装配需要配置 bean 标签的 autowire 属性,属性值主要有 no(不使用自动装配)、byType 、byName 、constructor 。
创建三个实体类:
package cn.edu.springdemo.beanDemo;
//学科类
public class Discipline {
private int id;
private String discipline;
public int getId() {
return id;
}
public String getDiscipline() {
return discipline;
}
public void setId(int id) {
this.id = id;
}
public void setDiscipline(String discipline) {
this.discipline = discipline;
}
@Override
public String toString() {
return "Discipline{" +
"id=" + id +
", discipline='" + discipline + '\'' +
'}';
}
}
package cn.edu.springdemo.beanDemo;
//成绩类
public class Score {
private int id;
private int score;
public int getId() {
return id;
}
public int getScore() {
return score;
}
public void setId(int id) {
this.id = id;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Score{" +
"id=" + id +
", score=" + score +
'}';
}
}
package cn.edu.springdemo.beanDemo;
import java.util.List;
//学生类
public class Student {
private int id;
private String name;
private Discipline discipline;
private List<Score> scores;
public int getId() {
return id;
}
public String getName() {
return name;
}
public Discipline getDiscipline() {
return discipline;
}
public List<Score> getScores() {
return scores;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setDiscipline(Discipline discipline) {
this.discipline = discipline;
}
public void setScores(List<Score> scores) {
this.scores = scores;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", discipline=" + discipline +
", scores=" + scores +
'}';
}
}
创建测试结果的类:
package cn.edu.springdemo.test;
import cn.edu.springdemo.beanDemo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
//测试类
public class AdminTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beanDemo.xml");
Student student = (Student) applicationContext.getBean("student");
System.out.println(student);
}
}
1. xml 文件配置:自动装配使用 byType 属性值时,将会根据该 bean 的属性类型来匹配容器中对应类型的 bean 进行自动注入,同时必须要有 Setter 方法。
<?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:util="http://www.springframework.org/schema/util"
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/util https://www.springframework.org/schema/util/spring-util.xsd">
<!-- Discipline 类的对象属性值将会自动注入在 id 为 student 的 bean 上 -->
<bean id="discipline1" class="cn.edu.springdemo.beanDemo.Discipline" p:id="1" p:discipline="数学" />
<!-- 给 Score 类的对象属性赋值 -->
<bean id="math" class="cn.edu.springdemo.beanDemo.Score" p:id="1" p:score="96" />
<!-- 获取 id="math" 的 bean 后将会自动注入在 id="student" 的 bean 上 -->
<util:list id="scores">
<ref bean="math" />
</util:list>
<!-- Student 类属性类型有 int、String、Discipline、List<Score> 类型,其中 Discipline、List<Score> 类型自动装配 -->
<bean id="student" class="cn.edu.springdemo.beanDemo.Student" p:id="20230416" p:name="曹操" autowire="byType" />
</beans>
结果如图:
注: 当存在多个相同类但不同的 bean 实例时,需要在 bean 标签中使用 autowire-candidate=“false” 来指定不需要注入的 bean 实例
2. xml 文件配置:自动装配使用 byName 属性值时,将会根据该 bean 的属性名来匹配容器中对应 bean 名的 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:util="http://www.springframework.org/schema/util"
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/util https://www.springframework.org/schema/util/spring-util.xsd">
<!-- id="discipline"的 bean 与 Student 类 Discipline 属性的名称一致,会自动注入在 id 为 student 的 bean 上 -->
<bean id="discipline" class="cn.edu.springdemo.beanDemo.Discipline" p:id="1" p:discipline="数学" />
<!-- 名字不匹配,不会注入 -->
<bean id="discipline2" autowire-candidate="false" class="cn.edu.springdemo.beanDemo.Discipline" p:id="2" p:discipline="英语" />
<!-- 给 Score 类的对象属性赋值 -->
<bean id="math" class="cn.edu.springdemo.beanDemo.Score" p:id="1" p:score="96" />
<bean id="english" class="cn.edu.springdemo.beanDemo.Score" p:id="2" p:score="98" />
<!-- 获取 Score 类对象属性值,id="scores" 与 Student 类 List<Score> 属性的名称一致,会自动注入在 id 为 student 的 bean 上 -->
<util:list id="scores">
<ref bean="math" />
<ref bean="english" />
</util:list>
<!-- Student 类属性类型有 int、String、Discipline、List<Score> 类型,其中 Discipline、List<Score> 类型使用自动装配 -->
<bean id="student" class="cn.edu.springdemo.beanDemo.Student" p:id="20230416" p:name="曹操" autowire="byName" />
</beans>
结果如图:
3. 自动装配使用 constructor 属性值时,将会根据该 bean 的构造器参数类型来匹配容器中对应类型的 bean 进行自动注入。与 byType 类似,都通过类型来匹配,但区别在于 byType 需要 Setter 方法,而 constructor 需要构造方法。所以,这使得更复杂,简单认识,不推荐使用。
继承与依赖
Bean 的继承是 bean 配置项之间的继承关系。子bean 必须有 父bean 定义的所有属性,子bean 可以继承或覆盖 父bean 的属性;父bean 可以作为配置模板或 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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Bean继承 -->
<!-- 父bean设置为配置模板,需要在 abstract 属性中设置为 true 值 -->
<bean abstract="true" id="father" class="cn.edu.springdemo.beanDemo.Father" p:name="刘备" p:sex="男" p:bloodType="O型血" p:eyelidType="双眼皮" />
<!-- 子bean 继承 父bean ,需要在 parent 属性中设置为 父bean 的 id 值 -->
<bean parent="father" id="son" class="cn.edu.springdemo.beanDemo.Son" p:name="刘禅" />
</beans>
测试结果:父bean 为配置模板,不被实例化,不能获取;子bean 覆盖了 父bean 的 name 属性,继承了其他属性,如图:
Bean 的依赖 是 通过 bean 标签的 depends-on 属性来确定一个 bean 依赖另一个 bean,进而实现 bean 实例化的先后顺序。即当 A 依赖 B 时,在 A 实例化前,B 已经实例化。若 B 没有实例化,A 无法实例化,Spring 容器会报错。
<!-- Bean依赖 -->
<!-- 当依赖多个 bean 的时候,使用逗号或空格隔开 -->
<bean depends-on=" 前置依赖 Bean " />
注:B 为前置依赖 Bean
作用域
Bean 的作用域是通过 bean 标签中的 scope 属性来设定 Bean 实例的作用范围。属性值主要有 singleton、prototype、request、session、global-session 。
属性值 | 作用 |
---|---|
singleton | 默认值,每次从容器中获取的实例都是同一个实例 |
prototype | 每次从容器中获取的实例都会重新创建 |
request | 只作用于HTTP请求,每次HTTP请求从容器中获取的实例都会重新创建 |
session | 只作用于HTTP Session,但不同的Session从容器中获取的实例不同 |
global-session | 只作用于HTTP Session,每次从容器中获取的实例都是同一个实例 |
外部属性文件的使用
引用外部属性文件是将 bean 的配置信息提取到 bean 配置文件的外部,以 properties 格式文件保存,并在 bean 配置文件中通过 ${key} 的方式引用属性文件中的属性项。这样,更便于部署和维护。
简单示例:
首先在 pom.xml 中添加两个依赖:
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
然后在 resources 目录下创建 jdbc.properties ,添加以下内容:
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/student?useSSL=false&serverTimezone=UTC
jdbc.user=root
jdbc.password=0123
接着在 beanDemo.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"
xmlns:context="http://www.springframework.org/schema/context"
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">
<!-- 使用context命名空间,通过 location 属性指定 properties 文件位置 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
</beans>
最后,测试结果:
package cn.edu.springdemo.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource;
import java.sql.SQLException;
public class JDBCUtilTest {
public static void main(String[] args) throws SQLException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beanDemo.xml");
DataSource dataSource = (DataSource) applicationContext.getBean("dataSource");
System.out.println(dataSource.getConnection());
}
}
结果如图: