图解 & 深入浅出 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 ———-

时间: 2024-10-03 11:18:41

图解 & 深入浅出 JavaWeb:Servlet 再说几句的相关文章

图解 & 深入浅出 JavaWeb:Servlet必会必知

Writer      :BYSocket(泥沙砖瓦浆木匠) 微         博:BYSocket 豆         瓣:BYSocket FaceBook:BYSocket Twitter    :BYSocket "眨眼间,离上一篇写技术博文时隔1个月.怕自己真的生疏了,都是备案太慢惹得.哈哈,继续high~ " 从[JavaEE 要懂的小事] Http相关,一直想写点Web开发相关的.最近项目接口开发紧,还有准备新的九月份战斗.JDK IO源码就隔一段落,温故知新看看Ser

图解 &amp; 深入浅出JavaWeb:事务必会必知

图解 & 深入浅出JavaWeb:事务必会必知 转载自http://www.bysocket.com/ 事务,大家所熟悉的事务(Transaction),基本上会就往Spring事务靠.其实Spring事务管理基于底层数据库本身的事务处理机制.数据库事务的基础,是掌握Spring事务管理的基础.这篇总结下数据库事务. 一.数据库事务 它的思想:we are 伐木累.就是多个SQL语句(一个团队),要么所有执行success,不然就fail. 它最终的目标:数据不会被破坏.即事务操作成功,数据的结

图解 & 深入浅出Java初始化与清理:构造器必知必会

Writer      :BYSocket(泥沙砖瓦浆木匠) 微         博:BYSocket 豆         瓣:BYSocket FaceBook:BYSocket Twitter    :BYSocket 在面向对象编程中,编程人员应该在意"资源".比如 ? 1 <font color="#000000">String hello = "hello": </font> 在代码中,我们很在意在内存中Stri

深入浅出 JavaWeb:Servlet必会必知

一.Web服务器 从事web开发的人,会很清楚一个东西叫HTTP服务器,比如JEE开发—Tomcat,Jetty,.NET开发—ISS等.HTTP服务器是使用 HTTP(超文本传输协议) 与客户机浏览器进行信息交流.下面就是HTTP服务器简单交互图:(来自[JavaEE 要懂的小事] Http相关博客) HTTP服务器是Web服务器的一种,也是开发最常见的,自然还有其他方式进行信息交互,比如FTP文件服务器… Web服务器是可以向发出请求的浏览器提供文档的程序.其核心过程为 连接过程 — 请求过

JavaWeb——Servlet

一.基本概念 Servlet是运行在Web服务器上的小程序,通过http协议和客户端进行交互. 这里的客户端一般为浏览器,发送http请求(request)给服务器(如Tomcat).服务器接收到请求后选择相应的Servlet进行处理,并给出响应(response). 从这里可以看出Servlet并不是独立运行的程序,而是以服务器为宿主,由服务器进行调度的.通常我们把能够运行Servlet的服务器称作Servlet容器,如Tomcat. 这里Tomcat为什么能够根据客户端的请求去选择相应的Se

JavaWeb servlet过滤器

一.Filter简介: *************************************************************************************** Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件 或静态 html 文件等进行拦截,从而实现一些特殊的功能.例如实现URL级别的权限访问控制.过滤敏感词汇.压缩响应信

图解JSP与Servlet的关系

Servlet是Java提供的用于开发Web服务器应用程序的一个组件,运行在服务器端,由Servlet容器所管理,用于生成动态的内容.Servlet是平台独立的Java类,编写一个Servlet,实际上就是按照Servlet规范编写一个Java类. 如图所示,Java提供一系列接口类(所谓接口类就是类中所有方法只提供方法声明,不提供任何的方法实现,这些类的实现就留给后继者去做.):Servlet.ServletConfig.Serializable,然后通过多重继承产生一个最通用的Servlet

图解WildFly8之Servlet容器Undertow剖析

Undertow简介 Undertow 是RedHat(红帽公司)的开源产品,采用 Java 开发的灵活的高性能 Web 服务器,提供包括阻塞和基于 NIO 的非堵塞机制. WildFly8的默认Servlet容器采用的不是Tomcat,也不是Jetty,而是JBoss自己开源的Undertow,Undertow是用Java编写的性能灵活的Servlet容器,底层基于高性能的NIO框架XNIO,XNIO也是JBoss开源的产品,JBoss开源的高性能NIO框架还有一个很有名:Netty.Unde

石家庄铁道大学课程信息管理系统(javaWeb+servlet+Mysql)

实现网页版的课程管理系统,具有增删改查的功能. 1.首先连接数据库,具体数据库的使用及如何连接eclipse,参考     https://blog.csdn.net/lrici/article/details/54380872. 本项目连接数据库的代码如下: package com.hjf.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java