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 ———-

转载于:https://www.cnblogs.com/Alandre/p/4779897.html

图解 深入浅出 JavaWeb:Servlet 再说几句相关推荐

  1. 图解 深入浅出JavaWeb:事务必会必知

    事务,大家所熟悉的事务(Transcation),基本上会就往Spring事务靠.其实Spring事务管理基于底层数据库本身的事务处理机制.数据库事务的基础,是掌握Spring事务管理的基础.这篇总结 ...

  2. Javaweb servlet体系结构与原理剖析

    Javaweb servlet体系结构与原理剖析 1.Servlet的工作过程 2.Servlet体系结构 3.Servlet工作原理 4.Servlet生命周期 1.Servlet的工作过程 当用户 ...

  3. Javaweb Servlet 下载文件

    JavaWeb Servlet 实现下载文件 Servlet类 import javax.servlet.ServletException; import javax.servlet.ServletO ...

  4. javaweb(servlet)+jsp+Mysql实现的简单相册管理系统(功能包含登录、管理首页、添加图片、分类管理、修改密码、图片详情等)

    博客目录 javaweb(servlet)+jsp+Mysql实现的简单相册管理系统 实现功能截图 系统功能 使用技术 代码 完整源码 javaweb(servlet)+jsp+Mysql实现的简单相 ...

  5. javaweb(servlet)+jsp+Mysql实现的酒店客房管理系统(功能包含登录、用户管理、住客信息管理、房型管理、房间管理、会员星级管理、订单管理等)

    博客目录 javaweb(servlet)+jsp+Mysql实现的酒店客房管理系统 实现功能截图 系统功能 使用技术 代码 完整源码 javaweb(servlet)+jsp+Mysql实现的酒店客 ...

  6. JavaWeb——Servlet(全网最详细教程包括Servlet源码分析)

    JavaWeb--Servlet Tomcat工作机制动画演示(点击动图可全屏观看) 什么是Servlet Servlet(Server Applet),全称Java Servlet,未有中文译文.是 ...

  7. JavaWeb Servlet 登录功能 注销功能

    JavaWeb Servlet 登录功能 注销功能 有三个逻辑: 处理登陆的逻辑,用户主页的逻辑,退出登录逻辑 登陆的逻辑LoginServlet.java import java.io.IOExce ...

  8. GET方式请求参数中文乱码问题 [JavaWeb][Servlet]

    请求参数中文乱码问题(GET) 同样的我们要解决GET方式下的请求参数中文乱码问题,那么我们首先要知道GET请求方式之下为什么中文数据就会出现乱码? 因为我们GET方式之下的请求参数是在请求行中,是紧 ...

  9. javaWeb——Servlet

    Servlet 系统架构 B/S结构的系统通信原理(没有涉及到Java小程序) 关于WEB服务器软件 实现一个最基本的web应用(这个web应用中没有java小程序) 对于一个动态的web应用来说,一 ...

最新文章

  1. 集体智慧及其常用算法
  2. 有符号整型的数据范围为什么负数比正数多一个?
  3. openfalcon 组件监控_运维监控系统之Open-Falcon
  4. 加速度随机游走_IMU Noise Model
  5. Linux CenOS7下安装RabbitMQ
  6. 杜克大学是原来英国Durham人去建立的 MIT和哈佛的是原来Cambridge的人去建立的
  7. 阿里云ECS Cloudbuild开发者大赛等你挑战!
  8. 将java 打包成exe 可执行文件
  9. entity framework5 sqlserver2005 事务(TransactionScope)报未启用MSDTC错误解决办法
  10. IE6PNG8PNG24test
  11. JavaWeb前台异常处理
  12. 5个不可多得的黑科技网站,让你在办公中如有神助,请低调收藏
  13. Acrel 2000E/G配电室综合监控系统
  14. 从行业到技术,10+年资深工程师带你进行嵌入式行业职业规划!
  15. python面向对象之面向对象三要素
  16. Shell脚本详解---一篇搞定
  17. OpenAnolis开源社区的萌芽与发展
  18. 【投资者日记(戴斌撰写)】【2017年9月13日(周三)】
  19. [产品设计]华为云的产品经理不是一般得弱
  20. 【论文笔记】Vision Transformer for Small-Size Datasets

热门文章

  1. 设计之路:如何进行软件需求分析?
  2. 新浪微博开发-添加子视图控制器设置颜色
  3. java.logging的重定向?
  4. Asp.Net基础 - 9.Web开发原则
  5. VS2005 VS2008新建网站和新建项目里选Web应用程序区别
  6. 重庆大学校友会计算机,资环学院联谊会隆重举行
  7. mysql 横向排列,mysql横向转纵向、纵向转横向排列的方法
  8. altera fpga 型号说明_A/X家FPGA架构及资源评估
  9. python我想对你说_python学习第3天-----字典、解构
  10. 宿迁学计算机的学校,宿迁计算机学校