# Spring 5 – Bean 范围

> 原文： [https://howtodoinjava.com/spring-core/spring-bean-scopes/](https://howtodoinjava.com/spring-core/spring-bean-scopes/)

在 Spring 框架中，我们可以在 6 个内置的 **spring bean 范围**中创建 bean，还可以定义**自定义 bean 作用域**。 在这六个范围中，只有当您使用网络感知`ApplicationContext`时，四个才可用。 `singleton`和`prototype`范围在任何类型的 IOC 容器中都可用。

## 1\. Spring Bean 范围类型

在 Spring 中，可以使用 spring bean `@Scope`注解定义范围。 让我们快速列出所有六个可在 Spring 应用程序上下文中使用的内置 bean 范围。 这些相同的范围也适用于 SpringBoot bean 范围。

| 范围 | 描述 |
| --- | --- |
| `singleton`（默认） | 每个 spring IoC 容器一个 bean 对象实例 |
| `prototype` | 与单例相反，每次请求 bean 时，它都会产生一个新实例。 |
| `request` | 将创建一个单例，并在 HTTP 请求的整个生命周期中可用。仅在可感知网络的 Spring `ApplicationContext`中有效。 |
| `session` | 一个单例将在 HTTP 会话的整个生命周期中创建并可用。仅在可感知网络的 Spring `ApplicationContext`中有效。 |
| `application` | 一个单例将在`ServletContext`的整个生命周期中创建并可用。仅在可感知网络的 Spring `ApplicationContext`中有效。 |
| `websocket` | 一个单例将在`WebSocket`的整个生命周期中创建并可用。仅在可感知网络的 Spring `ApplicationContext`中有效。 |

#### 1.1. 单例范围

`singleton`是 spring 容器中的默认 bean 作用域。 它告诉容器每个容器仅创建和管理一个 bean 类实例。 该单个实例存储在此类[单例](https://howtodoinjava.com/design-patterns/creational/singleton-design-pattern-in-java/) Bean 的缓存中，并且对该命名 Bean 的所有后续请求和引用都返回该缓存的实例。

使用 Java 配置的单例作用域 bean 的示例：

```java
@Component
//This statement is redundant - singleton is default scope
@Scope("singleton")  //This statement is redundant
public class BeanClass {

}

```

使用 XML 配置的单例作用域 bean 的示例：

```java
<!-- To specify singleton scope is redundant -->
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="singleton" />
//or
<bean id="beanId" class="com.howtodoinjava.BeanClass" />

```

#### 1.2. 原型范围

每当应用程序代码对 Bean 进行请求时，`prototype`范围都会导致创建新的 Bean 实例。

您应该知道，销毁[ bean 生命周期方法](https://howtodoinjava.com/spring/spring-core/spring-bean-life-cycle/)没有被称为`prototype`作用域 bean，仅调用了初始化回调方法。 因此，作为开发人员，您需要负责清理原型作用域的 Bean 实例以及其中包含的所有资源。

原型 bean 范围的 Java 配置示例：

```java
@Component
@Scope("prototype")
public class BeanClass {
}

```

原型 bean 范围的 XML 配置示例：

```java
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="prototype" />

```

通常，您应该对所有有状态 Bean 使用`prototype`范围，而对无状态Bean使用`singleton`范围。要在请求，会话，应用程序和 Websocket 范围中使用 Bean，您需要注册[`RequestContextListener`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/context/request/RequestContextListener.html)或者[`RequestContextFilter`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/RequestContextFilter.html)。

#### 1.3. 请求范围

在`request`范围内，容器为每个 HTTP 请求创建一个新实例。 因此，如果服务器当前正在处理 50 个请求，则容器最多可以具有 50 个单独的 Bean 类实例。 对一个实例的任何状态更改，对其他实例都不可见。 请求完成后，这些实例将被销毁。

请求 bean 范围的 Java 配置示例：

```java
@Component
@Scope("request")
public class BeanClass {
}

//or

@Component
@RequestScope
public class BeanClass {
}

```

请求 bean 范围的 XML 配置示例：

```java
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="request" />

```

> 阅读更多： [Web 服务器如何工作？](https://howtodoinjava.com/server/tomcat/a-birds-eye-view-on-how-web-servers-work/)

#### 1.4. 会话范围

在`session`范围内，容器为每个 HTTP 会话创建一个新实例。 因此，如果服务器有 20 个活动会话，则容器最多可以具有 20 个 Bean 类的单独实例。 单个会话生存期内的所有 HTTP 请求都可以访问该会话范围内的同一单个 Bean 实例。

对一个实例的任何状态更改，对其他实例都不可见。 一旦会话在服务器上销毁/结束，这些实例将被销毁。

会话 bean 范围的 Java 配置示例：

```java
@Component
@Scope("session")
public class BeanClass {
}

//or

@Component
@SessionScope
public class BeanClass {
}

```

会话 bean 范围的 XML 配置示例：

```java
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="session" />

```

#### 1.5. 应用范围

在`application`范围内，容器为每个 Web 应用程序运行时创建一个实例。 它几乎与`singleton`示波器相似，只有两个区别，即

1.  `application`范围的 bean 是每个`ServletContext`单身，而`singleton`范围的 bean 是每个`ApplicationContext`单身。 请注意，单个应用程序可以有多个应用程序上下文。
2.  `application`范围内的 bean 作为`ServletContext`属性可见。

应用程序 bean 范围的 Java 配置示例：

```java
@Component
@Scope("application")
public class BeanClass {
}

//or

@Component
@ApplicationScope
public class BeanClass {
}

```

应用程序 bean 范围的 XML 配置示例：

```java
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="application" />

```

#### 1.6. websocket 范围

[WebSocket 协议](https://tools.ietf.org/html/rfc6455)允许客户端与已选择与客户端通信的远程主机之间进行双向通信。 WebSocket 协议为双向通信提供单个 TCP 连接。 这对于同时编辑和多用户游戏的多用户应用程序特别有用。

在这种类型的 Web 应用程序中，HTTP 仅用于初始握手。 如果服务器同意，服务器可以以[ HTTP 状态 101（交换协议）](https://restfulapi.net/http-status-codes/)进行响应。 如果握手成功，则 TCP 套接字保持打开状态，客户端和服务器都可以使用该套接字向彼此发送消息。

websocket bean 作用域的 Java 配置示例：

```java
@Component
@Scope("websocket")
public class BeanClass {
}

```

Websocket bean 作用域的 XML 配置示例：

```java
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="websocket" />

```

请注意，`websocket`范围内的 bean 通常是单例的，并且比任何单独的 WebSocket 会话的生存期都更长。

## 2\. 自定义线程范围

Spring 还使用类`SimpleThreadScope`提供了非默认`thread`范围。 要使用此作用域，必须使用`CustomScopeConfigurer`类将其注册到容器。

```java
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="thread">
                <bean class="org.springframework.context.support.SimpleThreadScope"/>
            </entry>
        </map>
    </property>
</bean>

```

对 bean 的每个请求都将在同一线程中返回相同的实例。

线程 bean 范围的 Java 配置示例：

```java
@Component
@Scope("thread")
public class BeanClass {
}

```

线程 bean 范围的 XML 配置示例：

```java
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="thread" />

```

## 3\. 总结

Spring 框架提供了六个 Spring bean 作用域，并且实例在每个作用域内具有不同的生命周期跨度。 作为开发人员，我们必须明智地选择任何容器管理的 bean 的范围。 同样，当具有不同作用域的 bean 相互引用时，我们必须做出明智的决定。

试着记住上面给出的所有信息，以回答任何 SpringBean 范围面试问题。

学习愉快！