第3.4.4.5节 http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes-other-injectionspring 文档对此解释得很好:
(请注意,以下“userPreferences”bean 定义并不完整):
<!-- an HTTP Session-scoped bean -->
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
<!-- a singleton-scoped bean -->
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
从上面的配置可以明显看出,单例 bean“userManager”正在注入对 HTTP 会话范围 bean“userPreferences”的引用。这里的重点是'userManager' bean 是一个单例... 这将是每个容器只实例化一次, 及其依赖项(在本例中只有一个,“userPreferences”bean)也只会被注入(一次!).
这意味着“userManager”(概念上)将仅对完全相同的“userPreferences”对象进行操作,即最初注入的对象。
当您将 HTTP 会话范围的 bean 作为依赖项注入协作对象(通常)时,这不是您想要的。相当,我们真正想要的是每个容器有一个“userManager”对象, 进而,在 HTTP 会话的生命周期中,我们希望查看并使用特定于所述 HTTP 会话的“userPreferences”对象.
相反,您需要的是注入某种对象,该对象公开与 UserPreferences 类完全相同的公共接口(理想情况下是一个 UserPreferences 实例的对象),并且足够智能,能够获取真正的 UserPreferences 对象来自我们选择的任何底层作用域机制(HTTP 请求、会话等)。然后,我们可以安全地将这个代理对象注入到“userManager”bean 中,该 bean 会幸福地不知道它所持有的 UserPreferences 引用是一个proxy.
在我们的例子中,当 UserManager 实例调用依赖注入的 UserPreferences 对象上的方法时,它实际上会调用代理上的方法...然后代理将开始从(在本例中)HTTP 会话中获取真实的 UserPreferences 对象,并将方法调用委托给检索到的真实 UserPreferences 对象。
这就是为什么在将 request-、session-和 globalSession-scoped beans 注入协作对象时需要以下正确且完整的配置:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>