先了解一下request和session这两个作用域是干嘛的
以下是官方文档中文翻译:
请求作用域
考虑如下的bean定义:
<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>
对于每个http请求,Spring容器会创建一个 LoginAction
bean 的新实例。也就是说,loginAction
bean 的作用域限于 HTTP 请求范围。 你可以在请求内随意修改这个bean实例的状态,因为其他 loginAction
bean实例看不到这些变化,bean实例是与特定的请求相关的。 当请求处理完毕,对应的bean实例也就销毁(被回收)了。
会话作用域
考虑如下的bean定义:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
在每个HTTP Session
的生命周期内,Spring容器会根据id为 userPreferences
的bean定义创建一个 UserPreferences
bean 的新实例。 也就是说,userPreferences
bean 的作用域限于 HTTP Session
范围。和请求作用域 request-scoped
bean 类似, 因为每个会话域 session-scoped
bean的范围限于特定的 HTTP Session
内部,所以一个 Session
内的 userPreferences
bean也是可以被随意修改, 而不会影响到其他 Session
中的 userPreferences
bean。当一个HTTP Session
最终用完被JVM回收时,相关的会话域 session-scoped
bean也被一起回收。
上面都是spring官方文档讲的关于request和session的作用
这里就不讲使用request session这些作用域要在web.xml中做什么了,这些对于使用spring mvc的我来说没什么用。
下面讲讲当作用域设置为这两个时,注入到其他bean中怎么使用,以及为什么可以这样用。
怎么使用?
为什么加<aop:scoped-proxy/>标签就可以了呢?
将上述作用域的bean作为依赖
Spring IoC 容器不仅负责管理对象(beans)的创建,也负责有合作(依赖)关系对象之间的组装。 如果你想将一个HTTP 请求作用域的bean注入到另一个 bean,必须注入一个 AOP 代理来取代请求作用域的bean本身。 也就是说,你得有一个和作用域bean实现了相同接口、能在相应作用域(例如,HTTP 请求) 访问真正的请求域bean目标对象的代理对象,而且这个代理对象要能把方法调用委派给真正的请求域bean, 然后把代理对象注入到请求域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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 将一个HTTP Session bean 暴露为一个代理bean --> <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"> <!-- 通知Spring容器去代理这个bean --> <aop:scoped-proxy/> </bean> <!-- 将上述bean 的代理注入到一个单例bean --> <bean id="userService" class="com.foo.SimpleUserService"> <!-- 引用被代理的 userPreferences bean --> <property name="userPreferences" ref="userPreferences"/> </bean> </beans>
为了创建上文提到的代理对象,要在 request
请求、 session
会话、 globalSession
全局会话 和自定义作用域的bean声明中加入 <aop:scoped‐proxy/>
子元素。 (参考 the section called “选择要创建的代理类型” 和 Chapter 33, XML Schema-based configuration) 。为什么要这么做呢?让我们将这几个作用域的bean定义与单例作用域的bean定义做个对比。 (下列代码的 userPreferences
bean定义实际是 不完整的 )。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/> <bean id="userManager" class="com.foo.UserManager"> <property name="userPreferences" ref="userPreferences"/> </bean>
在上述例子中,将HTTP Session
会话域的 userPreferences
bean 注入进了单例域 userManager
。 代码的关键在于userManager 是个单例bean,它在每个Spring 容器中只会被初始化 一次, 它的依赖对象(在这个例子中是 userPreferences
bean)也只会被注入一次。这就意味着 userManager
每次操作的都是在最开始注入进来的同一个 userPreferences
对象。
当你把一个生命周期较短的bean注入至一个生命周期较长的bean时,例如把HTTP Session
bean注入到单例bean, 这种情况肯定 不是 你所期望的。相反,你希望有个唯一的 userManager
单例对象,在每个HTTP Session
的生命周期内, 都能有一个专门的 userPreferences
对象供 userManager
使用。因此,Spring容器会创建一个代理类, 使之与 UserPreferences
类实现相同的接口(理论上也是一个 UserPreferences
对象),并能根据作用域(HTTP 请求、 Session
,等等)去获得真正的 UserPreferences
对象。 Spring容器将这个代理类的对象注入到 userManager
, 但是 userManager
并不清楚它获得的 UserPreferences
其实是个代理。 在这个例子中,当UserManager 实例调用注入的 UserPreferences
对象的某个方法时,实际上调用的是代理对象的方法。 然后,代理对象从HTTP Session
中获取、并将方法调用委派给真正的 UserPreferences
对象。
所以,当你需要将 request-
, session-
, and globalSession-scoped
作用域的 bean 注入至其他合作者bean的时候,要按照下面的方法去正确地配置。
<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>
其实这个原理与使用@Autowired注入HttpServletRequest是差不多了,都是注入代理对象,具体请看我写的另一片文章:
http://blog.csdn.net/qq_36951116/article/details/79116829
写着篇文章是为了防止自己以后忘了,到时候又要到处百度。
如果有错误,请指正,非常感谢!