ServletContext
当 servlet 容器(如Apache Tomcat)启动时,它将部署并加载其所有 Web 应用程序。加载 Web 应用程序时,servlet 容器会创建ServletContext
一次并将其保存在服务器的内存中。Web 应用程序web.xml
和所有包含的web-fragment.xml
文件都被解析,并且每个<servlet>
,<filter>
和找到的(或每个分别用,和<listener>
注释的类)将被实例化一次并保存在服务器的内存中,通过. 对于每个实例化的过滤器,它的方法被一个新参数调用,该参数又包含所涉及的.@WebServlet
@WebFilter
@WebListener
ServletContext
init()
FilterConfig
ServletContext
当 a 的Servlet
a<servlet><load-on-startup>
或@WebServlet(loadOnStartup)
值大于0
时,它的init()
方法也会在启动期间使用一个新ServletConfig
参数调用,该参数又包含所涉及的ServletContext
。这些 servlet 以该值指定的相同顺序进行初始化(1
第 1 次、2
第 2 次等)。如果为多个 servlet 指定了相同的值,则这些 servlet 中的每一个都按照它们在 、 或 类加载中出现的web.xml
顺序web-fragment.xml
加载@WebServlet
。如果“load-on-startup”值不存在,则只要HTTP 请求第一次命中该 servlet,init()
就会调用该方法。
当 servlet 容器完成上述所有初始化步骤后,ServletContextListener#contextInitialized()
将使用一个ServletContextEvent
参数调用 ,而该参数又包含所涉及的ServletContext
. 这将使开发人员有机会以编程方式注册另一个Servlet
,Filter
或Listener
.
当 servlet 容器关闭时,它会卸载所有 Web 应用程序,调用其destroy()
所有已初始化的 servlet 和过滤器的方法,并且通过 注册的所有Servlet
,Filter
和Listener
实例ServletContext
都被丢弃。最后ServletContextListener#contextDestroyed()
将被调用,并且ServletContext
本身将被丢弃。
HttpServletRequest
和HttpServletResponse
servlet 容器连接到一个 Web 服务器,该服务器在某个端口号上侦听 HTTP 请求(端口 8080 通常在开发期间使用,而在生产中使用端口 80)。当客户端(例如,使用 Web 浏览器的用户,或以编程方式使用URLConnection
)发送 HTTP 请求时,servlet 容器会创建新对象HttpServletRequest
和HttpServletResponse
对象,并将它们传递给Filter
链中定义的任何对象,最终传递给Servlet
实例。
在过滤器的情况下,该doFilter()
方法被调用。当 servlet 容器的代码调用chain.doFilter(request, response)
时,请求和响应继续到下一个过滤器,如果没有剩余的过滤器,则点击 servlet。
在servletservice()
的情况下,将调用该方法。默认情况下,此方法doXxx()
根据 request.getMethod()
. 如果确定的方法在 servlet 中不存在,则在响应中返回 HTTP 405 错误。
请求对象提供对有关 HTTP 请求的所有信息的访问,例如其URL、标头、查询字符串和正文。响应对象提供了以您想要的方式控制和发送 HTTP 响应的能力,例如,允许您设置标头和正文(通常使用从 JSP 文件生成的 HTML 内容)。当 HTTP 响应提交并完成时,请求和响应对象都会被回收并可供重用。
HttpSession
当客户端第一次访问 webapp 和/或第一次HttpSession
通过记忆。servlet 容器还在HTTP 响应的标头中设置 a作为其名称,并将唯一会话 ID 作为其值。request.getSession()
HttpSession
session.getId()
Cookie
Set-Cookie
JSESSIONID
根据HTTP cookie 规范(任何体面的 Web 浏览器和 Web 服务器必须遵守的合同),只要 cookie 有效,客户端(Web 浏览器)就需要在后续请求中将这个cookieCookie
发送回标头中(即唯一 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,并使用一个全新的会话 cookie。
简而言之
ServletContext
只要网络应用程序存在,它就会存在。它在所有会话中的所有请求之间共享。
HttpSession
只要客户端使用相同的浏览器实例与 Web 应用程序交互,并且会话在服务器端没有超时,它们就会一直存在。它在同一会话中的所有请求之间共享。
- 并且从 servlet 接收
HttpServletRequest
到HttpServletResponse
来自客户端的 HTTP 请求开始,直到完整的响应(网页)到达。它不在其他地方共享。
- 只要 Web 应用程序存在,所有
Servlet
,Filter
和实例就会存在。Listener
它们在所有会话中的所有请求之间共享。
- 任何
attribute
在 中定义的ServletContext
,HttpServletRequest
并且HttpSession
只要有问题的对象存在,就会存在。对象本身代表 bean 管理框架(如 JSF、CDI、Spring 等)中的“范围”。这些框架将其作用域 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.
}
}
也可以看看: