HttpServlet中service方法的源码解读

前言

    最近在看《Head First Servlet & JSP》这本书, 对servlet有了更加深入的理解。今天就来写一篇博客,谈一谈Servlet中一个重要的方法——service方法


介绍

    当浏览器对servlet发起请求时,web容器会开启一个新的线程,或者是从线程池中分配一个线程,并调用servlet的service()方法,这个方法不需要程序员编写,而是继承自父类HttpServlet(当然,servlet不一定继承HttpServlet,也可以是实现其它协议的servlet类,但是大部分情况是Http协议);

    在service()方法中,会查看请求的类型(Get,Post......),根据请求的类型,调用servlet中对应的方法,如doGet()、doPost()......下面就来看看HttpServlet类中service()方法的源码。


源码

protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {	//若为Get请求
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.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 {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);

            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

源码解读

对于Get类型的请求

    在上面的源代码中,若请求是Get类型的,那service()方法首先调用了**getLastModified()**方法,获取了一个值赋给lastModified变量,这个东西是什么呢?     首先要知道一个东西,叫做**If-Modified-Since**(源码的注释中也有提到),这是Http请求的一个请求头标签,记录的是你现在请求的文件,在上一次你请求的时候,服务器上最后修改它的时间。所以,前提是你之前已经请求过这个文件,浏览器中存有这个页面的缓存,才有这个值。而源码中的**getLastModified()**方法,就是用来获取这个值的。     对于第一次请求的文件,浏览器请求中是没有**If-Modified-Since**的,所以在上面的源码中,若是第一次请求,**getLastModified()**返回的是-1,表示是第一次请求,则直接调用doGet方法,获取服务器中的文件,而这时在浏览器中,也获得了请求的文件在服务器中最后被修改的时间;     而对于不是第一次的请求,浏览器会将**If-Modified-Since**通过请求发送到服务器,service()方法调用**getLastModified()**方法获取到了发送来的这个值;然后它要判断一件事,那就是在你上次请求到这次请求之间,这个文件在服务器上是否被修改了,若被修改,则调用doGet(),重新获取一次,若没有被修改,则直接使用你浏览器中这个文件的缓存。     那service方法是怎么做到这个操作的呢。看上面的源代码,若**getLastModified()**方法获取到的值不是-1,则表示你之前请求过这个页面,并在浏览器中有缓存。然后,service()方法调用***req.getDateHeader(HEADER_IFMODSINCE)***,获取服务器上,你请求文件的最后修改时间,并与你传来的最后修改时间进行比较(两者都是long类型,表示时间的毫秒值),若**服务器上的最后修改时间 > 你传来的最后修改时间**,则表示在你上次请求之后,这个文件被修改过,所以不能直接使用缓存,于是service()方法调用doGet()方法重新获取此文件,而浏览器的缓存以及**If-Modified-Since**也将得到更新;若**服务器上的最后修改时间 == 你传来的最后修改时间**,表示这个文件没有被修改,service()方法调用***resp.setStatus()***方法 ,为响应设置状态码304(HttpServletResponse.SC_NOT_MODIFIED == 304),告诉浏览器可以直接使用缓存。

对于Post类型的请求

    对于Post类型的请求,service()方法都是直接调用doPost()方法,因为Post请求在标准中被规定用来对服务器中的内容进行修改,所以没有必要考虑缓存(个人理解)。当然,还有其它6种请求,但是基本上不用,我也不是很懂,这里就不说了。

源码下载地址

http://www.java2s.com/Code/JarDownload/javax.servlet/javax.servlet-api-3.0.1-sources.jar.zip


参考文献

https://www.cnblogs.com/moxiaotao/p/9670109.html

https://www.2cto.com/kf/201705/638441.html

《Head First Servlet & JSP》

posted @ 2019-10-09 22:34  特务依昂  阅读(758)  评论(0编辑  收藏  举报