ServletContext
当 servlet 容器(如 Apache Tomcat)启动时,它将部署并加载其所有 Web 应用程序。加载 Web 应用程序时,Servlet 容器会创建一次 ServletContext,并将其保存在服务器的内存中。对 Web 应用程序和所有包含的文件进行解析,并且找到的每个 (或分别用 和 注释的每个类) 将被实例化一次,并保留在服务器的内存中,通过 .对于每个实例化筛选器,其方法都使用新的 FilterConfig 参数调用,该参数又包含所涉及的 。web.xmlweb-fragment.xml<servlet><filter><listener>@WebServlet@WebFilter@WebListenerServletContextinit()ServletContext
当 a 具有大于 或 的值时,则在启动期间也会使用新的 ServletConfig 参数调用其方法,该参数又包含所涉及的 。这些 servlet 按照该值指定的相同顺序进行初始化(即 1st、2nd 等)。如果为多个 servlet 指定了相同的值,那么每个 servlet 的装入顺序与它们在 、 或类装入中出现的顺序相同。如果“启动时加载”值不存在,则每当 HTTP 请求首次命中该 servlet 时,将调用该方法。Servlet<servlet><load-on-startup>@WebServlet(loadOnStartup)0init()ServletContext12web.xmlweb-fragment.xml@WebServletinit()
当 servlet 容器完成上述所有初始化步骤时,ServletContextListener#contextInitialized() 将使用一个参数调用,该参数又包含所涉及的 。这将允许开发人员有机会以编程方式注册另一个 或 。ServletContextEventServletContextServletFilterListener
当 servlet 容器关闭时,它会卸载所有 Web 应用程序,调用其所有初始化的 servlet 和过滤器的方法,并且所有 通过 注册的 实例都将被丢弃。最后,ServletContextListener#contextDestroyed() 将被调用,其本身将被丢弃。destroy()ServletFilterListenerServletContextServletContext
HttpServletRequest和HttpServletResponse
Servlet 容器附加到一个 Web 服务器,该服务器侦听某个端口号上的 HTTP 请求(端口 8080 通常在开发期间使用,端口 80 在生产中使用)。当客户端(例如,使用Web浏览器的用户,或以编程方式使用URLConnection)发送HTTP请求时,Servlet容器会创建新的HttpServletRequest和HttpServletResponse对象,并将它们传递到链中定义的任何对象,并最终传递实例。FilterServlet
对于筛选器,将调用该方法。当 servlet 容器的代码调用 时,请求和响应继续到下一个过滤器,或者如果没有剩余的过滤器,则命中 servlet。doFilter()chain.doFilter(request, response)
对于 servlet,将调用该方法。默认情况下,此方法根据 确定要调用的方法之一。如果 Servlet 中没有确定的方法,则在响应中返回 HTTP 405 错误。service()doXxx()request.getMethod()
请求对象提供对有关 HTTP 请求的所有信息的访问,例如其 URL、标头、查询字符串和正文。响应对象提供了以您想要的方式控制和发送HTTP响应的能力,例如,允许您设置标头和正文(通常使用从JSP文件生成的HTML内容)。提交并完成 HTTP 响应后,将回收请求和响应对象并使其可供重用。
HttpSession
当客户端第一次访问 webapp 和/或第一次通过 获得 HttpSession 时,servlet 容器会创建一个新对象,生成一个长而唯一的 ID(你可以通过它获得),并将其存储在服务器的内存中。Servlet 容器还在 HTTP 响应的标头中设置一个 Cookie,其名称为其名称,唯一会话 ID 作为其值。request.getSession()HttpSessionsession.getId()Set-CookieJSESSIONID
根据HTTP Cookie规范(任何体面的Web浏览器和Web服务器都必须遵守的合同),只要cookie有效,客户端(Web浏览器)就需要在标头中的后续请求中将此cookie发送回去(即唯一ID必须引用未过期的会话,并且域和路径是正确的)。使用浏览器的内置 HTTP 流量监视器,您可以验证 Cookie 是否有效(在 Chrome / Firefox 23+ / IE9+ 中按 F12,然后检查“网络/网络”选项卡)。Servlet 容器将检查每个传入 HTTP 请求的标头是否存在具有名称的 cookie,并使用其值(会话 ID)从服务器的内存中获取关联的 cookie。CookieCookieJSESSIONIDHttpSession
在空闲(即未在请求中使用)之前,将保持活动状态,其超时值超过 中指定的超时值。超时值默认为 30 分钟。因此,当客户端访问 Web 应用的时间不超过指定的时间时,servlet 容器将清除会话。每个后续请求,即使指定了cookie,也不再有权访问同一会话;servlet 容器将创建一个新会话。HttpSession<session-timeout>web.xml
在客户端,只要浏览器实例正在运行,会话 Cookie 就会保持活动状态。因此,如果客户端关闭浏览器实例(所有选项卡/窗口),则会话将在客户端被丢弃。在新的浏览器实例中,与会话关联的 Cookie 将不存在,因此将不再发送。这会导致创建一个全新的,使用一个全新的会话cookie。HttpSession
简而言之
- 只要 Web 应用程序存在,它们就会存在。它在所有会话中的所有请求之间共享。
ServletContext
- 只要客户端与具有相同浏览器实例的 Web 应用交互,并且会话在服务器端未超时,该会话就会存在。它在同一会话中的所有请求之间共享。
HttpSession
- 从 servlet 从客户端收到 HTTP 请求到完整的响应(网页)到达为止。它不会在其他地方共享。
HttpServletRequestHttpServletResponse
- 所有 和 实例的生存时间与 Web 应用程序一样长。它们在所有会话中的所有请求之间共享。
ServletFilterListener
- 任何在 中定义的,并且只要所讨论的对象存在,它就会存在。对象本身表示Bean管理框架(如JSF,CDI,Spring等)中的“范围”。这些框架将其作用域的Bean存储为其最接近的匹配作用域。
attributeServletContextHttpServletRequestHttpSessionattribute
螺纹安全
也就是说,您主要关心的可能是线程安全。您现在应该知道 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.
}
}
另请参阅: