Spring Framework Documentation (5.3.10)
Core | IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP. |
1. The IoC Container
1.1. Introduction to the Spring IoC Container and Beans(Spring IoC容器和bean简介)
1.2. Container Overview (容器概览)
1.5.1. The Singleton Scope (单例作用域)
1.5.2. The Prototype Scope(Prototype作用域)
1.5.3. Singleton Beans with Prototype-bean Dependencies(单例和原型Bean的依赖)
1.5.4. Request, Session, Application, and WebSocket Scopes
1.5.4.1. Initial Web Configuration (初始化Web配置)
1.5.4.4. Application Scope(应用作用域)
1.5.4.5. Scoped Beans as Dependencies (具有作用域的bean作为依赖项)
1.5.4.5.1 Choosing the Type of Proxy to Create(选择待创建代理的类型)
1.5.5.1. Creating a Custom Scope(创建自定义作用域)
1.5.5.2. Using a Custom Scope (使用自定义作用域)
下载此文档精编完整版
No. | 内容 | 下载地址 | 文档内容目录 |
1 | 中英双语精编版 第一部分 | PDF下载 | 内容目录 |
2 | 中英双语精编版 第二部分 | PDF下载 | 内容目录 |
3 | 中文精编版 第一部分 | PDF下载 | 内容目录 |
4 | 中文精编版 第二部分 | PDF下载 | 内容目录 |
更多章节内容,请点击查看: Core Technologies
1.5.4.5. Scoped Beans as Dependencies (具有作用域的bean作为依赖项)
The Spring IoC container manages not only the instantiation of your objects (beans), but also the wiring up of collaborators (or dependencies). 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. 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.
Spring IOC容器不仅管理对象(bean)的实例化,还管理协作者(collaborator)(或依赖项(dependency))的装配。如果您想要(例如)将HTTP请求作用域(HTTP request-scoped)的bean注入到另一个更长寿命作用域(longer-lived scope)的bean中,您可以选择注入AOP代理来代替具有作用域的bean。也就是说,您需要注入一个代理对象,该代理对象公开与作用域对象相同的公共接口,但也可以从相关作用域(如HTTP请求作用域)检索真实目标对象,并将方法调用委托给真实对象。
You may also use When declaring 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 As an extended variant, you may declare The JSR-330 variant of this is called |
您还可以在作用域为singleton的bean之间使用 当针对bean原型( 此外,作用域代理(scoped proxies)并不是以生命周期安全的方式从较短作用域访问bean的唯一方法。您还可以将注入点(即构造函数或setter参数或autowired字段)声明为 作为一个扩展变量,您可以声明 它的JSR-330变体称为Provider,它与 |
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:
以下示例中的配置仅为一行,但了解其背后的“为什么”和“如何”很重要:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- an HTTP Session-scoped bean exposed as a proxy -->
<bean id="userPreferences" class="com.something.UserPreferences" scope="session">
<!-- instructs the container to proxy the surrounding bean -->
<aop:scoped-proxy/> //1
</bean>
<!-- a singleton-scoped bean injected with a proxy to the above bean -->
<bean id="userService" class="com.something.SimpleUserService">
<!-- a reference to the proxied userPreferences bean -->
<property name="userPreferences" ref="userPreferences"/>
</bean>
</beans>
1
The line that defines the proxy.
1
定义代理的行。
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):
要创建这样一个代理,需要将一个<aop:scoped-proxy/>
子元素插入到具有作用域的bean定义(scoped bean definition)中(请参阅选择要创建的代理类型( Choosing the Type of Proxy to Create)和基于XML Schema的配置(XML Schema-based configuration))。为什么在请求、会话和自定义作用域级别(request
, session
and custom-scope level)定义的具有作用域的bean需要 <aop:scoped-proxy/>
元素?考虑下面的单例bean定义,并将它与前面所定义的作用域进行比较(注意,下面的userPreferences
bean定义不完整):
<bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>
<bean id="userManager" class="com.something.UserManager">
<property name="userPreferences" ref="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.
在前述示例中,向singleton bean(userManager)注入了具有HTTP会话作用域的bean(HTTP Session
-scoped 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(shorter-lived scoped bean)注入一个具有较长寿命的作用域bean(longer-lived scoped bean)(例如,将一个具有HTTP会话作用域(HTTP Session
-scoped)的协作bean作为依赖项注入到单例bean(singleton bean)中)时,这将不是您想要的行为。相反,您需要一个userManager对象,并且在HTTP会话的生命周期内,您需要一个特定于HTTP会话的UserPreferences
对象。因此,容器创建一个对象,该对象公开与UserPreferences
类完全相同的公共接口(理想情况下是一个UserPreferences
实例的对象),该对象可以从作用域机制(HTTP请求、会话等)获取真实的UserPreferences
对象。容器将这个代理对象注入userManager bean,而userManager bean不知道这个UserPreferences
引用是一个代理。在本例中,当UserManager实例调用通过依赖注入的UserPreferences
对象上的方法时,它实际上是在调用代理上的方法。然后代理从HTTP会话(在本例中)获取真实的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:
因此,在将具有请求和会话作用域的bean(request-
and session-scoped
bean)注入协作对象时,需要以下(正确且完整的)配置,如下例所示:
<bean id="userPreferences" class="com.something.UserPreferences" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.something.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>