一尘不染

如何使用servlet?

java servlet

如何实例化servlet?如何使用session?如何共享变量?如何在多线程中使用?


阅读 545

收藏
2020-01-07

共1个答案

一尘不染

ServletContext

当servlet容器(如Apache Tomcat)启动时,它将部署并加载其所有Web应用程序。加载Web应用程序后,Servlet容器将创建ServletContext一次并将其保存在服务器的内存中。Web应用程序的web.xml所有包含的web-fragment.xml文件进行解析,每个<servlet><filter><listener>发现(或每一类注释用@WebServlet@WebFilter@WebListener分别)被实例化一次,并保存在服务器的内存。对于每个实例化的过滤器,其init()方法都通过new调用FilterConfig

当a Servlet的值大于<servlet><load-on-startup>或时,则在启动时还会使用new调用其方法。这些servlet以该值指定的相同顺序进行初始化(为1st,为2nd等)。如果多于一个的servlet指定了相同的值,则每个这些小服务程序的如它们出现在加载以相同的顺序,或类加载。如果没有“启动时加载”值,则当HTTP请求首次访问该servlet时,将调用该方法。@WebServlet(loadOnStartup)0init()ServletConfig12web.xmlweb-fragment.xml@WebServletinit()

当Servlet容器完成上述所有初始化步骤后,ServletContextListener#contextInitialized()将调用。

当servlet容器关闭时,它卸载所有Web应用程序,调用destroy()其全部初始化servlet和过滤器,所有的方法ServletContextServletFilterListener实例丢弃。最后,ServletContextListener#contextDestroyed()将被调用。

HttpServletRequest和HttpServletResponse

Servlet容器连接到Web服务器,该Web服务器在某个端口号上侦听HTTP请求(端口8080通常在开发过程中使用,而端口80在生产中使用)。当客户端(例如,使用Web浏览器或以编程方式使用的用户URLConnection)发送HTTP请求时,Servlet容器将创建new HttpServletRequestHttpServletResponse对象,并将它们通过Filter链中定义的任何对象(最终是Servlet实例)传递。

对于filter,将doFilter()调用该方法。当servlet容器的代码调用时chain.doFilter(request, response),请求和响应将继续到下一个过滤器,如果没有剩余的过滤器,则单击servlet。

对于servlet,将service()调用该方法。默认情况下,此方法根据确定doXxx()要调用的方法之一 request.getMethod()。如果servlet中没有确定的方法,则在响应中返回HTTP 405错误。

request对象提供对有关HTTP请求的所有信息的访问,例如URL,标头,查询字符串和正文。响应对象提供了以所需方式控制和发送HTTP响应的功能,例如,允许你设置标头和正文(通常使用从JSP文件生成的HTML内容)。提交并完成HTTP响应后,请求和响应对象都将被回收并可供重用。

HttpSession

当客户端首次访问该Web应用程序和/或通过首次访问该应用程序HttpSession时request.getSession(),servlet容器将创建一个新HttpSession对象,生成一个长而唯一的ID(你可以通过获取session.getId()),并将其存储在服务器的记忆。Servlet容器还在HTTP响应Cookie的Set-Cookie标头中设置a JSESSIONID作为其名称,并将唯一会话ID作为其值。

根据HTTP cookie规范(任何体面的Web浏览器和Web服务器都必须遵守的合同),Cookie只要cookie有效,客户端(Web浏览器)就需要在标头的后续请求中将该cookie发送回去(也就是说,唯一ID必须指向未过期的会话,并且域和路径正确)。使用浏览器的内置HTTP流量监控器,你可以验证Cookie是否有效(在Chrome / Firefox 23 + / IE9 +中按F12,然后检查“ 网络/网络”标签)。Servlet容器将检查Cookie每个传入HTTP请求的标头中是否存在具有该名称的cookie,JSESSIONID并使用其值(会话ID)HttpSession从服务器的内存中获取关联。

HttpSession活,直到它停留已经空闲(即,在请求未使用)超过规定的超时值<session-timeout>,在设定web.xml。超时值默认为30分钟。因此,当客户端访问Web应用程序的时间不超过指定的时间时,Servlet容器将破坏会话。每个后续请求,即使指定了cookie,也将无法再访问同一会话。servlet容器将创建一个新会话。

在客户端,只要浏览器实例正在运行,会话cookie就会保持活动状态。因此,如果客户端关闭浏览器实例(所有选项卡/窗口),则会话将被丢弃在客户端侧。在新的浏览器实例中,与会话关联的cookie将不存在,因此将不再发送。这将导致HttpSession创建一个全新的会话,并使用一个全新的会话cookie。

简而言之

  • ServletContext生活,只要Web应用程序的生命。它在所有会话的所有请求之间共享。
  • HttpSession生活,只要客户端与同一个浏览器实例中的Web应用程序进行交互,和会话未在服务器端超时。它在同一会话中的所有请求之间共享。
  • 在HttpServletRequest和HttpServletResponse现场从servlet接收来自客户端的HTTP请求的时间,直到完全缓解(网页)已经到来。它没有在其他地方共享。
  • 只要Web应用程序存在Servlet,所有Filter和Listener实例都会存在。它们在所有会话的所有请求之间共享。
  • 任何attribute被定义ServletContext,HttpServletRequest并且HttpSession只要将生活中的问题生活中的对象。对象本身代表了诸如JSF,CDI,Spring等之类的bean管理框架中的“作用域”。那些框架将其范围内的bean作为attribute其最接近的匹配范围存储。

线程安全

就是说,你最关心的可能是线程安全。现在,你应该知道所有请求都共享servlet和过滤器。这对Java来说是一件好事,它是多线程的,并且不同的线程(阅读:HTTP请求)可以使用同一实例。否则,重新创建init()以及destroy()针对每个单个请求的重新创建将过于昂贵。

你还应该意识到,永远不要将任何请求或会话范围的数据分配为Servlet或过滤器的实例变量。它将在其他会话中的所有其他请求之间共享。那不是线程安全的!下面的示例说明了这一点:

public class ExampleServlet extends HttpServlet {

    private Object thisIsNOTThreadSafe;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Object thisIsThreadSafe;

        thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests!
        thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe.
    } 
}
2020-01-08