`
lan_qie
  • 浏览: 12542 次
社区版块
存档分类
最新评论

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>();

	@Override
	public 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);
	}

	@Override
	public 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 {
	@Override
	public 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进行作用域管理了

分享到:
评论

相关推荐

    domino xapges 开发 RequestScope传递值

    今天,我们将深入探讨 RequestScope 的用途和实现细节,以及与其他作用域(ApplicationScope、SessionScope、ViewScope)的比较。 RequestScope 的工作机理是将变量保存在当前 HTTP 请求的生命周期内,这意味着变量...

    四个作用于区别

    pageScope、requestScope、sessionScope、applicationScope区别

    Spring中Scope为Request和Session的Bean了.docx

    这两个Bean都继承自`HelloMessageGenerator`类,并且分别使用了`@RequestScope`和`@SessionScope`注解来指定它们的作用域。 1. `@RequestScope`:这个注解表示Bean的生命周期与每个HTTP请求关联。每当一个新的HTTP...

    spring-web-2.5.jar

    org.springframework.web.context.request.RequestScope.class org.springframework.web.context.request.ServletRequestAttributes.class org.springframework.web.context.request.ServletWebRequest.class org....

    jsp的四个作用域

    本文将对jsp的四个作用域:pageScope、requestScope、sessionScope和applicationScope进行详细的解释和比较。 pageScope是jsp的最小作用域,仅在当前页面有效。在一个jsp页面里有效,变量可以在当前页面中使用,...

    EL(Expression Language)表达式

    - **与范围有关的隐含对象**:pageScope、requestScope、sessionScope和applicationScope对应JSP的pageContext、request、session和application对象,用于获取范围内的属性值。 - **与输入有关的隐含对象**:param...

    EL表达式

    4. **属性范围**:在EL中有四种默认的属性范围:PageScope、RequestScope、SessionScope和ApplicationScope,分别对应JSP中的pageContext、request、session和application对象。这些范围用于存储和检索数据。 **二...

    spring-security3 配置和使用

    USERNAME:${sessionScope['SPRING_SECURITY_LAST_USERNAME']}" /&gt; PASSWORD:&lt;input type="password" name="j_password" value="" /&gt;&lt;br/&gt; ``` 通过以上步骤,我们便可以成功地配置和使用 Spring Security...

    浅谈SpringMVC jsp前台获取参数的方式 EL表达式

    ${requestScope.msg} ${sessionScope.msg2} JAVA: ModelAndView ModelMap Model里添加的参数 JSP: 直接用${参数名} JAVA: 前台表单里的信息,或者是直接在url后面以?name=value&name2=value2形式传到后台的 JSP...

    EL(Expression Language)表达式(详解)

    EL 中的隐含对象有四个:pageScope、requestScope、sessionScope 和 applicationScope,它们基本上就和 JSP 的 pageContext、request、session 和 application 一样。在 EL 中,这四个隐含对象只能用来取得范围属性...

    el表达式教程,教你学会使用el表达式

    EL 中提供了四个与范围有关的隐含对象:pageScope、requestScope、sessionScope 和 applicationScope。这些对象可以用于取得范围属性值。 与输入有关的隐含对象 EL 中提供了两个与输入有关的隐含对象:param 和 ...

    总结EL和JSTL

    EL 访问作用域包括 pageScope、requestScope、sessionScope 和 applicationScope。pageScope 主要用于获取页面范围内的属性值,requestScope 主要用于获取请求范围内的属性值,sessionScope 主要用于获取会话范围内...

    jstl[教程](20211117174031).pdf

    EL允许开发者从各种作用域(如pageScope、requestScope、sessionScope和applicationScope)中轻松地获取和操作数据,而无需进行繁琐的类型转换。在JSTL 1.1及以后的版本中,EL成为JSP 2.0规范的一部分,可以在JSP...

    spring框架,技术详解及使用指导

    Spring框架的核心特性包括依赖注入(Dependency Injection, DI)、面向切面编程(Aspect-Oriented Programming, AOP)、数据访问/集成(Data Access / Integration)等,这些特性使得开发者能够更加高效地开发、测试...

    el表达式的应用和理解

    如果直接写`${hello}`,则EL会从最小的作用域开始查找,依次为`pageScope`、`requestScope`、`sessionScope`和`applicationScope`,直到找到对应的值为止。 #### 实例详解 接下来,我们将通过几个具体的示例来...

    SpringWebFlow学习笔记:全XML配置方式,纯流程跳转,不带有功能实现

    首先,我们需要理解Spring Web Flow的核心概念,包括`Flow`、`State`和`Transition`。`Flow`代表了一个完整的业务流程,比如购物车结账流程;`State`则是流程中的各个步骤,如选择商品、确认订单等;`Transition`则...

    EL表达式详解教程.

    这些范围对应于JSTL中的PageScope、RequestScope、SessionScope和ApplicationScope。可以显式指定范围,例如`${sessionScope.username}`。 EL的另一个重要特性是自动类型转换。在表达式`${param.count + 20}`中,...

    spring mvc+hibernate实现事务管理(配置文件版)

    同时,为了使Spring MVC能够与Hibernate一起工作,我们需要在实体类上添加@Entity注解,创建对应的表,并使用@SessionScope或@Service注解标记服务层的类,以便Spring管理。 在项目运行过程中,Test6可能是测试类...

    domino xapges 开发sessionScope

    domino xapges 开发sessionScope

Global site tag (gtag.js) - Google Analytics