图解 & 深入浅出 JavaWeb:Servlet 再说几句
Writer :BYSocket(泥沙砖瓦浆木匠)
微 博:BYSocket
豆 瓣:BYSocket
FaceBook:BYSocket
Twitter :BYSocket
上一篇的《 Servlet必会必知 》受到大家一致好评 — (感谢 读者 及 OSC 推荐 每日一’搏’)![]()
后来觉得还有些东西没点到,这边补充补充。
一、回到 HttpServlet 的 service方法
Servlet 基础接口定义了用于客户端请求处理的service方法。 当请求到达Servlet容器,由Servlet容器路由到一个Servlet实例。
比如说 javax.servlet.http.HttpServlet 类 ,其中有一个 protected void service 方法如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
private static final String METHOD_DELETE = "DELETE";private static final String METHOD_HEAD = "HEAD";private static final String METHOD_GET = "GET";private static final String METHOD_OPTIONS = "OPTIONS";private static final String METHOD_POST = "POST";private static final String METHOD_PUT = "PUT";private static final String METHOD_TRACE = "TRACE";private static final String HEADER_IFMODSINCE = "If-Modified-Since";private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";private static ResourceBundle lStrings = ResourceBundle.getBundle(LSTRING_FILE);/** * HTTP状态码304 */public static final int SC_NOT_MODIFIED = 304;/** * 接收来自 public service方法的标准HTTP请求, * 并将它们分发给此类中定义的doXXX方法。 */protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取请求方法名 String method = req.getMethod(); // 如果是GET请求 if (method.equals(METHOD_GET)) { // 上一次修改HttpServletRequest对象的时间 long lastModified = getLastModified(req); // 没有改变 if (lastModified == -1) { doGet(req, resp); } else { long ifModifiedSince; try { // 获取请求头中服务器修改时间 ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) { // 获取无效 ifModifiedSince = -1; } // 如果请求头服务器修改时间迟 if (ifModifiedSince < (lastModified / 1000 * 1000)) { // 设置修改HttpServletResponse对象的时间,重新设置浏览器的参数 //maybeSetLastModified(resp, lastModified); // 调用doGet方法 doGet(req, resp); } else { // 304 HTTP状态码 resp.setStatus(SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); //maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // 如果没有被请求到的话 String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); // 501 HTTP状态码 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); }} |
代码逻辑详解如下:
1、HttpServlet的 protected void service方法 用于接受 public service接收的标准HTTP请求。
也就是说,HttpServlet 重写了父类 GenericServlet 的 service方法。如图显示的是该方法,将从容器获取的 ServletRequest 和 ServletResponse 对象强制转化成 用于HTTP处理的HttpServletRequest 和 HttpServletResponse 对象。然后将两个对象路由给了 HttpServlet的 protected void service方法(图中代码选中处)
![]()
2、然后根据请求的方法名,分发到此类定义的doXXX方法。如果没有被请求到的话,则返回501 HTTP 状态码。
这样子仿佛明白了什么,也就是说,如果你在 HelloServlet中重写了doGet方法,这里分发到就是HttpServlet的子类HelloServlet的doGet方法。
哦~ 还有,501 HTTP 状态码 — 未实现(Not implemented)表示服务器不支持实现请求所需要的功能。例如,客户发出了一个服务器不支持的PUT请求。原来如此,所谓死记硬背这些HTTP 状态码有什么用?这样的记忆才是最有效的。
休息休息,小广告插一下 :(维持生计,O(∩_∩)O~)
涉及到的代码都会在开源项目 servlet-core-learning 。简介 — Servlet/JSP学习积累的例子,是Java EE初学者及Servlet/JSP核心技术巩固的最佳实践
大致就是这两步骤。这就是service的工作流程:
1、接受 public service接收的标准HTTP请求。
2、分发到定义的doXXX方法
二、GET 请求的处理详解
上面对于GET请求代码处理如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
// 如果是GET请求if (method.equals(METHOD_GET)) { // 上一次修改HttpServletRequest对象的时间 long lastModified = getLastModified(req); // 没有改变 if (lastModified == -1) { doGet(req, resp); } else { long ifModifiedSince; try { // 获取请求头中服务器修改时间 ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) { // 获取无效 ifModifiedSince = -1; } // 如果请求头服务器修改时间迟 if (ifModifiedSince < (lastModified / 1000 * 1000)) { // 设置修改HttpServletResponse对象的时间,重新设置浏览器的参数 //maybeSetLastModified(resp, lastModified); // 调用doGet方法 doGet(req, resp); } else { // 304 HTTP状态码 resp.setStatus(SC_NOT_MODIFIED); } }} |
这里,
1、定义了 getLastModified(req) 方法。用于获取上一次修改HttpServletRequest对象的时间。如果lastModified为默认的 –1L,则总是刷新。
这个getLastModified,是HttpServlet定义了用于支持有条件GET操作。即当客户端通过GET请求获取资源时,当资源自第一次获取那个实际点发生更改后才再次发生数据,否则将使用客户端缓存的数据。
在一些适当的场合,实现此方法可以更有效的利用网络资源,减少不必要的数据发送。
2、如果getLastModified方法的返回值是一个正数,那就要分以下两种情况考虑:
(1)如果请求头没有包含If-Modified-Since头字段(应该是第一次访问资源时候) 或者 其getLastModified返回值比If-Modified-Since头字段指定时间新,则调用doGet返回生成response 和 设置Last-Modified 消息头。
(2)如果其getLastModified返回值比If-Modified-Since头字段指定时间旧,则返回一个304状态给客户端,表示让客户端继续使用以前缓存的页面。
比如说 304 这个场景我在《 JavaEE 要懂的小事:一、图解Http协议 》文章中提到,第一次访问 百度 首页时,有些资源会成功获取 返回200。再次F5,有些资源或直接调用客户端的缓存数据,则返回304。
![]()
三、Servlet线程问题
Servlet容器可以并发路由多个请求到 Servlet 的 service方法。为了处理这些请求,Servlet必须在并发及线程安全问题做好处理。上一篇的《 Servlet必会必知 》提到定义全局变量会造成线程安全问题。在开发Servlet时,考虑线程安全问题提出了一下解决:
1、实现 SingleThreadModel 接口
Servlet2.4 已经提出不提倡使用。实现此接口,Servlet容器为每个新的请求创建一个单独的Servlet实例。这会有严重性能问题。
2、同步锁
使用synchronized关键字,虽然可以保证只有一个线程可以访问被保护区段,已达到保证线程安全。但是系统性能及并发量大大降低。不可取~
3、避免使用实例变量,即Servlet中全局变量。使用局部变量 (推荐)
方法中的局部变量分配在栈空间,每个线程有私有的栈空间。因此访问是线程安全的。
我想到了以下一个问题:
既然Sevlet的全局变量是线程不安全的,那SpringMVC Controller 也一样。那我们在Controller定义个 XXXService 变量会不会造成线程安全呢?
答:因为这是Spring的一个Service Bean,是线程安全的,所以可以作为单例使用,不会造成线程安全。
四、总结(别忘了点赞哦)
补充文章内容要点:
HttpServlet service 方法详解
深入理解 代码 对HTTP状态码的运用
Servlet的线程安全问题
欢迎点击我的博客及GitHub — 博客提供RSS订阅哦
———- http://www.bysocket.com/ ————- https://github.com/JeffLi1993 ———-
图解 & 深入浅出 JavaWeb:Servlet 再说几句的更多相关文章
- 图解 & 深入浅出 JavaWeb:Servlet必会必知
从[JavaEE 要懂的小事] Http相关,一直想写点Web开发相关的.最近项目接口开发紧,还有准备新的九月份战斗.JDK IO源码就隔一段落,温故知新看看Servlet & JSP 相关. ...
- 图解 & 深入浅出JavaWeb:事务必会必知
事务,大家所熟悉的事务(Transcation),基本上会就往Spring事务靠.其实Spring事务管理基于底层数据库本身的事务处理机制.数据库事务的基础,是掌握Spring事务管理的基础.这篇总结 ...
- JavaWeb—Servlet
1.什么是Servlet 用来扩展web服务器功能的组件——早期的web服务器只能处理静态资源的请求,即需要事先将html文件准备好,并存放到web服务器上面.不能够处理动态资源的请求(需要计算,动态 ...
- JavaWeb:Servlet技术
JavaWeb:Servlet技术 快速开始 Servlet是什么 Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 ...
- 深入浅出 JavaWeb:Servlet必会必知
一.Web服务器 从事web开发的人,会很清楚一个东西叫HTTP服务器,比如JEE开发—Tomcat,Jetty,.NET开发—ISS等.HTTP服务器是使用 HTTP(超文本传输协议) 与客户机浏览 ...
- JavaWeb——Servlet开发
什么是Servlet? Servlet运行的过程 Servlet的生命周期 生命周期的各个阶段 Servlet的配置 使用Web.xml配置 使用注解配置 Servlet相关接口 ServletCon ...
- JavaWeb——Servlet
一.基本概念 Servlet是运行在Web服务器上的小程序,通过http协议和客户端进行交互. 这里的客户端一般为浏览器,发送http请求(request)给服务器(如Tomcat).服务器接收到请求 ...
- [JavaWeb] Servlet Filter
作用: Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息. 可以将一个或多个 Servlet 过滤器附加到一个 Servlet 或一组 Servlet.Servle ...
- 【Java123】JavaWeb Servlet开发
http://www.runoob.com/servlet/servlet-intro.html https://www.cnblogs.com/xdp-gacl/tag/JavaWeb学习总结/de ...
随机推荐
- 在mac中自动保存git用户名与密码如此简单
之前为了实现在Windows中自动保存git用户名与密码,写过一篇博客终于解决“Git Windows客户端保存用户名与密码”的问题,需要进行一堆配置. 而在Mac OS X中这个操作竟然如此简单.只 ...
- windows server 2012 r2 iis8.5 部署asp.net mvc4/5程序小结
windows server 2012 r2 iis8.5 部署asp.net mvc4/5程序小结 原文链接:http://www.xuanhun521.com/Blog/66d491f8-b479 ...
- NABCD竞争性需求分析
1. Need 需求 市面上关于各类记事本,时钟显示程序,图片显示程序,日历程序有很多,但是它们大多是零散的软件,不利于现在高集成的时代,我们所做的就是将各种功能合起来. 2. Approach ...
- 【译】UNIVERSAL IMAGE LOADER. PART 3---ImageLoader详解
在之前的文章,我们重点讲了Android-Universal-Image-Loader的三个主要组件,现在我们终于可以开始使用它了. Android-Universal-Image-Loader有四个 ...
- PAAS平台的web应用性能测试与分析
引言 为什么我会写这一篇博客,因为最近很多京东云擎jae的用户反应一个问题就是他们部署在jae上面的应用访问很慢,有极少数应用甚至经常出现504超时现象,当然大家首先想到的是jae性能太差,这也是人之 ...
- iOS上应用如何兼容32位系统和64位系统
在苹果推出iPhone5S时,64位的应用就走到了眼前.当时就看见苹果官方资料宣布iOS7.x的SDK支持了64位的应用,而且内置的应用都已经是64位. 我记得自己刚刚接触电脑时还有16位的系统,指针 ...
- CSS入门级学习
css入门学习1:认识CSS 1.1:css简介,css全称是层叠样式表,Cascading style sheets 1.2:css的作用,主要是用于定义html内容在浏览器内的显示样式,如文字大小 ...
- Linux中如何产生core文件?
在程序不寻常退出时,内核会在当前工作目录下生成一个core文件(是一个内存映像,同时加上调试信息).使用gdb来查看core文件,可以指示出导致程序出错的代码所在文件和行数. 1.core文件 ...
- Libjingle库简介
原文链接 国内现在很多语音聊天工具都是基于TURN方式实现的,包括YY.AK等等,这种方式对于服务器的性能要求很高,而且在用户量增大的时候,服务器压力也会越来越大,用户的语音质量也会受到很大影响.而基 ...
- ios app 实现热更新(无需发新版本实现app添加新功能)
目前能够实现热更新的方法,总结起来有以下三种 1. 使用FaceBook 的开源框架 reactive native,使用js写原生的iOS应用 ios app可以在运行时从服务器拉取最新的js文件到 ...