题目
Spring Bean的作用域有哪些?请说明它们的区别及适用场景
信息
- 类型:问答
- 难度:⭐⭐
考点
Bean作用域, 线程安全, 生命周期管理, 配置方式
快速回答
Spring Bean 支持五种核心作用域:
- singleton(默认):每个容器中只有一个实例
- prototype:每次请求都创建新实例
- request:每个HTTP请求创建一个实例
- session:每个HTTP会话创建一个实例
- application:每个ServletContext生命周期一个实例
关键区别:
1. singleton 全局共享需注意线程安全
2. prototype 适用于有状态的场景
3. Web相关作用域需在Web环境中使用
解析
1. 作用域详解及配置方式
配置示例(注解方式):
// XML配置
<bean id="service" class="com.example.Service" scope="prototype"/>
// 注解配置
@Bean
@Scope("prototype")
public Service service() {
return new Service();
}
// 或使用常量
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)2. 核心作用域对比
| 作用域 | 生命周期 | 线程安全 | 适用场景 |
|---|---|---|---|
| singleton | 容器初始化时创建(懒加载除外),容器销毁时销毁 | 需自行保证 | 无状态服务、工具类、数据库连接池 |
| prototype | 每次getBean()时创建,容器不管理销毁 | 天然隔离 | 有状态对象(如购物车)、需要隔离的组件 |
| request | HTTP请求开始时创建,请求结束时销毁 | 天然隔离 | 存储请求相关数据(如用户表单) |
| session | 会话创建时创建,会话超时/结束时销毁 | 天然隔离 | 用户会话数据(如登录信息) |
| application | ServletContext生命周期 | 需自行保证 | 全局缓存、共享资源 |
3. 最佳实践与常见错误
最佳实践:
- 优先使用singleton:减少对象创建开销,但需确保无状态
- prototype作用域中避免持有长期资源:需手动释放资源(如文件句柄)
- Web作用域代理模式:解决注入问题
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
常见错误:
- 错误1:在singleton中注入prototype Bean(需用方法注入解决)
- 错误2:在非Web环境使用request/session作用域
- 错误3:prototype Bean中忘记释放资源导致内存泄漏
4. 原理说明
Spring通过BeanDefinition存储作用域配置,由Scope接口实现具体行为:
public interface Scope {
Object get(String name, ObjectFactory<?> objectFactory);
Object remove(String name);
// ...
}容器在创建Bean时:
1. 检查作用域类型
2. 调用对应的Scope实现(如SingletonScope/PrototypeScope)
3. 对于Web作用域,通过RequestContextListener或RequestContextFilter绑定生命周期
5. 扩展知识
- 自定义作用域:实现
Scope接口并注册// 注册自定义作用域 context.getBeanFactory().registerScope("thread", new SimpleThreadScope()); - 作用域代理:解决作用域依赖问题(CGLIB/JDK动态代理)
- Jakarta EE 的@SessionScoped:需实现
Serializable接口