Spring Core 之 Bean Scopes(Bean的作用域)


生词汇总

  • bake ------------------------------------ 烤, 烘, 烘烤
  • as a rule ------------------------------ 通常
  • contrast ------------------------------- 对比, 对照, 比照
  • hands it to ---------------------------- 交给
  • in regard to ------------------------- 关于, 对于, 于
  • sole ------------------------------------ 唯一, 单一, 独
  • in effect ----------------------------- 有效
  • as much as you want ---------------- 随心所欲

一、Bean Scopes Overview(作用域概述)

When you create a bean definition,you create a recipe for creating instances of the class defined by that bean definaition.The idea that a bean definition is a recipe is important,beacuse it means that,as with a class,you can create object instances from a single recipe.

当你创建了一个bean定义,相当于创建了一个类如何创建其bean实例的配方,这种将bean定义看作配方的想法很重要,因为这意味着,对于一个类,你可以使用单个配方创建许多对象实例。

You can control not only the various dependencies and configuration values that are to be plugged into an object that is created from a particular bean definition but also control the scope of the objects created from a particular bean definition.This approach is powerful and flexible,because you can choose the scope of the objects you create through configuration instead of having to bake in the scope of an object at the java class level.Beans can be defined to be deployed in one of a number of scopes.The SpringFramework support six scopes,four of which are available only if you use a web-aware ApplicationContext.You can also create a custom scope.

你不仅可以通过特定的bean定义来控制对象各种各样的依赖关系和配置对象的各个属性值,而且可以控制对象的作用域。这种方式非常有用且灵活,因为你可以通过定义配置来选择对象的作用域,而不是在java类级别进行处理,可以将 Bean 的作用域定义为多个作用域之一。Spring框架提供了六种作用域,对于其中的四种,只有使用基于Web的ApplicationContext时才有效,你也可以自定义上下文。

The following list describes the supported scopes:
以下列表描述了支持的范围:

  • singleton:(Default)Scopes a single bean definition to a single object instance for each Spring IoC container.
    默认作用域,singleton的bean定义指明对于一个Spring IOC容器中只创建一个bean实例。
  • prototype:Scopes a single bean definition to any number of object instances.
    一个bean定义可以创建任意个对象实例。也就是说每一次获取都是新创建的对象实例。
  • request:Scopes a single bean definition to the lifecycle of a single HTTP request.That is,each HTTP request has its own instance of bean created off the back of a single bean definition.Only valid in the context of a web-aware Spring ApplicationContext.
    将单个 bean 定义范围限定为单个 HTTP 请求的生命周期。也就是说,对于每一次HTTP请求创建一个实例对象。只有使用基于Web的ApplicationContext时才有效。
  • session:Scopes a single bean definition to the lifecycle of an HTTP session.Only valid in the context of a web-aware Spring ApplicationContext.
    在一个HTTP session中定义单个bean,只有使用基于Web的ApplicationContext时才有效。
  • application:Scopes a single bean definition to the lifecycle of a ServletContext.Only valid in the context of a web-aware Spring ApplicationContext.
    在一个ServletContext中定义单个bean,只有使用基于Web的ApplicationContext时才有效。
  • websocket:Scopes a single bean definition to the lifecycle of a websocket.Only valid in the context of a web-aware Spring ApplicationContext.
    在一个websocket中定义单个bean,只有使用基于Web的ApplicationContext时才有效。

二、The Singleton Scope(单例作用域)

Only one shared instance of a singleton bean is managed, and all requests for beans with an ID or IDs that match that bean definition result in that one specific bean instance being returned by the Spring container.To put it another way, when you define a bean definition and it is scoped as a singleton, the Spring IoC container creates exactly one instance of the object defined by that bean definition. This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object. The following image shows how the singleton scope works:

只有一个共享的单实例bean 被管理,并且对带有一个或多个 ID 与该 bean 定义匹配的 bean 的请求, Spring 容器都返回一个特定的 bean 实例。换句话说,当你将一个bean的作用域定义为singleton,Spring容器明确的创建一个该bean定义的实例对象,这个单例对象被存储在专门存放单例对象的缓存中,并且随后所有对这个bean的请求和引用都会返回被缓存的对象。下图显示了单例范围的工作原理:
在这里插入图片描述
Spring’s concept of a singleton bean differs from the singleton pattern as defined in the Gang of Four (GoF) patterns book. The GoF singleton hard-codes the scope of an object such that one and only one instance of a particular class is created per ClassLoader. The scope of the Spring singleton is best described as being per-container and per-bean. This means that, if you define one bean for a particular class in a single Spring container, the Spring container creates one and only one instance of the class defined by that bean definition. The singleton scope is the default scope in Spring. To define a bean as a singleton in XML, you can define a bean as shown in the following example:

Spring中对于singleton的概念不同于“Gang Of Four”书中单例模式的概念,在“Gang Of Four”书中单例模式对对象的范围进行了硬编码,以便每个 ClassLoader 只创建一个指定类的一个实例。而Spring对单例的描述是一个容器中只有一个bean实例。这意味着如果你在一个容器中将一个指定类定义为单例的,Spring容器就只创建唯一一个实例。单例作用域是 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"/>

三、The Prototype Scope(原型作用域)

The non-singleton prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made. That is, the bean is injected into another bean or you request it through a getBean() method call on the container. As a rule, you should use the prototype scope for all stateful beans and the singleton scope for stateless beans.
The following diagram illustrates the Spring prototype scope:

bean 部署的非单一原型作用域使每次对特定 bean 发出请求时都会创建一个新 bean 实例。也就是说,bean 被注入到另一个 bean 中,或者你通过容器上的 getBean() 方法调用来请求它时都会创建一个新 bean 实例。通常,您应该对所有有状态 bean 使用原型作用域,对无状态 bean 使用单例作用域。有状态可以理解为对于同一个类的每一个实例,它们都有自己不同的属性值,相当于有不同的状态;而无状态实例通常是没有属性值,只有数据处理方法的类实例,如DAO和Service实例对象。
下图说明了 Spring 原型范围:
在这里插入图片描述
(A data access object (DAO) is not typically configured as a prototype, because a typical DAO does not hold any conversational state. It was easier for us to reuse the core of the singleton diagram.)
数据访问对象 (DAO) 通常不配置为原型,因为典型的 DAO 不保存任何会话状态。我们更容易重用单例图的核心。

The following example defines a bean as a prototype in XML:
以下示例将 bean 定义为 XML 中的原型:

<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>

In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean. The container instantiates, configures, and otherwise assembles a prototype object and hands it to the client, with no further record of that prototype instance. Thus, although initialization lifecycle callback methods are called on all objects regardless of scope, in the case of prototypes, configured destruction lifecycle callbacks are not called. The client code must clean up prototype-scoped objects and release expensive resources that the prototype beans hold. To get the Spring container to release resources held by prototype-scoped beans, try using a custom bean post-processor, which holds a reference to beans that need to be cleaned up.

与其他作用域相比,Spring 不管理原型 bean 的整个生命周期。容器实例化、配置和装配一个原型对象然后把它交给客户端,便不再记录该原型对象。因此,在原型作用域下,尽管配置了生命周期回调函数,但也不会被调用执行。客户端代码必须清理原型作用域的对象以释放被原型对象占有的昂贵资源。要让 Spring 容器释放原型作用域 bean 持有的资源,请尝试使用自定义 bean 后置处理器,它保存有对需要清理的 bean 的引用。

In some respects, the Spring container’s role in regard to a prototype-scoped bean is a replacement for the Java new operator. All lifecycle management past that point must be handled by the client.

在某些方面,Spring容器对于原型作用域的bean来说相当于java代码中new操作符的替换。原型作用域对象的所有生命周期管理都必须由客户端处理。

四、Singleton Beans with Prototype-bean Dependencies(单例作用域依赖原型作用域的bean)

When you use singleton-scoped beans with dependencies on prototype beans, be aware that dependencies are resolved at instantiation time. Thus, if you dependency-inject a prototype-scoped bean into a singleton-scoped bean, a new prototype bean is instantiated and then dependency-injected into the singleton bean. The prototype instance is the sole instance that is ever supplied to the singleton-scoped bean.

当你使用单例作用域的 bean 对原型 bean 依赖时,请注意到解析依赖关系是在实例化时。因此,如果你将原型作用域的 bean 依赖注入到单例作用域的 bean 中,则会实例化一个新的原型 bean,然后将依赖项注入到单例 bean 中。这个原型实例是唯一提供给单例作用域 bean 的实例。

However, suppose you want the singleton-scoped bean to acquire a new instance of the prototype-scoped bean repeatedly at runtime. You cannot dependency-inject a prototype-scoped bean into your singleton bean, because that injection occurs only once, when the Spring container instantiates the singleton bean and resolves and injects its dependencies.

但是,假设你希望单例作用域的 bean 在运行时重复获取原型作用域的 bean 的新实例。你不能将原型作用域的 bean 依赖注入到您的单例 bean 中,因为该注入仅发生一次,当 Spring 容器实例化单例 bean 并解析和注入其依赖项时。

五、Request,Session,Application,and WebSocket Scopes(Request,Session,Application和WebSocket作用域)

The request, session, application, and websocket scopes are available only if you use a web-aware Spring ApplicationContext implementation (such as XmlWebApplicationContext). If you use these scopes with regular Spring IoC containers, such as the ClassPathXmlApplicationContext, an IllegalStateException that complains about an unknown bean scope is thrown.

request,session,application和websocket作用域仅在使用基于Web的ApplicationContext实现中有效(如XmlWebApplicationContext)。如果你在常规的Spring容器中使用这些作用域,将会抛出一个非法参数异常,并提示unknown bean scope。

1、Initial Web Configuration(初始化Web配置)

To support the scoping of beans at the request, session, application, and websocket levels (web-scoped beans), some minor initial configuration is required before you define your beans. (This initial setup is not required for the standard scopes: singleton and prototype.)If you access scoped beans within Spring Web MVC, in effect, within a request that is processed by the Spring DispatcherServlet, no special setup is necessary. DispatcherServlet already exposes all relevant state.

为了能够使用request,session,application和websocket等作用域,在你定义你的bean之前,需要一些小的初始化配置。该初始化步骤对于singleton和prototype作用域不需要)。如果你在Spring Web MVC中获取作用域bean,实际上是在 Spring DispatcherServlet 处理的请求中,则不需要特殊设置。DispatcherServlet 已经公开了所有相关的状态。

2、Request scope(Request作用域)

Consider the following XML configuration for a bean definition:
参考以下 bean 定义的 XML 配置:

<bean id="loginAction" class="com.something.LoginAction" scope="request"/>

The Spring container creates a new instance of the LoginAction bean by using the loginAction bean definition for each and every HTTP request. That is, the loginAction bean is scoped at the HTTP request level. You can change the internal state of the instance that is created as much as you want, because other instances created from the same loginAction bean definition do not see these changes in state. They are particular to an individual request. When the request completes processing, the bean that is scoped to the request is discarded.

Spring容器通过使用loginAction bean定义为每一个HTTP请求创建一个新的LoginAction bean实例。也就是说,loginAction bean的作用域是request级别。您可以根据需要更改创建的实例的内部状态,因为其他通过同一个bean定义创建出的实例并不会被影响。它们对每一个请求是特别的。当请求处理完毕后,该bean实例就会被抛弃。

When using annotation-driven components or Java configuration, the @RequestScope annotation can be used to assign a component to the request scope. The following example shows how to do so:

当使用注解驱动的组件或 Java 配置时,@RequestScope 注解可用于将组件分配给请求范围。以下示例显示了如何执行此操作:

@RequestScope
@Component
public class LoginAction {
    // ...
}

3、Session Scope(Session作用域)

Consider the following XML configuration for a bean definition:
参考以下 bean 定义的 XML 配置:

<bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>

The Spring container creates a new instance of the UserPreferences bean by using the userPreferences bean definition for the lifetime of a single HTTP Session. In other words, the userPreferences bean is effectively scoped at the HTTP Session level. As with request-scoped beans, you can change the internal state of the instance that is created as much as you want, knowing that other HTTP Session instances that are also using instances created from the same userPreferences bean definition do not see these changes in state, because they are particular to an individual HTTP Session. When the HTTP Session is eventually discarded, the bean that is scoped to that particular HTTP Session is also discarded.

Spring 容器通过在单个 HTTP 会话的生命周期中使用 userPreferences bean 定义创建 UserPreferences bean 的新实例。换句话说,userPreferences bean 有效地限定在 HTTP Session级别。与Request作用域的 bean 一样,你可以根据需要更改创建的实例的内部状态,使用从相同 userPreferences bean 定义创建的实例的其他 HTTP Session实例不会看到这些状态更改,因为它们特定于单个 HTTP 会话。当 HTTP Session最终被丢弃时,作用域为该特定 HTTP Session的 bean 也将被丢弃。

When using annotation-driven components or Java configuration, you can use the @SessionScope annotation to assign a component to the session scope.

使用注解驱动的组件或 Java 配置时,您可以使用 @SessionScope 注解将组件分配给会话范围。

@SessionScope
@Component
public class UserPreferences {
    // ...
}

3、Application Scope(Application作用域)

Consider the following XML configuration for a bean definition:
参考以下 bean 定义的 XML 配置:

<bean id="appPreferences" class="com.something.AppPreferences" scope="application"/>

The Spring container creates a new instance of the AppPreferences bean by using the appPreferences bean definition once for the entire web application. That is, the appPreferences bean is scoped at the ServletContext level and stored as a regular ServletContext attribute. This is somewhat similar to a Spring singleton bean but differs in two important ways: It is a singleton per ServletContext, not per Spring ‘ApplicationContext’ (for which there may be several in any given web application), and it is actually exposed and therefore visible as a ServletContext attribute.

Spring 容器通过为整个 Web 应用程序使用 appPreferences bean 定义来创建 一次AppPreferences bean 的新实例。也就是说,appPreferences bean 的作用域是 ServletContext 级别并存储为一个常规 ServletContext 属性。这有点类似于 Spring 单例 bean,但在两个重要方面有所不同:它是每个 ServletContext 的单例,而不是每个 Spring ‘ApplicationContext’(在任何给定的 Web 应用程序中可能有多个),而且它实际上是公开的,因此作为 ServletContext 属性可见。

When using annotation-driven components or Java configuration, you can use the @ApplicationScope annotation to assign a component to the application scope. The following example shows how to do so:

当使用注解驱动的组件或 Java 配置时,您可以使用 @ApplicationScope 注解将组件分配给应用程序范围。以下示例显示了如何执行此操作:

@ApplicationScope
@Component
public class AppPreferences {
    // ...
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值