Bean 的范围:
范围 | 描述 |
---|---|
singleton | (默认)将单个 bean 定义范围限定为每个 Spring IoC 容器的单个对象实例。 |
prototype | 将单个 bean 定义范围限定为任意数量的对象实例。 |
request | 将单个 bean 定义范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有自己的 bean 实例,该 bean 实例是在单个 bean 定义的后面创建的。仅在 web-aware Spring 的上下文中有效ApplicationContext 。 |
session | 将单个 bean 定义范围限定为 HTTP 的生命周期Session 。仅在 web-aware Spring 的上下文中有效ApplicationContext 。 |
application | 将单个 bean 定义范围限定为ServletContext . 仅在 web-aware Spring 的上下文中有效ApplicationContext 。 |
websocket | 将单个 bean 定义范围限定为WebSocket . 仅在 web-aware Spring 的上下文中有效ApplicationContext 。 |
单例作用域
当您定义一个 bean 定义并且它的作用域是一个单例时,Spring IoC 容器会创建该 bean 定义定义的对象的一个实例。该单个实例存储在此类单例 bean 的缓存中,并且对该命名 bean 的所有后续请求和引用都返回缓存对象。下图显示了单例范围的工作原理:
单身人士Spring 的单例 bean 概念不同于四人组 (GoF) 模式书中定义的单例模式。GoF 单例对对象的范围进行了硬编码,以便每个 ClassLoader 只创建一个特定类的一个实例。Spring 单例的范围最好描述为每个容器和每个 bean。这意味着,如果您在单个 Spring 容器中为特定类定义一个 bean,则 Spring 容器会创建该 bean 定义定义的类的一个且仅一个实例。单例作用域是 Spring 中的默认作用域。要将 bean 定义为 XML 中的单例,您可以定义一个 bean,如下例所示:
<bean id="accountService" class="com.something.DefaultAccountService"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
原型范围
bean 部署的非单一原型范围导致每次对特定 bean 发出请求时都会创建一个新 bean 实例。也就是说,bean 被注入到另一个 bean 中,或者您通过getBean()
容器上的方法调用来请求它。通常,您应该对所有有状态 bean 使用原型作用域,对无状态 bean 使用单例作用域。
下图说明了 Spring 原型范围:
原型(数据访问对象 (DAO) 通常不配置为原型,因为典型的 DAO 不保存任何对话状态。我们更容易重用单例图的核心。)
以下示例将 bean 定义为 XML 中的原型:
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
与其他作用域相比,Spring 不管理原型 bean 的完整生命周期。容器实例化、配置和以其他方式组装原型对象并将其交给客户端,没有该原型实例的进一步记录。因此,尽管在所有对象上调用初始化生命周期回调方法,而不管范围如何,但在原型的情况下,不会调用配置的销毁生命周期回调。客户端代码必须清理原型范围内的对象并释放原型 bean 持有的昂贵资源。要让 Spring 容器释放原型作用域 bean 持有的资源,请尝试使用自定义bean post-processor,它保存对需要清理的 bean 的引用。
在某些方面,Spring 容器在原型作用域 bean 方面的角色是 Javanew
运算符的替代品。超过该点的所有生命周期管理都必须由客户端处理。
请求、会话、应用程序和 WebSocket 范围
在request
,session
,application
,和websocket
范围只有当你使用一个基于web的Spring在ApplicationContext
实现(例如 XmlWebApplicationContext
)。如果将这些作用域与常规 Spring IoC 容器(例如 )一起使用ClassPathXmlApplicationContext
,IllegalStateException
则会抛出抱怨未知 bean 作用域的 。
请求范围
考虑以下 bean 定义的 XML 配置:
<bean id="loginAction" class="com.something.LoginAction" scope="request"/>
Spring 容器LoginAction
通过loginAction
对每个 HTTP 请求使用bean 定义来创建bean 的新实例。也就是说, loginAction
bean 的范围在 HTTP 请求级别。您可以根据需要更改所创建实例的内部状态,因为从同一loginAction
bean 定义创建的其他实例看不到这些状态更改。它们是针对个人要求的。当请求完成处理时,该请求范围内的 bean 将被丢弃。
当使用注解驱动的组件或 Java 配置时,@RequestScope
注解可用于将组件分配给request
作用域。以下示例显示了如何执行此操作:
@RequestScope
@Component
public class LoginAction {
// ...
}
会话范围
考虑以下 bean 定义的 XML 配置:
<bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>
Spring 容器UserPreferences
通过在userPreferences
单个 HTTP 的生命周期中使用bean 定义来创建bean 的新实例Session
。换句话说,userPreferences
bean 有效地限定在 HTTPSession
级别。与请求范围的 bean 一样,您可以根据需要更改所创建实例的内部状态,因为知道其他Session
也在使用从相同userPreferences
bean 定义创建的实例的HTTP实例不会看到这些状态更改,因为它们特定于单个 HTTP Session
。当 HTTPSession
最终被丢弃时,作用域为该特定 HTTP 的 bean Session
也将被丢弃。
当使用注解驱动的组件或 Java 配置时,您可以使用 @SessionScope
注解将组件分配给session
作用域。
@SessionScope
@Component
public class UserPreferences {
// ...
}
应用程序范围
考虑以下 bean 定义的 XML 配置:
<bean id="appPreferences" class="com.something.AppPreferences" scope="application"/>
Spring 容器AppPreferences
通过appPreferences
对整个 Web 应用程序使用一次 bean 定义来创建bean 的新实例。也就是说, appPreferences
bean 的作用域在ServletContext
级别并存储为常规 ServletContext
属性。这有点类似于 Spring 单例 bean,但在两个重要方面有所不同:它是一个单例 per ServletContext
,而不是 per Spring ApplicationContext
(在任何给定的 Web 应用程序中可能有多个),并且它实际上是公开的,因此作为一个ServletContext
属性可见.
当使用注解驱动的组件或 Java 配置时,您可以使用 @ApplicationScope
注解将组件分配给application
作用域。以下示例显示了如何执行此操作:
@ApplicationScope
@Component
public class AppPreferences {
// ...
}
以上文档来自Spring官方网站,关于 Spring-framework 文档 Bean作用域介绍。
网友评论