题目
Spring Bean 的作用域有哪些?Singleton 和 Prototype 的区别是什么?
信息
- 类型:问答
- 难度:⭐
考点
Bean作用域,Singleton模式,Prototype模式
快速回答
Spring Bean 有五种核心作用域:
- Singleton:默认作用域,整个容器中只有一个实例
- Prototype:每次请求都创建新实例
- Request(Web 环境):每个 HTTP 请求一个实例
- Session(Web 环境):每个 HTTP 会话一个实例
- Application(Web 环境):ServletContext 生命周期内一个实例
Singleton 与 Prototype 的区别:
- Singleton 全局共享同一实例,Prototype 每次创建新实例
- Singleton 由容器管理生命周期,Prototype 创建后由调用者管理
- Singleton 适合无状态组件,Prototype 适合有状态组件
一、原理说明
Spring 框架通过作用域(Scope)控制 Bean 的创建方式和生命周期:
- Singleton:IoC 容器启动时创建单例 Bean(默认惰性加载可配置),所有依赖注入共享同一实例
- Prototype:每次通过
getBean()或依赖注入时动态创建新实例,容器不管理其完整生命周期
二、代码示例
1. 作用域配置:
// 注解方式
@Component
@Scope("prototype") // 默认为 @Scope("singleton")
public class UserService {
// 类实现
}
// XML 配置方式
<bean id="userService" class="com.example.UserService" scope="prototype"/>2. 测试验证:
@Autowired
private ApplicationContext context;
public void testScopes() {
// Singleton 测试
Object bean1 = context.getBean("singletonBean");
Object bean2 = context.getBean("singletonBean");
System.out.println(bean1 == bean2); // 输出 true
// Prototype 测试
Object bean3 = context.getBean("prototypeBean");
Object bean4 = context.getBean("prototypeBean");
System.out.println(bean3 == bean4); // 输出 false
}三、最佳实践
- 使用 Singleton 的场景:无状态服务(如工具类、DAO、Service 层)、线程安全组件
- 使用 Prototype 的场景:需要维护状态的组件(如购物车)、非线程安全对象
- 性能考量:Singleton 减少对象创建开销,Prototype 增加内存消耗但避免状态污染
四、常见错误
- 错误 1:在 Singleton Bean 中注入 Prototype Bean 期望每次获得新实例
解决方案:使用@Lookup注解或ObjectFactory<T> - 错误 2:Prototype Bean 中持有资源未手动释放
原因:Spring 不管理 Prototype Bean 的销毁生命周期
解决方案:实现DisposableBean并手动调用销毁方法 - 错误 3:误用 Singleton 存储用户会话数据(导致数据交叉污染)
五、扩展知识
- 生命周期差异:
- Singleton:初始化后常驻内存,容器关闭时调用
@PreDestroy - Prototype:初始化后容器即丢弃,需自行管理资源释放
- Singleton:初始化后常驻内存,容器关闭时调用
- 作用域代理:使用
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)解决注入作用域不匹配问题 - 自定义作用域:通过实现
Scope接口创建线程级作用域等定制化方案