When you create a bean definition, you create a recipe for creating actual instances of the class defined by that bean definition. 当你创建一个 bean 定义时,你创建了一个用于创建由该 bean 定义的类实际实例的配方。 The idea that a bean definition is a recipe is important, because it means that, as with a class, you can create many object instances from a single recipe. 一个 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.
你可以控制不仅要将各种依赖项和配置值插入到从特定 bean 定义创建的对象中,还可以控制从特定 bean 定义创建的对象的作用域。
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.
这种方法强大且灵活,因为你可以通过配置来选择你创建的对象的作用域,而不是必须在 Java 类级别中硬编码对象的作用域。Bean
可以被定义为部署在多个作用域之一。
The Spring Framework supports six scopes, four of which are available only if you use a web-aware
ApplicationContext.
You can also create a custom scope.
Spring 框架支持六个作用域,其中四个只有在你使用具有网络意识的 ApplicationContext 时才可用。你还可以创建自定义作用域。
The following table describes the supported scopes: 以下表格描述了支持的范围:
Table 3. Bean scopes 表 3. 豆类范围
Scope 范围
Description 描述
(Default) Scopes a single bean definition to a single object instance for each Spring IoC container. (默认) 将单个 bean 定义范围限定为每个 Spring IoC 容器的一个对象实例。
Scopes a single bean definition to any number of object instances. 将单个 bean 定义扩展到任意数量的对象实例。
Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own
instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring
ApplicationContext.
将单个 bean 定义的范围限定在单个 HTTP 请求的生命周期中。也就是说,每个 HTTP 请求都有其基于单个 bean
定义创建的独立实例。仅在具有网络意识的
Spring ApplicationContext 上下文中有效。
Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware
Spring
ApplicationContext.
将单个 bean 定义范围限定到 HTTP Session 的生命周期中。仅在具有网络意识的 Spring ApplicationContext 的上下文中有效。
Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware
Spring
ApplicationContext.
将单个 bean 定义范围限定于 ServletContext 的生命周期。仅在具有网络意识的 Spring ApplicationContext 的上下文中有效。
Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring
ApplicationContext.
将单个 bean 定义范围限定于 WebSocket 的生命周期。仅在具有网络意识的 Spring ApplicationContext 的上下文中有效。
As of Spring 3.0, a thread scope is available but is not registered by default. For more information, see the
documentation for
SimpleThreadScope.
For instructions on how to register this or any other custom scope,
see Using a Custom Scope.
截至 Spring 3.0,线程作用域可用,但默认未注册。有关更多信息,请参阅 SimpleThreadScope
的文档。有关如何注册此作用域或任何其他自定义作用域的说明,请参阅使用自定义作用域。
1.5.1. 单例作用域
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. 仅管理一个单例 bean 的共享实例,所有请求 ID 或 ID 与该 bean 定义匹配的 bean 都将由 Spring 容器返回该特定 bean 实例。
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. 换句话说,当你定义一个 bean 定义,并且将其作用域设置为单例时,Spring IoC 容器将创建该 bean 定义所定义的对象的一个实例。 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 的缓存中,对该命名 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. Spring 的单例 bean 概念与《设计模式:可复用面向对象软件的基础》(Gang of Four,GoF)模式书中定义的单例模式不同。GoF 单例模式硬编码了对象的范围,使得每个 ClassLoader 只创建一个特定类的实例。 The scope of the Spring singleton is best described as being per-container and per-bean. Spring 单例的作用域最好描述为每个容器和每个 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. 这意味着,如果你在单个 Spring 容器中为特定类定义一个 bean,Spring 容器将根据该 bean 定义创建一个且仅创建一个类的实例。在 Spring 中,单例作用域是默认的作用域。 To define a bean as a singleton in XML, you can define a bean as shown in the following example: 要将一个 Bean 在 XML 中定义为单例,可以按照以下示例进行定义:
1.5.2. 原型范围
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.
非单例原型作用域的 bean 部署会导致每次对该特定 bean 的请求都创建一个新的 bean 实例。也就是说,bean 被注入到另一个 bean
中,或者你通过容器上的 getBean() 方法调用请求它。通常情况下,你应该为所有有状态的 bean 使用原型作用域,为无状态的 bean
使用单例作用域。
The following diagram illustrates the Spring prototype scope: 以下图表说明了 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: 以下示例在 XML 中将一个 bean 定义为原型:
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. 与其它作用域不同,Spring 不管理原型 bean 的完整生命周期。容器实例化、配置并组装原型对象,然后将其交给客户端,不再记录该原型实例。 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. 客户端代码必须清理原型作用域的对象并释放原型 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. (For details on the lifecycle of a
bean in the Spring container, see Lifecycle Callbacks.)
在某些方面,Spring 容器在原型作用域的 bean 方面的作用是 Java new 操作符的替代品。从那个点开始的所有生命周期管理都必须由客户端处理。(有关
Spring 容器中 bean 的生命周期详细信息,请参阅生命周期回调。)
1.5.3. 单例 Bean 与原型-bean 依赖
When you use singleton-scoped beans with dependencies on prototype beans, be aware that dependencies are resolved at instantiation time. 当你使用具有原型 bean 依赖的单例作用域 bean 时,请注意依赖项是在实例化时解决的。 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 的实例。
However, suppose you want the singleton-scoped bean to acquire a new instance of the prototype-scoped bean repeatedly at runtime. bean 在运行时反复获取原型作用域 bean 的新实例。 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 中,因为这种注入只发生一次,即在 Spring 容器实例化单例 bean 并解析和注入其依赖项时。 If you need a new instance of a prototype bean at runtime more than once, see Method Injection. 如果你在运行时需要多次获取原型 bean 的新实例,请参阅方法注入。
1.5.4. 请求、会话、应用程序和 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 作用域仅在你使用具有网络感知功能的 Spring ApplicationContext
实现(如
XmlWebApplicationContext )时可用。如果你将这些作用域与常规 Spring IoC 容器(如 ClassPathXmlApplicationContext
)一起使用,则会抛出一个关于未知 bean 作用域的异常 IllegalStateException 。
初始网络配置
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.)
为了支持在 request 、 session 、 application 和 websocket 级别(Web 作用域的 bean)中对 bean 进行范围定义,你在定义
bean 之前需要一些基本的初始配置。(对于标准作用域 singleton 和 prototype ,此初始设置不是必需的。)
How you accomplish this initial setup depends on your particular Servlet environment. 你如何完成此初始设置取决于你的特定 Servlet 环境。
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.
如果你在 Spring Web MVC 中访问作用域内的 bean,实际上,在由 Spring DispatcherServlet 处理的请求中,无需特殊设置。
DispatcherServlet 已经暴露了所有相关状态。
If you use a Servlet 2.5 web container, with requests processed outside of Spring’s DispatcherServlet (for
example,
when using JSF or Struts), you need to register the org.springframework.web.context.request.RequestContextListener
ServletRequestListener. For Servlet 3.0+, this can be done programmatically by using the
WebApplicationInitializer
interface. Alternatively, or for older containers, add the following declaration to your web application’s web.xml
file:
如果你使用 Servlet 2.5 Web 容器,并且请求在 Spring 的 DispatcherServlet 之外处理(例如,使用 JSF 或 Struts 时),则需要注册
org.springframework.web.context.request.RequestContextListener ServletRequestListener 。对于 Servlet 3.0+,可以通过使用
WebApplicationInitializer 接口进行程序化处理。或者,对于较旧的容器,将以下声明添加到你的 web 应用的 web.xml 文件中:
Alternatively, if there are issues with your listener setup, consider using Spring’s RequestContextFilter. The
filter
mapping depends on the surrounding web application configuration, so you have to change it as appropriate. The
following
listing shows the filter part of a web application:
另外,如果你的监听器设置存在问题,请考虑使用 Spring 的 RequestContextFilter 。过滤器映射取决于周围的 Web
应用程序配置,因此你需要根据实际情况进行更改。以下列表显示了 Web 应用程序的过滤器部分:
DispatcherServlet, RequestContextListener, and RequestContextFilter all do exactly the same thing, namely bind
the
HTTP request object to the Thread that is servicing that request. This makes beans that are request- and
session-scoped available further down the call chain.
DispatcherServlet 、 RequestContextListener 和 RequestContextFilter 都执行完全相同的功能,即绑定 HTTP
请求对象到正在处理该请求的
Thread 。这使得请求作用域和会话作用域的 bean 在调用链的更下游可用。
Consider the following XML configuration for a bean definition:
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.
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:
Consider the following XML configuration for a bean definition: 考虑以下用于 bean 定义的 XML 配置:
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 请求的 bean 定义创建 UserPreferences bean 的新实例。换句话说, userPreferences bean 在
HTTP
Session 级别上有效。与请求作用域的 bean 一样,你可以随意更改创建的实例的内部状态,因为知道其他也使用从同一
userPreferences bean 定义创建的实例的 HTTP Session 实例不会看到这些状态变化,因为这些变化仅针对单个 HTTP
Session 。当
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 注解将组件分配给 session 作用域。
Consider the following XML configuration for a bean definition: 考虑以下用于 bean 定义的 XML 配置:
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 注解将组件分配给 application 作用域。以下示例展示了如何操作:
WebSocket scope is associated with the lifecycle of a WebSocket session and applies to STOMP over WebSocket applications, see WebSocket scope for more details. WebSocket 作用域与 WebSocket 会话的生命周期相关联,适用于 STOMP over WebSocket 应用程序,有关更多详细信息,请参阅 WebSocket 作用域。
作用域内 Bean 作为依赖项
The Spring IoC container manages not only the instantiation of your objects (beans), but also the wiring up of collaborators (or dependencies). Spring IoC 容器不仅管理你的对象(bean)的实例化,还负责连接协作者(或依赖项)。 If you want to inject (for example) an HTTP request-scoped bean into another bean of a longer-lived scope, you may choose to inject an AOP proxy in place of the scoped bean. 如果你想将(例如)一个请求作用域的 bean 注入到具有更长生命周期的 bean 中,你可以选择注入一个 AOP 代理来代替作用域 bean。 That is, you need to inject a proxy object that exposes the same public interface as the scoped object but that can also retrieve the real target object from the relevant scope (such as an HTTP request) and delegate method calls onto the real object. 这意味着你需要注入一个代理对象,该对象公开与作用域对象相同的公共接口,但也可以从相关作用域(如 HTTP 请求)检索实际目标对象,并将方法调用委托给实际对象。
You may also use <aop:scoped-proxy/> between beans that are scoped as singleton, with the reference then going
through an intermediate proxy that is serializable and therefore able to re-obtain the target singleton bean on
deserialization.
你还可以在作用域为 singleton 的豆子之间使用 <aop:scoped-proxy/> ,此时引用将通过一个可序列化的中间代理进行传递,因此能够在反序列化时重新获取目标单例
bean。
When declaring <aop:scoped-proxy/> against a bean of scope prototype, every method call on the shared proxy leads to
the creation of a new target instance to which the call is then being forwarded.
当对作用域为 prototype 的 bean 声明 <aop:scoped-proxy/> 时,对共享代理的每次方法调用都会导致创建一个新的目标实例,然后调用被转发到该实例。
Also, scoped proxies are not the only way to access beans from shorter scopes in a lifecycle-safe fashion. You may
also
declare your injection point (that is, the constructor or setter argument or autowired field) as
ObjectFactory<MyTargetBean>, allowing for a getObject() call to retrieve the current instance on demand every
time
it is needed — without holding on to the instance or storing it separately.
此外,作用域代理并非访问较短作用域中 bean 的唯一方式。你还可以将你的注入点(即构造函数或 setter 参数或 autowired 字段)声明为
ObjectFactory<MyTargetBean> ,允许在需要时每次按需调用 getObject() 以检索当前实例——而不必保留实例或将其单独存储。
As an extended variant, you may declare ObjectProvider<MyTargetBean> which delivers several additional access
variants, including getIfAvailable and getIfUnique.
作为一个扩展变体,你可以声明 ObjectProvider<MyTargetBean> ,它提供了包括 getIfAvailable 和 getIfUnique
在内的几个附加访问变体。
The JSR-330 variant of this is called Provider and is used with a Provider<MyTargetBean> declaration and a
corresponding get() call for every retrieval attempt. See here for more details on
JSR-330 overall.
这种 JSR-330 变体称为 Provider ,与 Provider<MyTargetBean> 声明和每个检索尝试的相应 get() 调用一起使用。有关
JSR-330
整体详情,请参阅此处。
The configuration in the following example is only one line, but it is important to understand the “why” as well as the “how” behind it: 以下示例中的配置只有一行,但理解其背后的“为什么”以及“如何”同样重要:
1
The line that defines the proxy. 定义代理的行。
To create such a proxy, you insert a child <aop:scoped-proxy/> element into a scoped bean definition (
see Choosing the Type of Proxy to Create
and XML Schema-based configuration). Why do definitions of beans scoped at the request, session
and
custom-scope levels require the <aop:scoped-proxy/> element? Consider the following singleton bean definition and
contrast it with what you need to define for the aforementioned scopes (note that the following userPreferences
bean
definition as it stands is incomplete):
为了创建这样的代理,你需要在作用域的 bean 定义中插入一个子 <aop:scoped-proxy/> 元素(参见《创建代理的类型选择》和基于 XML
Schema 的配置)。为什么在 request 、 session 和自定义作用域级别的 bean 定义需要 <aop:scoped-proxy/> 元素?考虑以下单例
bean 定义,并将其与你需要定义的上述作用域进行对比(请注意,以下 userPreferences bean 定义目前是不完整的):
In the preceding example, the singleton bean (userManager) is injected with a reference to the HTTP
Session-scoped
bean (userPreferences). The salient point here is that the userManager bean is a singleton: it is instantiated
exactly once per container, and its dependencies (in this case only one, the userPreferences bean) are also
injected
only once. This means that the userManager bean operates only on the exact same userPreferences object (that is,
the
one with which it was originally injected).
在先前的示例中,单例 bean( userManager )注入了对 HTTP Session 作用域 bean( userPreferences )的引用。这里的要点是
userManager bean 是单例:它在每个容器中只实例化一次,其依赖项(在这种情况下只有一个,即 userPreferences
bean)也只注入一次。这意味着
userManager bean 仅在完全相同的 userPreferences 对象上操作(即它最初注入的那个对象)。
This is not the behavior you want when injecting a shorter-lived scoped bean into a longer-lived scoped bean (for
example, injecting an HTTP Session-scoped collaborating bean as a dependency into singleton bean). Rather, you
need a
single userManager object, and, for the lifetime of an HTTP Session, you need a userPreferences object that is
specific to the HTTP Session. Thus, the container creates an object that exposes the exact same public interface
as
the UserPreferences class (ideally an object that is a UserPreferences instance), which can fetch the real
UserPreferences object from the scoping mechanism (HTTP request, Session, and so forth). The container injects
this
proxy object into the userManager bean, which is unaware that this UserPreferences reference is a proxy. In this
example, when a UserManager instance invokes a method on the dependency-injected UserPreferences object, it is
actually invoking a method on the proxy. The proxy then fetches the real UserPreferences object from (in this
case)
the HTTP Session and delegates the method invocation onto the retrieved real UserPreferences object.
这不是将短生命周期作用域的 bean 注入到长生命周期作用域的 bean(例如,将 HTTP Session 作用域的协作 bean 作为依赖项注入到单例
bean)时你想要的行为。相反,你需要一个单一的 userManager 对象,并且,在 HTTP Session 的生命周期内,你需要一个特定于
HTTP
Session 的 userPreferences 对象。因此,容器创建了一个对象,该对象公开与 UserPreferences 类完全相同的公共接口(理想情况下是一个
UserPreferences 实例),可以从作用域机制(HTTP 请求、 Session 等)中检索真实的 UserPreferences 对象。容器将这个代理对象注入到
userManager bean 中,该 bean 不知道这个 UserPreferences 引用是一个代理。在这个例子中,当 UserManager 实例在依赖注入的
UserPreferences 对象上调用方法时,它实际上是在调用代理上的方法。然后代理从(在这种情况下)HTTP Session 中检索真实的
UserPreferences 对象,并将方法调用委托给检索到的真实 UserPreferences 对象。
Thus, you need the following (correct and complete) configuration when injecting request- and session-scoped
beans
into collaborating objects, as the following example shows:
因此,当将 request- 和 session-scoped 豆注入协作对象时,你需要以下(正确且完整的)配置,如下例所示:
选择创建代理的类型
By default, when the Spring container creates a proxy for a bean that is marked up with the <aop:scoped-proxy/>
element, a CGLIB-based class proxy is created.
默认情况下,当 Spring 容器为标记有 <aop:scoped-proxy/> 元素的 bean 创建代理时,会创建一个基于 CGLIB 的类代理。
CGLIB proxies do not intercept private methods. Attempting to call a private method on such a proxy will not delegate to the actual scoped target object. CGLIB 代理不拦截私有方法。尝试在这样一个代理上调用私有方法不会委派到实际的作用域目标对象。
Alternatively, you can configure the Spring container to create standard JDK interface-based proxies for such scoped
beans, by specifying false for the value of the proxy-target-class attribute of the <aop:scoped-proxy/> element.
Using JDK interface-based proxies means that you do not need additional libraries in your application classpath to
affect such proxying.
另外,你可以通过指定 <aop:scoped-proxy/> 元素的 proxy-target-class 属性的值为 false 来配置 Spring 容器为这样的作用域
bean 创建基于 JDK 接口的标准代理。使用基于 JDK 接口的代理意味着你不需要在应用程序类路径中添加额外的库来影响这种代理。
However, it also means that the class of the scoped bean must implement at least one interface and that all
collaborators into which the scoped bean is injected must reference the bean through one of its interfaces. The
following example shows a proxy based on an interface:
然而,这也意味着作用域 bean 的类必须实现至少一个接口,并且所有注入到作用域 bean 中的协作者都必须通过其接口之一引用该
bean。以下示例展示了基于接口的代理:
For more detailed information about choosing class-based or interface-based proxying, see Proxying Mechanisms. 关于选择基于类或基于接口的代理的更详细信息,请参阅代理机制。
The bean scoping mechanism is extensible. You can define your own scopes or even redefine existing scopes, although
the
latter is considered bad practice and you cannot override the built-in singleton and prototype scopes.
Java 的作用域机制是可扩展的。你可以定义自己的作用域,甚至重新定义现有作用域,尽管后者被视为不良实践,并且你不能覆盖内置的
singleton 和 prototype 作用域。
创建自定义范围
To integrate your custom scopes into the Spring container, you need to implement the
org.springframework.beans.factory.config.Scope interface, which is described in this section. For an idea of how
to
implement your own scopes, see the Scope implementations that are supplied with the Spring Framework itself and
the
Scope
javadoc, which explains the methods you need to implement in more detail.
要将自定义作用域集成到 Spring 容器中,你需要实现 org.springframework.beans.factory.config.Scope
接口,该接口在本节中有所描述。有关如何实现你自己的作用域的示例,请参阅 Spring 框架本身提供的 Scope 实现和 Scope
javadoc,它更详细地解释了你需要实现的方法。
The Scope interface has four methods to get objects from the scope, remove them from the scope, and let them be
destroyed.
Scope 接口有四种方法用于从作用域获取对象、从作用域中移除它们以及让它们被销毁。
The session scope implementation, for example, returns the session-scoped bean (if it does not exist, the method returns a new instance of the bean, after having bound it to the session for future reference). The following method returns the object from the underlying scope: 会话作用域实现,例如,返回会话作用域的 bean(如果不存在,该方法将返回一个新实例的 bean,在将其绑定到会话以供将来引用之前)。以下方法返回底层作用域的对象:
The session scope implementation, for example, removes the session-scoped bean from the underlying session. The object
should be returned, but you can return null if the object with the specified name is not found. The following method
removes the object from the underlying scope:
会话作用域实现,例如,从底层会话中删除会话作用域的 bean。应该返回对象,但如果找不到指定名称的对象,则可以返回 null
。以下方法从底层作用域中删除对象:
The following method registers a callback that the scope should invoke when it is destroyed or when the specified object in the scope is destroyed: 以下方法注册了一个回调,当作用域被销毁或作用域中指定的对象被销毁时,作用域应该调用该回调:
See the javadoc or a Spring scope implementation for more information on destruction callbacks. 查看 javadoc 或 Spring 作用域实现以获取有关销毁回调的更多信息。
The following method obtains the conversation identifier for the underlying scope: 以下方法获取底层作用域的会话标识符:
This identifier is different for each scope. For a session scoped implementation, this identifier can be the session identifier.
使用自定义范围
After you write and test one or more custom Scope implementations, you need to make the Spring container aware of your
new scopes. The following method is the central method to register a new Scope with the Spring container:
在你编写和测试一个或多个自定义 Scope 实现之后,你需要让 Spring 容器知道你的新作用域。以下方法是向 Spring 容器注册新
Scope 的核心方法:
This method is declared on the ConfigurableBeanFactory interface, which is available through the BeanFactory
property on most of the concrete ApplicationContext implementations that ship with Spring.
此方法在 ConfigurableBeanFactory 接口上声明,通过 Spring 附带的大多数具体 ApplicationContext 实现的 BeanFactory
属性可以获得。
The first argument to the registerScope(..) method is the unique name associated with a scope. Examples of such names
in the Spring container itself are singleton and prototype. The second argument to the registerScope(..) method is
an actual instance of the custom Scope implementation that you wish to register and use.
Suppose that you write your custom Scope implementation, and then register it as shown in the next example.
The next example uses SimpleThreadScope, which is included with Spring but is not registered by default. The
instructions would be the same for your own custom Scope implementations.
You can then create bean definitions that adhere to the scoping rules of your custom Scope, as follows:
With a custom Scope implementation, you are not limited to programmatic registration of the scope. You can also do the
Scope registration declaratively, by using the CustomScopeConfigurer class, as the following example shows:
When you place <aop:scoped-proxy/> within a <bean> declaration for a FactoryBean implementation, it is the factory
bean itself that is scoped, not the object returned from getObject().
当你在一个 FactoryBean 实现体的 <bean> 声明中放置 <aop:scoped-proxy/> 时,是工厂 bean 本身被作用域化,而不是从
getObject() 返回的对象。