博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Servlets是怎么工作的?
阅读量:7243 次
发布时间:2019-06-29

本文共 9627 字,大约阅读时间需要 32 分钟。

  hot3.png

ServletContext

When the servletcontainer (like Apache Tomcat) starts up, it will deploy and load all webapplications. When a webapplication get loaded, the servletcontainer will create the ServletContext once and keep in server's memory. The webapp's web.xml will be parsed and every <servlet>, <filter> and <listener> found in web.xml, or annotated with respectively @WebServlet, @WebFilter and @WebListener, will be created once and kept in server's memory as well. For all filters, the init() method will also be invoked immediately. When the servletcontainer shuts down, it will unload all webapplications, invoke the destroy() of all initialized servlets and filters, and finally the ServletContext and all Servlet, Filter and Listener instances will be trashed.

servlet容器(如tomcat)启动时,会部署和加载所有的web应用。web应用加载完成,servlet容器将会创建一次ServletContext并保存在server的内存。web应用的web.xml被解析并且定义在这个xml中的所有的servlet,filter,listener被找到,且也会创建一次并将其保存在server的内存。对于所有的filter,init()方法被直接调用。当Servlet容器关闭时,会卸载所有的web应用,并调用所有初始化了得servlets和filters的destory()方法,最终ServletContext,Servlet,Filter ,Listener 将被销毁。

When the Servlet in question has a <servlet><load-on-startup> or @WebServlet(loadOnStartup) value greater than 0, then its init() method will also immediately be invoked during startup. Those servlets are initialized in the same order as "load-on-startup" value represents, or if they are the same, then the order in the web.xml or @WebServlet classloading. Or, if the "load-on-startup" value is absent, then the init() method will only be invoked on very first HTTP request hitting the servlet in question.

当Servlet配置了<servlet><load-on-startup> 或@WebServlet(loadOnStartup) 的值大于0,它的init()方法会在servlet容器启动时直接被调用。这些servlets的初始化顺序是根据load-on-startup的值来体现的(注:值小的在值大的之前初始化,值越小月先初始化),如果他们相同,则按在web.xml或 @WebServlet 中定义的顺序(越前的越先初始化)。还有,如果load-on-startup的值是缺失(注:何为缺失,就是没有填<load-on-startup></load-on-startup>或者没有定义该标签)的,那么init()将会在第一个命中该Servlet的Http请求时被调用。

HttpServletRequest and HttpServletResponse

The servletcontainer is attached to a webserver which listens on HTTP requests on a certain port number, which is usually 8080 in development and 80 in production. When a client (user with a webbrowser) sends a HTTP request, the servletcontainer will create new HttpServletRequest and HttpServletResponse objects and pass it through the methods of the already-created Filter and Servlet instances whose url-pattern matches the request URL, all in the same thread.

servletcontainer是附属于一个监听开发环境端口为8080、生产环境端口是80的Http请求的服务器。当一个客户端(通过浏览器访问的用户)发送一个请求到服务器,servletcontainer 会创建一个HttpServletRequest和HttpServletResponse 对象,并在同一线程中将他们传递到已经创建并且符合他们路径的的Filter 和Servlet。

In case of filters, the doFilter() method will be invoked. When its code calls chain.doFilter(request, response), then the request and response will continue to the next filter, or if there is none, hit the servlet. In case of servlets, the service() method will be invoked, which by default determines based on request.getMethod() which one of the doXxx() methods to invoke. If such method is absent on the actual servlet, then it will return HTTP 405 error.

在filters情况下,doFilter()方法被调用。如果它的代码是chain.doFilter(request, response),request和response 传递到下一个filter,如果没有了,这传递到servlet。在servlets情况下,service() 方法被调用,他将会根据request.getMethod()的值决定doXxx()被调用,如果这些方法在这个servlet不存在,他将会返回 HTTP 405 错误。

The request object provides access to all information of the HTTP request, such as the request headers and the request body. The response object provides facility to control and send the HTTP response the way you want, such as setting headers and the body (usually with HTML content from a JSP file). When the HTTP response is committed and finished, then both the request and response objects will be trashed (actually, most containers will cleanup the state and recycle the instance for reuse).

request 对象提供了访问http 请求所有信息(如,请求头 ,请求体.)的方法。response 对象提供根据你想要方式的灵活控制和发送http response,如设置响应头和响应体(通常是以js形式呈现Html内容)。当HTTP response提交和完成,request和response都将被销毁。

HttpSession

When a client visits the webapp for the first time and/or the HttpSession is to be obtained for the first time by request.getSession(), then the servletcontainer will create a new HttpSession object, generate a long and unique ID (which you can get by session.getId()), and store it in server's memory. The servletcontainer will also set a Cookie in the Set-Cookie header of the HTTP response with JSESSIONID as cookie name and the unique session ID as cookie value.

当一个客户端第一次访问web应用的或者HttpSession对象已经在第一次访问时通过request.getSession()获取了,servletcontainer 将会创建一个先得HttpSession对象,生成一个很长且唯一的ID(你可以通过session.getId())来获得),并且保存在服务器内存。servletcontainer也会通过在HTTP response的Set-Cookie header来设置一个cookie名为JSESSIONID,值为唯一的session id的cookie。

As per the HTTP cookie specification (a contract a decent webbrowser and webserver has to adhere), the client (the webbrowser) is required to send this cookie back in the subsequent requests in the Cookie header as long as the cookie is valid (i.e. is not expired and has the right domain and path). Using browser builtin HTTP traffic monitor you can check them (press F12 in Chrome / Firefox23+ / IE9+ and check Net/Network tab). The servletcontainer will determine the Cookie header of every incoming HTTP request for the presence of the cookie with the name JSESSIONID and use its value (the session ID) to get the associated HttpSession from server's memory.

根据HTTP cookie specification(一个正式的浏览器和web服务必须遵循的合同/协议),客户端在cookie是有效(如:未过期并且有正确的domain和path)时,必须要将该cookie设置到随后请求的Cookie header中发回给服务器,通过浏览器的内置的Http流量监控器你可以查看他们(按F12在Chrome / Firefox23+ / IE9+ ,选择Net/Network选项卡)。servletcontainer 将确定每一个进来的http请求是否存在Cookie 名是JSESSIONID的cookie,并根据该cookie的值从服务器的内存中取得关联的HttpSession。(注:如果是要实现Session共享,需要做什么?)

The HttpSession lives until it has not been used for more than the <session-timeout> time, a setting you can specify in web.xml, which defaults to 30 minutes. So when the client doesn't visit the webapp anymore for over 30 minutes, then the servletcontainer will trash the session. Every subsequent request, even though with the cookie specified, will not have access to the same session anymore. The servletcontainer will create a new one.

HttpSession存活到超出在web.xml中<session-timeout>设置的值没有使用为止,<session-timeout>默认值是30分钟。因此,客户端在超过三分钟没用访问web 应用,servletcontainer将会销毁这个session。每个后续的请求,即使是有指定的cookie,也不能再访问相同的session。servletcontainer 将会创建一个新的。

On the other hand, the session cookie on the client side has a default lifetime which is as long as the browser instance is running. So when the client closes the browser instance (all tabs/windows), then the session will be trashed at the client side. In a new browser instance the cookie associated with the session won't be sent anymore. A new request.getSession() would return a brand new HttpSession and set a cookie with a brand new session ID.

另一方后面,session cookie在客户端也有一个与浏览器进程运行( 浏览器进程关闭了运行就结束了)一样长的默认的生命时间。因此客户端关闭了浏览器进程(所有的标签和窗口),客户端的session也将被销毁。在一个新的浏览器进程中session关联的cookie也不再会被发送给到服务器。一个新的request.getSession()将会返回一个全新的HttpSession并且设置一个全新的session ID。

In a nutshell 简而言之

  • The ServletContext lives as long as the webapp lives. It's been shared among all requests in all sessions.
  • The HttpSession lives as long as the client is interacting with the webapp with the same browser instance and the session hasn't timed out at the server side yet. It's been shared among all requests in the same session.

  • The HttpServletRequest and HttpServletResponse lives as long as the client has sent it until the complete response (the webpage) is arrived. It is not being shared elsewhere.

  • Any Servlet, Filter and Listener lives as long as the webapp lives. They are being shared among all requests in all sessions.

  • Any attribute which you set in ServletContext, HttpServletRequest and HttpSession will live as long as the object in question lives. The object itself represents the "scope" in bean management frameworks such as JSF, CDI, Spring, etc. Those frameworks store their scoped beans as an attribute of closest matching scope.

  • ServletContext 生命周期是webapp的生命周期。他在所有回话的所有请求中共享。

  • HttpSession 生命周期是客户端与webapp 交互的浏览器进程存活时间并且服务端的session没有超时。他在同一个回话中的所有请求中共享。

  • HttpServletRequest和HttpServletResponse 生命周期是发送请求到完整的响应到达为止。他不共享。

  • 任何的Servlet,Filter,Listener 生命周期是webapp的生命周期。他在所有回话的所有请求中共享。

  • 任何设置在相应对象上的属性器生命周期是响应对象的生命周期。对象本身代表的生命周期也表示bean管理框架(如:JSF,CDI,Spring,等等)中的scope。这些框架通过接近范围的属性来保存他们bean的作用域。

Threadsafety 线程安全

That said, your major concern is possibly threadsafety. You should now have learnt that Servlets and filters are shared among all requests. That's the nice thing of Java, it's multithreaded and different threads (read: HTTP requests) can make use of the same instance. It would otherwise have been too expensive to recreate, init() and destroy() it on every single request.

考虑到线程安全。现在已经学习到Servlets和filters 所有请求共享的。这就是java的好处,他的多线程和不同线程能够不够使用相同的实例。否则每个请求上将会在重新创建,初始化和销毁花费巨大的时间。

But you should also realize that you should never assign any request or session scoped data as an instance variable of a servlet or filter. It will be shared among all other requests in other sessions. That's threadunsafe! The below example illustrates that:

但是你应该意识到绝不能将request和session范围的数据定义为servlet 或filter的实例变量。他将会被其他回话的其他请求共享。这就是线程安全!下面的例子阐述了他:

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.}

}

See also 参考

转载于:https://my.oschina.net/jast90/blog/780738

你可能感兴趣的文章
数据仓库中的 SQL 性能优化(MySQL篇)
查看>>
函数式 Python 中的 Pipe 与 itertools
查看>>
Latex希腊字母
查看>>
人工智能助力企业客户服务
查看>>
虚拟化技术介绍、Xen的简单实现
查看>>
数据库问题
查看>>
spring mvc文件上传方法
查看>>
RHEL5配置RHCS集群web (无共享存储)
查看>>
Elasticsearch简单使用系列--详细介绍ES的核心概念
查看>>
Django模型查询管理器笔记
查看>>
C# IPC管道通讯模块
查看>>
Java 异常处理的误区和经验总结
查看>>
读书笔记:关于 time_t
查看>>
解决在Android 4.0下无法搜到ubuntu建立的Ad-hoc热点
查看>>
Linux下Mysql数据库备份和恢复全攻略
查看>>
我的友情链接
查看>>
mvc控制器代码
查看>>
FreeSWITCH 与 Asterisk(译)
查看>>
JS判断字符串是否包含某字符串 indexOf()方法使用
查看>>
django 增加south apps
查看>>