ServletContext、ActionContext、ServletActionContext介绍

首先讲明ServletContext(application)、request、session为Servlet的三大域对象,ActionContext及ServletActionContext为Struts2的两个域对象。由于Struts2其实是servlet封装以后得到的结果,故在ActionContext及ServletActionContext域对象中仍包含有Servlet三个域对象的引用。

一 、ServletContext

两个问题:
1.大家在访问某个网站的时候,往往都会看到网站的首页面显示您是第几位浏览者(网站计数器),这是怎么实现的?
2.我们在访问某个bbs网站的时候,往往会显示有多少人在线,这是怎么实现的?

可能我们会想到的常规实现思路:数据库或者文件。这种做法比较简单,但是却会对数据库或者文件访问过于频繁,开销比较大。

解决之道是用ServletContext

1.什么是ServletContext

要理解ServletContext就必须和Cookie、Session做一个对比,如下图:
在这里插入图片描述
你可以把它想象成一个公用的空间,可以被所有的客户访问,也就是说A客户端可以访问D,B客户端可以访问D,C客户端也可以访问D。

  • WEB容器在启动时,它会为每个Web应用程序都创建一个对应的ServletContext,它代表当前Web应用。并且它被所有客户端共享。
  • ServletContext对象可以通过ServletConfig.getServletContext()方法获得对ServletContext对象的引用,也可以通过this.getServletContext()方法获得其对象的引用。
  • 由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。公共聊天室就会用到它。
  • 当web应用关闭、Tomcat关闭或者Web应用reload的时候,ServletContext对象会被销毁

2.怎么使用ServletContext

使用ServletContext:
(1) 如何得到ServletContext对象

this.getServletContext();
this.getServletConfig().getServletContext();

(2) 你可以把它想象成一张表,这个和Session非常相似:每一行就是一个属性,如下:

名字(String)值(Object)
  • 添加属性:setAttribute(String name, Object obj);
  • 得到值:getAttribute(String name),这个方法返回Object
  • 删除属性:removeAttribute(String name)

(3) 生命周期
ServletContext中的属性的生命周期从创建开始,到服务器关闭结束。

一个案例:
我们创建Servlet1和Servlet2,Servlet1用于在ServletContext中创建属性,Servlet2用于从ServletContext读取属性:
Servlet1的doGet方法为:

public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    response.setContentType("text/html;charset=utf-8");
    PrintWriter out = response.getWriter();
    // 获取ServletContext对象的引用
    // 第一种方法
    ServletContext servletContext = this.getServletContext();
    // 第二种方法
    // ServletContext servletContext2 = this.getServletConfig().getServletContext();
    servletContext.setAttribute("name", "小明");
    out.println("将 name=小明  写入了ServletContext");
}

Servlet2的doGet方法为:

public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    response.setContentType("text/html;charset=utf-8");
    PrintWriter out = response.getWriter();
    // 取出ServletContext的某个属性
    //1.首先获取到ServletContext
    ServletContext servletContext = this.getServletContext();
    //2.取出属性
    String name = (String)servletContext.getAttribute("name");
    out.println("name="+name);
}

以此访问Servlet1和Servlet2,我们可以分别看到输出如下:
在这里插入图片描述
在这里插入图片描述
运行结果似乎和Session,Cookie的应用没什么不同。其实看似相同,实则完全不一样。只要我们不关闭Tomcat或者reload该应用,这时候我们关闭当前的浏览器,或者是换一个浏览器,假设我们从Chrome换到IE再次访问Servlet2,依然可以看到结果!这就是它们最大的不同了,因为ServletContext是存在于服务器内存中的一个公共空间,它可以供所有的用户客户端访问。

参考:https://blog.csdn.net/gavin_john/article/details/51399425

二、ActionContext

1.ActionContext域对象

在Strust2中,有一个内置对象叫ActionContext,是Action执行时的上下文,上下文可以看作是一个容器(其实我们这里的容器就是一个Map而已),它存放的是Action在执行时需要用到的对象。通过该对象可以获得之前Servlet中的对象,比如:requst、response、ServletContext(struts2中为application对象)、session等对象…

Struts2本身在其中放入的数据有ActionInvocation、application(即ServletContext)、conversionErrors、Locale、action的name、request的参数、HTTP的Session以及值栈等。完整的列表请参考它的Javadoc。
在这里插入图片描述
上图就是简单理解为什么通过ActionContext可以获得request等对象,其实request和response还是Servlet中我们用的那个对象,只是在ActionContext中被引用了。

从图中也可以看出ActionContext其实就是一个Map集合。

由于requst的生命周期是一次请求,该请求结束后request就会结束,那么ActionContext中的requst自然也就没了,那么ActionContext的生命周期是如何呢?其实每次发出请求时都会创建一个ActionContext,也就是说,ActionContext的生命周期是和request相同的,证明很简单,既然ActionContext是一个Map集合,那么我们就可以自己向里面添加数据

ActionContext.getContext().put("test", "哈哈");

我们在一个请求中执行上面代码,就是向ActionContext这个Map集合中放一个数据,我们在另一个请求中是否能获得该数据?

ActionContext.getContext().get("test");

上面代码是从ActionContext这个Map集合中获得数据,在测试时获得的数据为null。从这也就可以看出,两次请求中是不同的ActionContext,可以下结论说ActionContext的生命周期是一次请求,也就是同request一样。

那么问题来了,我们都知道request这个对象内部就提供了一个域也是一个Map,那么既然ActionContext这个Map和request内部的Map生命周期一样,是不是就可以ActionContext代替request中的Map域呢?

其实在Strus2设计的时候,本意就是想用ActionContext来替换request 来存储数据,所以ActionContext的确可以代替request来存储数据,至于具体使用哪一个更好,其实没什么区别,看个人习惯和喜好吧,无论使用哪一个,要记得他们是两个不同的域,虽然生命周期一样,但是放在request中的数据,是不能从ActionContext这个Map中得到的,可以通过ActionContext先获得request对象再用request来获得数据。

2.从ActionContext中获得解耦域对象

我们知道request,session,application内部都封装了一个域对象,用来存储数据,request的域对象我们可以通过如下方式获得,那么session和application的域对象怎么获得呢,当然通过requst对象可以获得session对象也可以获得session的域对象,但这种方法就太麻烦了。其实可在ActionContext中获取request、session及application等域对象(注意此时获取的request及session都是map集合,非HttpRequest及HttpSession对象,但仍可从中取出请求参数及session数据,在ServletActionContext对象中可取到HttpRequest等封装好的对象):

Map request=(Map)ActionContext.getContext().get("request");	//得到request对象
Map<String,Object> session=ActionContext.getContext.getSession();	//得到session对象
Map<String, Object> application = ActionContext.getContext().getApplication();	//获得application对象

上面的代码就是获得session和application的域对象,可以看出返回值都是一个Map,这个Map就是它们的域对象,操作这个Map就是操作域对象,session.put(“key”,“value”);就是向session域中存数据session.get(“key”);就是从session域中取数据,但是却没有提供直接获得requst域对象的方法,在上面说过struts2想用ActionContext代替request的域对象,所以就没有提供获得request域对象的方法。其实也是在ActionContext这个Map中存放了session和application的Map的引用而已。
在这里插入图片描述
回到一开始说ActionContext的生命周期是和requst一样的,就是每次访问Action时都会创建一个新的ActionContext这个Map对象,也是因为它只是引用了其他对象,所以,ActionContext消失的时候其他的对象还是存在的。

那么当ActionContext创建的时候是怎么再次获得那些引用的呢,让我们想想我们在使用Servlet的时候我们是怎么获得的那些对象的呢,是通过request对象,只要request对象存在就可以获得那些对象的引用(request中包含session等信息),所以,ActionContext也是在它创建的时候使用每次的request对象来重新引用那些对象。

3.ValueStack与ActionContext的联系和区别:

相同点:它们都是在一次HTTP请求的范围内使用的,即它们的生命周期都是一次请求。

不同点:值栈是栈的结构,ActionContext是映射(Map)的结构。

联系:ValueStack.getContext()方法得到的Map其实就是ActionContext的Map。查看Struts2的源代码可知(Struts2.3.1.2的org.apache.struts2.dispatcher.ng.PrepareOperations的第79行,createActionContext方法),在创建ActionContext时,就是把ValueStack.getContext()作为ActionContext的构造函数的参数。所以,ValueStack和ActionContext本质上可以互相获得。

注意:在一些文档中,会出现把对象存入“stack‘s context”的字样,其实就是把值存入了ActionContext。所以在阅读这些文档时,要看清楚,到底是放入了栈结构(即值栈),还是映射结构(值栈的context,即ActionContext)。

参考:https://blog.csdn.net/qishubiao/article/details/78479865

三、ServletActionContext

1.ServletActionContext域对象

ServletActionContext,该类直接继承了ActionContext类,生命周期和ActionContext一样。可取得对象:

  1. javax.servlet.http.HttpServletRequest:HTTPservlet请求对象
  2. javax.servlet.http.HttpServletResponse:HTTPservlet响应对象
  3. javax.servlet.ServletContext:Servlet上下文信息
  4. javax.servlet.ServletConfig:Servlet配置对象
  5. javax.servlet.jsp.PageContext:Http页面上下文

从ServletActionContext里取得Servlet的相关对象

HttpServletRequest request = ServletActionContext. getRequest();	//取得HttpServletRequest对象
HttpSession session = ServletActionContext. getRequest().getSession();	//取得HttpSession对象

2.ServletActionContext和ActionContext联系

ServletActionContext和ActionContext有着一些重复的功能,该如何去抉择?

遵循的原则是:ActionContext能够实现我们的功能,最好就不要使用ServletActionContext,让Action尽量不要直接去访问Servlet的相关对象。

参考:https://www.cnblogs.com/keyi/p/6192669.html

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值