在 Spring 中,Bean 的作用域定义了 Bean 在 Spring 容器中的生命周期和可见范围。Spring 提供了多种 Bean 作用域,以下是常见的几种及其适用场景:

1. singleton(单例作用域)

  • 描述:这是 Spring 默认的 Bean 作用域。在整个 Spring 容器的生命周期内,对于一个 singleton 作用域的 Bean,Spring 容器只会创建一个实例,并且所有对该 Bean 的请求都会返回同一个实例。
  • 适用场景
    • 无状态的 Bean:例如服务层的业务逻辑类,这些类通常不保存特定于某个请求或用户的状态信息,只包含一些通用的业务处理方法。如用户服务类 UserService,它可能包含用户注册、登录等通用业务逻辑,不需要为每个请求都创建一个新的实例。
    • 配置信息类:像数据库连接配置类、系统参数配置类等,这些类的配置信息在整个应用程序中是共享的,只需要一个实例即可。

2. prototype(原型作用域)

  • 描述:每次从 Spring 容器中获取 prototype 作用域的 Bean 时,容器都会创建一个新的实例。也就是说,对该 Bean 的每个请求都会返回一个不同的实例。
  • 适用场景
    • 有状态的 Bean:当 Bean 需要保存特定于某个请求或用户的状态信息时,使用 prototype 作用域比较合适。例如,购物车类 ShoppingCart,每个用户的购物车内容是不同的,因此需要为每个用户创建一个独立的购物车实例。
    • 多线程环境下需要避免共享状态的 Bean:在多线程应用中,如果一个 Bean 的状态可能会被多个线程同时访问和修改,为了避免线程安全问题,可以将其设置为 prototype 作用域,确保每个线程都使用自己的 Bean 实例。

3. request(请求作用域,仅适用于 Web 应用)

  • 描述:在一次 HTTP 请求的生命周期内,Spring 容器会为 request 作用域的 Bean 创建一个实例。对于同一个请求中的所有对该 Bean 的引用,都会返回同一个实例;而不同的请求会得到不同的实例。
  • 适用场景
    • 处理请求相关信息的 Bean:例如处理用户请求参数的 Bean,它可能会根据当前请求的参数进行一些处理和计算,不同的请求可能会有不同的参数,因此需要为每个请求创建一个独立的实例。
    • 记录请求日志的 Bean:在处理每个请求时,需要记录该请求的相关信息,如请求的 URL、请求时间等,使用 request 作用域可以确保每个请求的日志信息是独立记录的。

4. session(会话作用域,仅适用于 Web 应用)

  • 描述:在一个用户会话的生命周期内,Spring 容器会为 session 作用域的 Bean 创建一个实例。同一个用户的不同请求在同一个会话中会共享同一个 Bean 实例;而不同用户的会话会得到不同的实例。
  • 适用场景
    • 用户会话信息管理的 Bean:例如用户登录状态管理类,它可以保存用户的登录信息、权限信息等,在用户的整个会话期间都可以使用这些信息。
    • 用户个性化设置的 Bean:如用户的主题设置、语言偏好等,这些信息在用户的会话期间是保持不变的,可以使用 session 作用域的 Bean 来管理。

5. application(应用作用域,仅适用于 Web 应用)

  • 描述:在整个 Web 应用程序的生命周期内,Spring 容器会为 application 作用域的 Bean 创建一个实例。所有用户的请求都会共享同一个 Bean 实例。
  • 适用场景
    • 统计应用程序全局信息的 Bean:例如统计网站的访问量、在线用户数等全局信息的 Bean,这些信息在整个应用程序中是共享的,只需要一个实例来进行统计和管理。
    • 应用程序级别的配置信息管理 Bean:如应用程序的全局配置参数,这些参数在整个应用程序中是固定的,所有用户都可以访问和使用这些配置信息。

6. websocket(WebSocket 作用域,仅适用于 Spring WebSocket 应用)

  • 描述:在一个 WebSocket 会话的生命周期内,Spring 容器会为 websocket 作用域的 Bean 创建一个实例。同一个 WebSocket 会话中的所有消息处理都会共享同一个 Bean 实例;而不同的 WebSocket 会话会得到不同的实例。
  • 适用场景
    • 处理 WebSocket 会话相关信息的 Bean:例如管理 WebSocket 连接状态、处理 WebSocket 消息的 Bean,每个 WebSocket 会话都有自己独立的状态和消息处理逻辑,使用 websocket 作用域可以确保每个会话的信息和处理逻辑是独立的。

示例代码

XML 配置方式

<bean id="singletonBean" class="com.example.SingletonBean" scope="singleton"/>
<bean id="prototypeBean" class="com.example.PrototypeBean" scope="prototype"/>

Java 注解方式

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class AppConfig {

    @Bean
    @Scope("singleton")
    public SingletonBean singletonBean() {
        return new SingletonBean();
    }

    @Bean
    @Scope("prototype")
    public PrototypeBean prototypeBean() {
        return new PrototypeBean();
    }
}