在HttpServletRequest、HttpSession、ServletContext中有三个相同的方法,都与属性有关:
- public Object getAttribute(String name);
- public void setAttribute(String name, Object o);
- public void removeAttribute(String name);
对这三者而言,实际上就是作用域不同的问题,范围从小到大分别是:Request < Session < ServletContext
请求属性
请求对象的生命周期较短,每个线程访问Web组件,都会创建一个新的请求,只有请求转发时才将请求转发到下一个资源。
所以请求属性不会长期驻留在容器内存中,也不会带来并发访问的问题,能够使用请求属性完成相关功能时,尽量使用请求属性。
会话属性
会话对象在一次会话过程中是一个唯一的对象,生命周期比请求要长。
建议在Web应用中,只有当某些对象必须在会话范围内共享,必须使用会话属性时,才考虑使用会话属性。
上下文属性
上下文对象随容器启动而创建,只有容器关闭时才销毁,所以生命周期长,而且一个应用只有一个上下文对象。
所以,不要轻易使用上下文属性,只有当确定某对象必须在上下文范围内共享时,才考虑使用。
上面的描述看不太明白?那么形象一点。
话说武松一日来到景阳岗,见一旗帜迎风飘扬,旗子上书五个大字“三碗不过岗”。 武松叫道:“店家,拿三碗酒来,再切两斤熟牛肉!”店小二应声道:“三碗好酒,二斤熟牛肉啰~~” 里面厨师赶忙当当当当切好牛肉,店小二倒上三碗酒,店小二端上前来。
武松咕咚咕咚连干三碗,叫一声“好酒!店家,再来三碗!” 小二忙又倒上三碗好酒, 武松一饮而尽。就这样前前后后武松一共喝了十八大腕。付了帐刚要走,店小二道: “客官,这前面山上有大虫,客官刚刚喝完十八碗酒恐怕过不得岗,不如在小店暂住一夜, 待明天和猎户一同过岗岂不是好?”
其实这里,转换成用户通过浏览器访问服务器的话,等同于:
武松 | 用户浏览器 |
酒馆 | 服务器 |
店小二、厨师 | Servlet |
“来三碗好酒!” | 浏览器向服务器发出HTTP请求 |
店小二上酒 | 服务器的响应 |
武松从进店到离开 | 一个HTTP对话 |
我们可以看到:
- Web交互的最基本单位为HTTP请求(武松点菜)
- 每个用户从进入网站到离开网站这段过程称为一个HTTP会话 (武松进店到出店)
- 一个HTTP请求的处理可能需要多个Servlet合作(武松点菜时店小二就要吩咐厨房做菜)
- 几个Servlet之间可以通过某种方式传递信息(店小二就用吆喝的方式通知厨房)
- 一个服务器的运行过程中会有多个用户访问, 就是多个HTTP会话(酒馆当然不可能只接待武松一个客人)
那么作用域就可以理解为:
- 请求:HTTP请求开始到结束这段时间
- 会话:HTTP会话开始到结束这段时间
- 上下文:服务器启动到停止这段时间
也正是有这种奇妙的关系,如果你只有request,想获取ServletContext,那么可以有:
request.getSession().getServletContext()
1
1
request.getSession().getServletContext()
实际上,这种方式也常在涉及文件存放时获取项目的物理路径,如:
String path = request.getSession().getServletContext().getRealPath("/WEB-INF/temp/image/") + fileName;
1
String path = request.getSession().getServletContext().getRealPath("/WEB-INF/temp/image/") + fileName;
写在后面的话,这里提到了request.getAttribute()方法,而request请求中还有一个getParameter()方法,两者还是稍有区别的:
- getParameter()是获取POST/GET传递的参数值,是String类型,它从客户端到服务器
- getAttribute()则是获取对象容器中的数据,是Object类型,只是在Web容器内部传递
- getParameter()中的参数,在请求转发不会丢失,仍可在新的Servlet中获取到,而重定向方式则会丢失