Java Servlet 工作原理问答
导读
本文来自stackoverflow的问答,讨论了Java Servlet的工作机制,如何进行实例化、共享变量和多线程处理。
问题:Servlet是如何工作的?Servlet 如何实例化、共享变量、并进行多线程处理?
假设我有一个运行了大量 Servlet 的 web 服务器。通过 Servlet 之间传输信息得到 Servlet 上下文,并设置 session 变量。
现在,如果有两名或更多使用者向这个服务发送请求,接下来 session 变量会发生什么变化?究竟是所有用户都是用共同的变量?还是不同的用户使用的变量都不一样?如果是后者,服务器如何区分不同用户?
另一个相似的问题,如果有 *n* 名用户访问一个特定的 Servlet,那么该 Servlet 是仅在第一个用户首次访问的时候实例化,还是分别为每个用户实例化?
回答(BalusC):
ServletContext
当 Servlet 容器(比如 Apache Tomcat)启动后,会部署和加载所有 web 应用。当web 应用被加载,Servlet 容器会创建一次 ServletContext,然后将其保存在服务器的内存中。web 应用的 web.xml 被解析,找到其中所有 servlet、filter 和 Listener 或 @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 类加载的顺序。另外,如果不设置 “load-on-startup” 值,init() 方法只在第一次 HTTP 请求命中问题中的 Servlet 时才被调用。
HttpServletRequest 与 HttpServletResponse
Servlet 容器附加在一个 web 服务上,这个 web 服务会在某个端口号上监听 HTTP 请求,在开发环境中这个端口通常为 8080,生产环境中通常为 80。当客户端(web 浏览器)发送了一个 HTTP 请求,Servlet 容器会创建新的 HttpServletRequest 和 HttpServletResponse 对象,传递给已创建好并且请求的 URL 匹配 url-pattern 的 Filter 和 Servlet 实例中的方法,所有工作都在同一个线程中处理。
request 对象可以访问所有该 HTTP 请求中的信息,例如 request header 和 request body。response 对象为你提供需要的控制和发送 HTTP 响应方法,例如设置 header 和 body(通常会带有 JSP 文件中的 HTML 内容)。提交并完成HTTP 响应后,将回收 request 和 response 对象。
HttpSession
当用户第一次访问该 web 应用时,会通过 request.getSession() 第一次获得 HttpSession。之后 Servlet 容器将会创建 HttpSession,生成一个唯一的 ID(可以通过 session.getId() 获取)并储存在服务器内存中。然后 Servlet 容器在该次 HTTP 响应的 Set-Cookie 头部设置一个 Cookie,以 JSESSIONID 作为 Cookie 名字,那个唯一的 session ID 作为 Cookie 的值。
按照 HTTP cookie 规则(正常 web 浏览器和 web 服务端必须遵循的标准),当 cookie 有效时,要求客户端(浏览器)在后续请求的 Cookie 头中返回这个 cookie。使用浏览器内置的 HTTP 流量监控器,你可以查看它们(在 Chrome、Firefox23+、IE9+ 中按 F12,然后查看 Net/Network 标签)。Servlet 容器将会确定每个进入的 HTTP 请求的 Cookie 头中是否存在名为JSESSIONID 的 cookie,然后用它的值(session ID)从服务端内存中找到关联的 HttpSession。
你可以在 web.xml 中设置 session-timeout ,默认值为 30 分钟。超时到达之前 HttpSession 会一直存活。所以当客户端不再访问该 web 应用超过 30 分钟后,Servlet 容器就会回收这个 session。后续每个请求,即使指定 cookie 名称也不能再访问到相同的 session。Servlet 容器会创建一个新的 Cookie。
另一方面,客户端上的 session cookie 有一个默认存活时间,该事件和该浏览器实例运行时间一样长。所以,当客户端关闭该浏览器实例(所有标签和窗口)后,这个 session 就会被客户端回收。新浏览器实例不再发送与该 session 关联的 cookie。一个新的 request.getSession() 将会返回新的 HttpSession 并设置一个拥有新 session ID 的 cookie。
概述
ServletContext与 web 应用存活时间一样长。它被所有 session 中的所有请求共享。- 只要客户端一直与相同浏览器实例的web应用交互并且没有超时,HttpSession就会存在。
HttpServletRequest和HttpServletResponse的存活时间为客户端发送完成到完整的响应(web 页面)到达的这段时间。不会被其他地方共享。所有 Servlet、Filter和Listener对象在 web 应用运行时都是活跃的。它们被所有 session 中的请求共享。- 你设置在
HttpServletRequest、HttpServletResponse和HttpSession中的所有属性在问题中的对象存活时都会一直保持存活。
线程安全
即便如此,你最关心的可能是线程安全。你现在应该学习到 Servlet 和 filter 被所有请求共享。那是 Java 的一个优点,使得多个不同线程(读取 HTTP 请求)可以使用同一个实例。否则为每个请求重新创建线程的开销实在过于昂贵。
但你应该也意识到永远不要将任何 request 或 session 域中的数据赋值给 servlet 或 filter 的实例变量。它将会被所有其他 session 中的所有请求共享。那是非线程安全的!下面的示例对这种情况进行了展示:
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.
}
}
请参考:
Java Servlet 工作原理问答的更多相关文章
- 【译】Stackoverflow:Java Servlet 工作原理问答
导读 本文来自stackoverflow的问答,讨论了Java Servlet的工作机制,如何进行实例化.共享变量和多线程处理. 问题:Servlet 是如何工作的?Servlet 如何实例化.共享变 ...
- [Java] Servlet工作原理之一:体系结构及其容器
一.Servlet体系结构 在 servlet-api.jar (2.5) 中有两个包:javax.servlet 和 javax.servlet.http 1 Servlet ...
- [Java] Servlet工作原理之二:Session与Cookie
(未完成) 一.Cookie与Session的使用简介 1 Cookie Cookie 用于记录用户在一段时间内的行为,它有两个版本:Version 0 和 Version 1,分别对应两种响应头 S ...
- HTTP协议 Servlet入门 Servlet工作原理和生命周期 Servlet细节 ServletConfig对象
1 HTTP协议特点 1)客户端->服务端(请求request)有三部份 a)请求行--请求行用于描述客户端的请求方式.请求的资源名称,以及使用的HTTP协议版本号 请求行中的GET ...
- Servlet工作原理
Servlet生命周期分为三个阶段: 1,初始化阶段 调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在 ...
- Servlet工作原理分析
最近在看<Java Web技术内幕>的Servlet工作原理,有点深奥和难以理解,于是乎,想通过一个简单的Demo将书上的思路理一遍,对Servlet有个更透彻更深的了解. Servlet ...
- [Java] SpringMVC工作原理之一:DispatcherServlet
一.DispatcherServlet 处理流程 在整个 Spring MVC 框架中,DispatcherServlet 处于核心位置,它负责协调和组织不同组件完成请求处理并返回响应工作.在看 Di ...
- Unit02: Servlet工作原理
Unit02: Servlet工作原理 点击注册按钮,返回注册信息 package web; import java.io.IOException; import java.io.PrintWrite ...
- JSP+JavaBean+Servlet工作原理实例…
JSP+JavaBean+Servlet工作原理实例讲解 首先,JavaBean和Servlet虽都是Java程序,但是是完全不同的两个概念.引用mz3226960提出的MVC的概念,即M-model ...
随机推荐
- sql server 数据库正在使用该文件的解决办法
今天在帮朋友还原数据库时遇到了一个问题.朋友用的是sql server 2008数据库,本身有一个数据库,他在修改程序的时候,想修改数据库的内容.但是又不想在原数据库中修改.想备份还原出一个数据库然后 ...
- ASP.net+MVC--2
1.ASP.NET MVC控制器 1)在Controllers文件夹下新建控制类 public class HelloWorld2Controller : Controller { public st ...
- github配置和git学习
参考:http://www.eoeandroid.com/thread-272837-1-1.html http://blog.csdn.net/hcbbt/article/details/11651 ...
- 国内各大互联网公司UED(用户体验设计)团队博客介绍
UED是什么UED = user experience design,用户体验设计.UED的通常理解,就是“我们做的一切都是为了呈现在您眼前的页面”.UED团队包括:交互设计师(Interactio ...
- 定时工作方式2实现1s定时
定时器的几种工作方式中,除0和前面的1类似都需要初始化计数值,然后开始计数,计数溢出后,需要再次控制计数的初值,但工作模式2不同于此,工作方式2将THx和TLx分开处理,将初值存放在THx中,计数时只 ...
- Polygon Table - Google Chrome
Polygon table by Pedro Amaro Santos Lisboa, Portugal posted at http://forums.cgsociety.org/showthrea ...
- css 浮动 相对定位 绝对定位区别
今天下班在地铁上看了一个样式教学视频,因为最近在学习前端.以前刚毕业的时候,感觉后台才是王道,但最近发现,前端也很重要,比如:自己接一些私单做的时候,自己要根据需求做好界面,才能更加符合客户需求,不然 ...
- su: Bad item passed to pam_*_item()
su: Bad item passed to pam_*_item() 查看 /etc/default/locale 该文件应该只含义如下格式的文字: LANG=en_US.UTF-8 如何还没有解决 ...
- 加密算法 - RSA
与DES不同,RSA算法中,每个通信主体都有两个钥匙,一个公钥一个私钥. 就是有2把钥匙1.使用publicKey可以对数据进行加密2.使用Key才能对数据进行解密单方向传输用公钥加密的数据,只有私钥 ...
- 【MS Office2013小技巧】Word中公式中的等号对齐
步骤: 1. 先将所需要对齐的公式分不同行打出来: 2. 选中所有公式,右键点击并选择“对齐点(A) =”,如图 此时,如果能够正常对齐,则无需进行下面的步骤,但如果出现下图情况并未正常对齐的,再进行 ...