侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

Spring Bean 的作用域有哪些?Singleton 和 Prototype 的区别是什么?

2025-12-13 / 0 评论 / 4 阅读

题目

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:初始化后容器即丢弃,需自行管理资源释放
  • 作用域代理:使用 @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) 解决注入作用域不匹配问题
  • 自定义作用域:通过实现 Scope 接口创建线程级作用域等定制化方案