当前位置: 首页 > article >正文

Spring RequestScope和SessionScope的来龙去脉

Spring在bean配置时可以配置scope(bean的作用域),主要用来控制bean的生命周期,在spring2.0之前bean只有2种作用域即:singleton(单例)、non-singleton(也称prototype), Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。所以,默认情况下Spring2.0现在有五种类型的Bean。
1、singleton
当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。
2、prototype
prototype作用域部署的bean,每一次请求(以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。也就是说spring只负责对prototype的bean产生,不负责销毁,这种bean的消息需要自己来处理
3、request
request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
4、session
session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效

5、global session
global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。

 

事实上,在Spring核心中只有singleton和prototype两种作用域,request、session、global session这3种scope都是基于prototype来实现的,对这3种方式产生的bean,spring的核心也是不负责销毁的,负责管理的是他们对应的Scope实现类,而且spring还允许自定义Scope。

 

request、session、global session使用的时候首先要在初始化web的web.xml中配置对应的listener或者 filter,listener:org.springframework.web.context.request.RequestContextListener(servlet2.4 以上)或者filter:org.springframework.web.filter.RequestContextFilter,这两个类的作用是一样的,就是从java的web Servlet机制中获取请求的HttpServletRequest和HttpSession对象

 

以request为例:

在RequestContextListener中获取到HttpServletRequest对象,以此来生成ServletRequestAttributes对象,然后把ServletRequestAttributes对象放入RequestContextHolder线程对象中,在调用BeanFactory.getBean()方法时Spring会调用RequestScope.get(String name, ObjectFactory objectFactory)方法,具体代码:

 

public Object get(String name, ObjectFactory objectFactory) {RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();Object scopedObject = attributes.getAttribute(name, getScope());if (scopedObject == null) {scopedObject = objectFactory.getObject();attributes.setAttribute(name, scopedObject, getScope());}return scopedObject;}
 ,从RequestContextHolder中获取ServletRequestAttributes对象,ServletRequestAttributes.getAttribute(String name, int scope)在request的Scope下就是从HttpServletRequest对象的attribute属性中取值,如果取不到再调用ObjectFactory以prototype方式重新生成一个并放入HttpServletRequest的attribute中,以便下次获取,放HttpServletRequest的bean随着请求的结束,生命周期也就结束了

 

 --------------------------------------------------------

 

自定义的Scope

Spring允许我们自定义Scope来管理bean,下面有一个简单例子,假设一个bean能被对个request线程复用,但是只能被使用5次(每个线程算一次)

 

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;public class MyScope implements Scope {private Map<String, ThreadsShareBean> map = new ConcurrentHashMap<String, ThreadsShareBean>();@Overridepublic Object get(String name, ObjectFactory objectFactory) {RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();Object scopedObject = attributes.getAttribute(name, RequestAttributes.SCOPE_REQUEST);if (scopedObject == null) {ThreadsShareBean threadsShareBean = this.map.get(name);if (threadsShareBean != null) {scopedObject = threadsShareBean.get();}if (scopedObject == null) {scopedObject = objectFactory.getObject();this.map.put(name, new ThreadsShareBean(scopedObject));}attributes.setAttribute(name, scopedObject, RequestAttributes.SCOPE_REQUEST);}return scopedObject;}public Object remove(String name) {RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();ThreadsShareBean threadsShareBean = this.map.remove(name);Object scopedObject = attributes.getAttribute(name, RequestAttributes.SCOPE_REQUEST);if (scopedObject != null) {attributes.removeAttribute(name, RequestAttributes.SCOPE_REQUEST);} else {scopedObject = threadsShareBean.obj;}return scopedObject;}public void registerDestructionCallback(String name, Runnable callback) {RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();attributes.registerDestructionCallback(name, callback, RequestAttributes.SCOPE_REQUEST);}@Overridepublic String getConversationId() {return null;}class ThreadsShareBean {private AtomicInteger atomicInteger = new AtomicInteger(1);private Object obj = null;public ThreadsShareBean(Object obj) {this.obj = obj;}public Object get() {if (atomicInteger.getAndIncrement() < 5) {return obj;}return null;}}
}
 首先要实现org.springframework.beans.factory.config.Scope接口,然后借用了RequestContextHolder的存放当前线程的bean

 

 

另外必须在bean初始化之前把MyScope注册到Spring ioc中,否则Spring启动的时候会报错,我是用BeanFactoryPostProcessor来实现的

 

public class RegisterMyScope implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {beanFactory.registerScope("myScope", new MyScope());}
}
 最要只要在spring配置文件中注册这个bean就可以了
<bean class="com.xxx.RegisterMyScope" />

 

<bean id="testBean" class="com.xxx.TestBean" scope="myScope"/>
这样就可以用myScope对bean进行作用域管理了

http://www.lryc.cn/news/2414152.html

相关文章:

  • 鼠标事件之外,认识一下指针事件家族?
  • Linux安装教程(超详细版)
  • Linux服务器安全配置加固防护方法_怎么做端口加固
  • U盘病毒专杀工具(usbcleaner)(绿色版)
  • 华为EC6108V9C/ E6108V9强刷固件及教程
  • C++ string的详细总结
  • 轻量级网络模型之MobileNet系列
  • kindeditor php 漏洞,Kindeditor特定情况可能会导致全盘浏览 - 网站安全
  • 堆栈的区别
  • 10种JavaScript特效实例
  • BuildaFlightTrackerwithCesiumforUnreal_译
  • SDF!这特效牛不牛?
  • dwmapi.dll文件丢失导致程序无法运行问题
  • 华三交换机基本配置命令
  • setAttribute、getAttribute、getParameter方法的用法 /// Session的getSession()方法的使用小结
  • 开源人脸识别项目 —— face_recognition
  • rx 文件管理器_免费开源资源管理器——RX 文件管理器
  • asp毕业设计——基于asp+access的教师信息管理系统设计与实现(毕业论文+程序源码)——教师信息管理系统
  • 通过JavaEye2.0网站看ruby on rails性能
  • QQ快速登录协议分析
  • 【RDMA】技术详解(一):RDMA概述
  • 面试专区|【60道计算机网络高频题整理(附答案背诵版)】
  • Codeigniter 框架开启PDO查询方式、多库连接实现、多语言网站开发配置、以及捕获页面最后报错
  • java语言技术_Java语言四大核心技术详解
  • WEB前端开发准备-Atom编辑器使用说明 Atom常用插件推荐 Atom快捷键
  • GUI Design Studio 4.5.151.0原型设计工具的使用
  • DOM4J 知识详解
  • 简单了解cms(内容管理系统)
  • [Visual Studio 2022 C#]设置splitContainer拆分器中间分隔条splitter的颜色和宽度
  • 【reverse】通俗易懂的gcc内联汇编入门+示例:实现花指令