Spring Bean作用域机制:单例与原型实例详解
Bean 作用域的六种形态
在 Spring 容器中,每个 Bean 定义都可以指定其作用域,控制实例的创建方式与生命周期。Spring 提供了以下六种作用域:
| 作用域 | 说明 |
|---|---|
singleton | (默认)在整个 Spring IoC 容器中,每个 Bean 定义只存在一个共享实例。 |
prototype | 每次请求该 Bean 时,都会创建新的实例。 |
request | 限定在单个 HTTP 请求的生命周期内,每个请求拥有独立实例。仅适用于 Web 环境。 |
session | 限定在 HTTP Session 的生命周期内。仅适用于 Web 环境。 |
application | 限定在 ServletContext 的生命周期内。仅适用于 Web 环境。 |
websocket | 限定在 WebSocket 的生命周期内。仅适用于 Web 环境。 |
其中,singleton 和 prototype 是两种基础且通用的作用域,其余四种只适用于 Web 应用上下文。
单例与原型的行为差异
单例 Bean 保证容器中只存在一个实例,所有注入点共享同一个对象;原型 Bean 则每次注入或调用 getBean() 时都会生成全新对象。
代码演示
定义一个简单的实体类用于演示:
package com.example.demo.model;
public class Student {
private int id;
private String name;
public Student() {
}
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{id=" + id + ", name='" + name + "'}";
}
}
Spring XML 配置中分别声明单例和原型 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 单例 Bean -->
<bean id="singletonStudent" class="com.example.demo.model.Student" scope="singleton">
<property name="id" value="1"/>
<property name="name" value="Alice"/>
</bean>
<!-- 原型 Bean -->
<bean id="prototypeStudent" class="com.example.demo.model.Student" scope="prototype">
<constructor-arg index="0" value="2"/>
<constructor-arg index="1" value="Bob"/>
</bean>
</beans>
测试代码验证实例唯一性:
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.demo.model.Student;
public class ScopeTest {
@Test
public void testScope() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-config.xml");
Student s1 = ctx.getBean("singletonStudent", Student.class);
Student s2 = ctx.getBean("singletonStudent", Student.class);
System.out.println("单例引用相同: " + (s1 == s2)); // true
Student p1 = ctx.getBean("prototypeStudent", Student.class);
Student p2 = ctx.getBean("prototypeStudent", Student.class);
System.out.println("原型引用相同: " + (p1 == p2)); // false
}
}
运行测试,控制台输出:
单例引用相同: true
原型引用相同: false
结果表明,单例 Bean 每次返回的都是同一个实例,而原型 Bean 每次都会创建新对象。