问题:Servlets是如何工作的?Servlets如何实例化、共享变量、多线程?假设我有一个运行大量servlet的Web服务器。通过在Servlet之间传递信息获取Servlet上下文,并设置会话变量。现在,如果两个或多个消费者向该服务发送请求,会话变量接下来会发生什么?所有用户都使用公共变量吗?还是不同的用户使用不同的变量?如果是后者,服务器如何区分不同的用户?另一个类似的问题,如果有*n*个用户访问一个特定的servlet,这个servlet是只在第一个用户***访问它时实例化,还是为每个用户单独实例化?答案(BalusC):ServletContext在Servlet容器(如ApacheTomcat)启动时部署并加载所有Web应用程序。当加载Web应用程序时,Servlet容器将创建一个ServletContext,然后将其保存在服务器的内存中。解析web应用的web.xml,找到所有servlets、filters和Listeners或者@WebServlet、@WebFilter、@WebListener注解的内容,创建一次,保存在服务器的内存中。立即为所有过滤器调用init()。当Servlet容器停止时,所有的Web应用都会被卸载,所有初始化的Servlet和过滤器的destroy()方法都会被调用,最后回收ServletContext和所有的Servlet、Filter和Listener实例。当有问题的Servlet配置的load-on-startup或@WebServlet(loadOnStartup)设置为大于0的值时,init()方法也会在启动时立即被调用。“load-on-startup”中的值表示这些servlet将以相同顺序初始化。如果配置的值相同,则按照web.xml中指定的顺序或者@WebServlet类加载的顺序。此外,如果您不设置“启动时加载”值,则仅当第一个HTTP请求到达相关Servlet时才会调用init()方法。HttpServletRequest和HttpServletResponseServlet容器附加到一个Web服务,该服务在某个端口号上侦听HTTP请求,通常在开发环境中为8080,在生产环境中为80。当客户端(Web浏览器)发送HTTP请求时,Servlet容器会创建新的HttpServletRequest和HttpServletResponse对象,这些对象将传递给已创建且请求的URL与url-pattern匹配的Filter和Servlet实例中的方法,并且所有在同一线程中处理的工作。请求对象可以访问HTTP请求中的所有信息,如请求头和请求体。响应对象为您提供发送HTTP响应所需的控件和方法,例如设置标头和正文(通常带有JSP文件中的HTML内容)。在HTTP响应提交完成后,request和response对象被回收。HttpSession当用户第一次访问web应用时,会通过request.getSession()第一次获取到HttpSession。之后,Servlet容器会创建HttpSession,生成一个唯一的ID(可以通过session.getId()获取)并保存在服务器内存中。然后Servlet容器在HTTP响应的Set-Cookie头中设置一个Cookie,以JSESSIONID为Cookie名称,以唯一会话ID为Cookie值。根据HTTPcookie规则(普通网络浏览器和网络服务器必须遵循的标准),当cookie有效时,要求客户端(浏览器)在后续请求的Cookie头中返回这个cookie。使用浏览器内置的HTTP流量监视器,您可以查看它们(在Chrome、Firefox23+、IE9+中按F12,然后查看网络/网络选项卡)。servlet容器会判断每个传入的HTTP请求的Cookie头中是否有一个名为JSESSIONID的cookie,然后使用它的值(sessionID)从服务器内存中找到关联的HttpSession。您可以在web.xml中设置session-timeout,默认值为30分钟。HttpSession将保持活动状态,直到达到超时。所以当客户端超过30分钟没有访问web应用时,Servlet容器就会回收session。对于随后的每个请求,即使指定了cookie名称,也无法访问同一会话。servlet容器创建一个新的cookie。另一方面,客户端的会话cookie有一个默认的生存时间,只要浏览器实例在运行。因此,当客户端关闭浏览器实例(所有选项卡和窗口)时,会话将被客户端回收。新的浏览器实例不再发送与会话关联的cookie。新的request.getSession()将返回新的HttpSession并使用新的会话ID设置一个cookie。概述ServletContext与Web应用程序一样长。它由所有会话中的所有请求共享。只要客户端在同一浏览器实例中与Web应用程序交互而不会超时,HttpSession就会存在。HttpServletRequest和HttpServletResponse的生命周期是从客户端发送完成到完整响应(网页)到达的时间段。不会在别处分享。当Web应用程序运行时,所有Servlet、Filter和Listener对象都是活动的。它们由所有会话中的请求共享。只要相关对象存在,您在HttpServletRequest、HttpServletResponse和HttpSession中设置的所有属性都将持续存在。即便如此,线程安全可能是您最关心的问题。您现在应该了解所有请求共享servlet和过滤器。这是Java的一个优点,多个不同的线程(读取HTTP请求)可以使用同一个实例。否则,为每个请求重新创建线程的成本会高得令人望而却步。但是您还应该知道,您永远不应该将任何请求或会话字段数据分配给servlet或过滤器实例变量。它将被所有其他会话中的所有请求共享。That'snotthreadsafe!下面的示例对这种情况进行了展示:publicclassExampleServletextendsHttpServlet{privateObjectthisIsNOTThreadSafe;protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{ObjectthisIsThreadSafe;thisIsNOTThreadSafe=request.getParameter("foo");//BAD!!Sharedamongallrequests!thisIsThreadSafe=request.getParameter("foo");//OK,thisisthreadsafe。}}请参考:JSF、Servlet、JSP有什么区别?Java中管理Session的最佳选择,Servlet中的doGet和doPostServlet貌似可以同步处理多个并发请求
