1.5.4.5. Scoped Beans as Dependencies (具有作用域的bean作为依赖项)

 Spring Framework Documentation (5.3.10)

Core

IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP.

   Core Technologies

1. The IoC Container

1.1. Introduction to the Spring IoC Container and Beans(Spring IoC容器和bean简介)

1.2. Container Overview (容器概览)

1.3. Bean Overview (Bean概览)

1.4. Dependencies(依赖)

1.5. Bean Scopes(Bean作用域)

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.2. Request scope(请求作用域)

1.5.4.3. Session Scope(会话作用域)

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. Custom Scopes (自定义作用域)

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 <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.

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.

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.

As an extended variant, you may declare ObjectProvider<MyTargetBean>, which delivers several additional access variants, including getIfAvailable and 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.

您还可以在作用域为singletonbean之间使用<aop:scoped-proxy/> ,并具有跨越可序列化的中间代理的引用,从而能够在反序列化时重新获取目标单例(singleton bean

当针对bean原型(prototype)作用域声明<aop:scoped-proxy/>时,共享代理(shared proxy)上的每个方法调用都会导致创建一个新的目标实例,然后将调用转发到该实例。

此外,作用域代理(scoped proxies)并不是以生命周期安全的方式从较短作用域访问bean的唯一方法。您还可以将注入点(即构造函数或setter参数或autowired字段)声明为ObjectFactory<MyTargetBean>,允许每次需要时调用getObject() 来按需检索当前实例,从而无需保留实例或单独存储它。

作为一个扩展变量,您可以声明 ObjectProvider<MyTargetBean>,它提供了几个额外的访问变量,包括getIfAvailablegetIfUnique

它的JSR-330变体称为Provider,它与Provider<MyTargetBean>声明以及每次检索尝试的相应get() 调用一起使用。更多有关JSR-330整体的详细信息,请参见此处(here)

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 requestsession 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))。为什么在请求、会话和自定义作用域级别(requestsession 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 beanuserManager)注入了具有HTTP会话作用域的beanHTTP 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.

当将一个具有较短寿命的作用域的beanshorter-lived scoped bean)注入一个具有较长寿命的作用域beanlonger-lived scoped bean)(例如,将一个具有HTTP会话作用域(HTTP Session-scoped)的协作bean作为依赖项注入到单例beansingleton 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:

因此,在将具有请求和会话作用域的beanrequest- 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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月满闲庭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值