request,session作用域注入singleton

本文详细阐述了在Spring IoC容器中,如何通过配置将不同作用域(如HTTPrequest、Session等)的bean注入到其他bean中,并使用代理对象确保在每个作用域生命周期内都能获取到正确的bean实例。重点解释了为何需要使用<aop:scoped-proxy/>元素,并提供了完整的配置示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

能够在HTTP request或者Session(甚至自定义)作用域中定义bean固然很好,但是Spring IoC容器除了管理对象(bean)的实例化,同时还负责协作者(或者叫依赖)的实例化。如果你打算将一个Http request范围的bean注入到另一个bean中,那么需要注入一个AOP代理来替代被注入的作用域bean。也就是说,你需要注入一个代理对象,该对象具有与被代理对象一样的公共接口,而容器则可以足够智能的从相关作用域中(比如一个HTTP request)获取到真实的目标对象,并把方法调用委派给实际的对象。
[Note] Note

<aop:scoped-proxy/> 不能和作用域为singleton或prototype的bean一起使用。为singleton bean创建一个scoped proxy将抛出BeanCreationException异常。

让我们看一下将相关作用域bean作为依赖的配置,配置并不复杂(只有一行),但是对理解“为何这么做”以及“如何做”是很重要的。

<?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 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

<!-- a HTTP Session-scoped bean exposed as a proxy -->
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">

<!-- this next element effects the proxying of the surrounding bean -->
<aop:scoped-proxy/>
</bean>

<!-- a singleton-scoped bean injected with a proxy to the above bean -->
<bean id="userService" class="com.foo.SimpleUserService">

<!-- a reference to the proxied
'userPreferences' bean -->
<property name="userPreferences" ref="userPreferences"/>

</bean>
</beans>

要创建这样的代理,只需要在Bean作用域定义中增加一个<aop:scoped-proxy/>子元素(为了让容器可以有效的使用基于类(而不是接口)的代理,你需要在classpath中加入CGLIB包, 并且要使用Appendix A, XML Schema-based configuration配置方式)。为什么在request,session, globalSession 和 '自定义作用域' 需要<aop:scoped-proxy/>元素?在下面配置片段中可以找到解释(注意下面 'userPreferences' Bean定义是不完整的):

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

<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>

从上述配置中可以很明显的看到singleton bean userManager被注入了一个指向HTTP Session作用域bean userPreferences的引用。singleton userManager bean会被容器仅实例化一次,并且其依赖(即userPreferences bean)也仅被注入一次。这意味着,userManager在理论上只会操作同一个userPreferences对象,即原先被注入的那个bean。而注入一个HTTP Session作用域的bean作为依赖,有违我们的初衷。因为我们想要的只是一个userManager对象,在它进入一个HTTP Session生命周期时,我们希望去使用一个HTTP Session的userPreferences对象。

当注入某种类型对象时,该对象实现了和UserPreferences类一样的公共接口(即UserPreferences实例)。并且不论我们底层选择了何种作用域机制(HTTP request、Session等等),容器都会足够智能的获取到真正的 UserPreferences对象,因此我们需要将该对象的代理注入到userManager bean中, 而userManager bean并不会意识到它所持有的是一个指向UserPreferences引用的代理。在本例中,当UserManager实例调用了一个使用UserPreferences对象的方法时,实际调用的是代理对象的方法。随后代理对象会从HTTP Session获取真正的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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值