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