微信登录

Bean 作用域 - 原型作用域 - 每次请求新实例

Java - Web - Spring 《Bean 作用域 - 原型作用域 - 每次请求新实例》

在 Java 的 Spring 框架中,Bean 的作用域是一个非常重要的概念。它定义了 Spring 容器如何创建和管理 Bean 实例。Spring 框架提供了多种 Bean 作用域,其中原型(Prototype)作用域是一种特殊且实用的作用域,它允许每次从容器中获取 Bean 时都返回一个新的实例。本文将深入探讨原型作用域,并通过示例代码展示其使用方法。

原型作用域的特点

在 Spring 中,Bean 的默认作用域是单例(Singleton),即 Spring 容器只会创建一个 Bean 实例,并在整个应用程序生命周期中共享该实例。而原型作用域则不同,它的特点如下:

  • 每次请求新实例:每当从 Spring 容器中获取原型作用域的 Bean 时,容器都会创建一个新的 Bean 实例。
  • 不进行缓存:与单例作用域不同,原型作用域的 Bean 不会被 Spring 容器缓存,因此不会在整个应用程序中共享同一个实例。
  • 销毁管理:Spring 容器只负责创建原型作用域的 Bean 实例,而不负责销毁这些实例。当客户端获取到 Bean 实例后,实例的生命周期由客户端管理。

演示代码

1. 创建 Maven 项目

首先,我们创建一个简单的 Maven 项目,并在 pom.xml 中添加 Spring 框架的依赖:

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-context</artifactId>
  5. <version>5.3.23</version>
  6. </dependency>
  7. </dependencies>

2. 定义 Bean 类

创建一个简单的 Java 类作为我们的 Bean:

  1. package com.example.demo;
  2. public class MyPrototypeBean {
  3. private int id;
  4. public MyPrototypeBean(int id) {
  5. this.id = id;
  6. }
  7. public int getId() {
  8. return id;
  9. }
  10. public void setId(int id) {
  11. this.id = id;
  12. }
  13. @Override
  14. public String toString() {
  15. return "MyPrototypeBean{id=" + id + "}";
  16. }
  17. }

3. 配置 Bean 的作用域

使用 Java 配置类来配置 Bean 的作用域为原型:

  1. package com.example.demo;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.context.annotation.Scope;
  5. @Configuration
  6. public class AppConfig {
  7. @Bean
  8. @Scope("prototype")
  9. public MyPrototypeBean myPrototypeBean() {
  10. return new MyPrototypeBean((int) (Math.random() * 100));
  11. }
  12. }

在上述代码中,@Scope("prototype") 注解将 myPrototypeBean 方法返回的 Bean 作用域设置为原型。

4. 测试原型作用域

编写一个测试类来验证每次获取 Bean 时是否返回新的实例:

  1. package com.example.demo;
  2. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  3. public class Main {
  4. public static void main(String[] args) {
  5. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
  6. // 第一次获取 Bean
  7. MyPrototypeBean bean1 = context.getBean(MyPrototypeBean.class);
  8. System.out.println("第一次获取的 Bean: " + bean1);
  9. // 第二次获取 Bean
  10. MyPrototypeBean bean2 = context.getBean(MyPrototypeBean.class);
  11. System.out.println("第二次获取的 Bean: " + bean2);
  12. // 比较两个 Bean 是否为同一个实例
  13. System.out.println("两个 Bean 是否为同一个实例: " + (bean1 == bean2));
  14. context.close();
  15. }
  16. }

5. 运行结果

运行 Main 类,输出结果可能如下:

  1. 第一次获取的 Bean: MyPrototypeBean{id=34}
  2. 第二次获取的 Bean: MyPrototypeBean{id=87}
  3. 两个 Bean 是否为同一个实例: false

从输出结果可以看出,每次从 Spring 容器中获取 MyPrototypeBean 时,都会得到一个新的实例。

总结

作用域类型 描述 示例场景
单例(Singleton) 整个应用程序中只创建一个 Bean 实例 配置信息、数据库连接池等
原型(Prototype) 每次请求都创建一个新的 Bean 实例 多线程环境下需要独立状态的对象

原型作用域在 Spring 框架中非常实用,尤其是在需要每次获取新实例的场景下,如多线程环境中需要独立状态的对象。通过合理使用原型作用域,可以避免对象状态的共享和冲突,提高应用程序的安全性和稳定性。

希望本文能帮助你更好地理解 Spring 框架中原型作用域的概念和使用方法。