原文: 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 类实例。 该单个实例存储在此类单例 Bean 的缓存中,并且对该命名 Bean 的所有后续请求和引用都返回该缓存的实例。
使用 Java 配置的单例作用域 bean 的示例:
@Component//This statement is redundant - singleton is default scope@Scope("singleton") //This statement is redundantpublic class BeanClass {}
使用 XML 配置的单例作用域 bean 的示例:
<!-- 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 生命周期方法没有被称为prototype作用域 bean,仅调用了初始化回调方法。 因此,作为开发人员,您需要负责清理原型作用域的 Bean 实例以及其中包含的所有资源。
原型 bean 范围的 Java 配置示例:
@Component@Scope("prototype")public class BeanClass {}
原型 bean 范围的 XML 配置示例:
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="prototype" />
通常,您应该对所有有状态 Bean 使用prototype范围,而对无状态Bean使用singleton范围。要在请求,会话,应用程序和 Websocket 范围中使用 Bean,您需要注册RequestContextListener或者RequestContextFilter。
1.3. 请求范围
在request范围内,容器为每个 HTTP 请求创建一个新实例。 因此,如果服务器当前正在处理 50 个请求,则容器最多可以具有 50 个单独的 Bean 类实例。 对一个实例的任何状态更改,对其他实例都不可见。 请求完成后,这些实例将被销毁。
请求 bean 范围的 Java 配置示例:
@Component@Scope("request")public class BeanClass {}//or@Component@RequestScopepublic class BeanClass {}
请求 bean 范围的 XML 配置示例:
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="request" />
阅读更多: Web 服务器如何工作?
1.4. 会话范围
在session范围内,容器为每个 HTTP 会话创建一个新实例。 因此,如果服务器有 20 个活动会话,则容器最多可以具有 20 个 Bean 类的单独实例。 单个会话生存期内的所有 HTTP 请求都可以访问该会话范围内的同一单个 Bean 实例。
对一个实例的任何状态更改,对其他实例都不可见。 一旦会话在服务器上销毁/结束,这些实例将被销毁。
会话 bean 范围的 Java 配置示例:
@Component@Scope("session")public class BeanClass {}//or@Component@SessionScopepublic class BeanClass {}
会话 bean 范围的 XML 配置示例:
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="session" />
1.5. 应用范围
在application范围内,容器为每个 Web 应用程序运行时创建一个实例。 它几乎与singleton示波器相似,只有两个区别,即
application范围的 bean 是每个ServletContext单身,而singleton范围的 bean 是每个ApplicationContext单身。 请注意,单个应用程序可以有多个应用程序上下文。application范围内的 bean 作为ServletContext属性可见。
应用程序 bean 范围的 Java 配置示例:
@Component@Scope("application")public class BeanClass {}//or@Component@ApplicationScopepublic class BeanClass {}
应用程序 bean 范围的 XML 配置示例:
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="application" />
1.6. websocket 范围
WebSocket 协议允许客户端与已选择与客户端通信的远程主机之间进行双向通信。 WebSocket 协议为双向通信提供单个 TCP 连接。 这对于同时编辑和多用户游戏的多用户应用程序特别有用。
在这种类型的 Web 应用程序中,HTTP 仅用于初始握手。 如果服务器同意,服务器可以以 HTTP 状态 101(交换协议)进行响应。 如果握手成功,则 TCP 套接字保持打开状态,客户端和服务器都可以使用该套接字向彼此发送消息。
websocket bean 作用域的 Java 配置示例:
@Component@Scope("websocket")public class BeanClass {}
Websocket bean 作用域的 XML 配置示例:
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="websocket" />
请注意,websocket范围内的 bean 通常是单例的,并且比任何单独的 WebSocket 会话的生存期都更长。
2. 自定义线程范围
Spring 还使用类SimpleThreadScope提供了非默认thread范围。 要使用此作用域,必须使用CustomScopeConfigurer类将其注册到容器。
<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 配置示例:
@Component@Scope("thread")public class BeanClass {}
线程 bean 范围的 XML 配置示例:
<bean id="beanId" class="com.howtodoinjava.BeanClass" scope="thread" />
3. 总结
Spring 框架提供了六个 Spring bean 作用域,并且实例在每个作用域内具有不同的生命周期跨度。 作为开发人员,我们必须明智地选择任何容器管理的 bean 的范围。 同样,当具有不同作用域的 bean 相互引用时,我们必须做出明智的决定。
试着记住上面给出的所有信息,以回答任何 SpringBean 范围面试问题。
学习愉快!
