HttpServlet类 (源码解析)

一、HttpServlet类

HttpServlet类是一个没有抽象方法的抽象类。

抽象类中可以没有抽象方法,但有抽象方法的一定是抽象类。但是抽象类是不能被实例化的,即使它没有抽象方法。

当一个类被声明为抽象方法有两个原因:

  1. 有抽象方法
  2. 没有抽象方法,但是不想此类被实例化

没有抽象方法的抽象类的价值在于:实例化了没有意义,因为类已经把方法都实现了,而且它不需要通过不同的对象来保存不同的状态。

这种场景更多的出现在各种工具类中,如果它的所有方法都是静态的,那么把它定义为抽象的,会从机制上防止实例化。

二、HttpServlet深度解析

1. HttpServlet没有抽象方法的抽象类

(1)如果将HttpServlet中的方法设置为抽象方法,那么我们就不得不去实现这些方法,但是很多时候大部分方法对我们来说是用不上的,因此我们可能需要实现很多无意义的方法,所以设置成抽象方法并不是一个优雅的做法。

(2)HttpServlet如果不设置为抽象类,那么我们就可以new出其实例,但是这个实例内部方法如doGet()、doPost()并没有任何实现(业务逻辑的代码只有自己知道怎么写),所以new出来的这个实例是没有意义的一个实例,它不能做任何事情,所以为了防止我们做这种没有意义的事情,将其设置为抽象类是优雅的做法。

三、HttpServlet的生命周期

1.客户端第一次请求一个 Servlet 时,web服务器(如 tomcat )根据 web.xml 的配置信息找到此 Servlet 的类,并创建该 Servlet 的对象,并根据配置信息创建 ServletConfig 对象,然后调用 Servlet 对象的 init(ServletConfig) 方法进行初始化。
2.服务器解析请求信息,创建 HttpServletRequest 对象,把请求信息封装到 HttpServletRequest 对象中,然后创建空的HttpServletResponse对象。
3.服务器调用 Servlet 对象的 service 方法,并把 HttpServletRequest 对象和 HttpServletResponse 对象传递给 service 方法的参数。
4.service方法根据请求方式(get/post)调用相应的方法(doGet/doPost)。
5.以后再收到此请求时直接调用 service方法处理请求。
6.当关闭服务器时从服务中取出 servlet,然后使用 destroy 方法销毁它,最后进行垃圾回收并终止它。

三、HttpServlet类的继承与实现

1. 继承GenericServlet类

HttpServlet类继承了GenericServlet类,实现了GenericServlet类的抽象方法service()。

2. 实现Serializable接口

Serializable是Java提供的序列化接口,是一个空接口,为对象提供标准的序列化与反序列化操作。使用Serializable实现序列化过程相当简单,只需要在类声明的时候指定一个标识,便可以自动的实现默认的序列化过程。

即定义程序序列化ID,序列化ID等同于身份验证,主要用于程序的版本控制,维护不同版本的兼容性以及避免在程序版本升级时程序报告的错误。

private static final long serialVersionUID = 1L;
3. 两个重载的service()方法
 public void service(ServletRequest req, ServletResponse res)	//public方法
 protected void service(HttpServletRequest req, HttpServletResponse resp)	//protected方法

首先简单了解一下ServletRequest和HttpServletRequest,

HttpServletReuqest不是相关请求的顶级接口,它继承自父接口——ServletRequest。
ServletRequest将客户端请求信息提供给某个 servlet 的对象;servlet 容器创建 ServletRequest 对象,并将该对象作为参数传递给该servlet的service方法 。

public void service(ServletRequest req, ServletResponse res) {
	request = (HttpServletRequest)req;
	response = (HttpServletResponse)res;
	this.service(request, response);
}

HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户请求信息。
HttpServlet类中对ServletRequest对象进行强制类型转换为HttpServletRequest,来调用 保护方法

protected void service(HttpServletRequest req, HttpServletResponse resp)	//protected方法

以对http类型的请求做更具体的service响应。

4. 派生类一般重写doGet或doPost方法,不重写service方法

(1)在默认情况下,无论是get请求还是post请求提交过来,都会经过service()方法的处理。然后由保护的service方法,根据请求类型调用 doGet或doPost方法。也就是说默认的情况下service方法的作用是转向,接着 doGet或doPost方法中进行逻辑的处理(这也就是为什么子类重写doGet或doPost方法。)

(2)如果我们自己在 HttpServlet 子类中覆写了 service 方法,那么这时 service方法就不是用来转向的,而是用来处理业务的,现在不论你的客户端是用 post 还是 get 来请求此 servlet,都会执行 service方法也只能执行service方法,不会去执行 doPost 或是 doGet方法。所以一般都是重写 doGet 或 doPost 方法,不会管service方法。

(3)拓展:为什子类不要重写service方法。还有另一方面的本质原因:service 方法自己实现了缓存协商的机制,如果我们重写它,反而将这中良好的机制给去掉了。

四、HttpServlet类源码

 
package javax.servlet.http;
 
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.ResourceBundle;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.NoBodyResponse;
 
public abstract class HttpServlet extends GenericServlet implements Serializable {
    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 HEADER_LASTMOD = "Last-Modified";
    private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
    private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
 
    public HttpServlet() {
    }
 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if(protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }
 
    }
 
    protected long getLastModified(HttpServletRequest req) {
        return -1L;
    }
 
    protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        NoBodyResponse response = new NoBodyResponse(resp);
        this.doGet(req, response);
        response.setContentLength();
    }
 
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if(protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }
 
    }
 
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_put_not_supported");
        if(protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }
 
    }
 
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_delete_not_supported");
        if(protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }
 
    }
 
    private Method[] getAllDeclaredMethods(Class c) {
        if(c.equals(HttpServlet.class)) {
            return null;
        } else {
            Method[] parentMethods = this.getAllDeclaredMethods(c.getSuperclass());
            Method[] thisMethods = c.getDeclaredMethods();
            if(parentMethods != null && parentMethods.length > 0) {
                Method[] allMethods = new Method[parentMethods.length + thisMethods.length];
                System.arraycopy(parentMethods, 0, allMethods, 0, parentMethods.length);
                System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, thisMethods.length);
                thisMethods = allMethods;
            }
 
            return thisMethods;
        }
    }
 
    protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Method[] methods = this.getAllDeclaredMethods(this.getClass());
        boolean ALLOW_GET = false;
        boolean ALLOW_HEAD = false;
        boolean ALLOW_POST = false;
        boolean ALLOW_PUT = false;
        boolean ALLOW_DELETE = false;
        boolean ALLOW_TRACE = true;
        boolean ALLOW_OPTIONS = true;
 
        for(int allow = 0; allow < methods.length; ++allow) {
            Method m = methods[allow];
            if(m.getName().equals("doGet")) {
                ALLOW_GET = true;
                ALLOW_HEAD = true;
            }
 
            if(m.getName().equals("doPost")) {
                ALLOW_POST = true;
            }
 
            if(m.getName().equals("doPut")) {
                ALLOW_PUT = true;
            }
 
            if(m.getName().equals("doDelete")) {
                ALLOW_DELETE = true;
            }
        }
 
        String var13 = null;
        if(ALLOW_GET && var13 == null) {
            var13 = "GET";
        }
 
        if(ALLOW_HEAD) {
            if(var13 == null) {
                var13 = "HEAD";
            } else {
                var13 = var13 + ", HEAD";
            }
        }
 
        if(ALLOW_POST) {
            if(var13 == null) {
                var13 = "POST";
            } else {
                var13 = var13 + ", POST";
            }
        }
 
        if(ALLOW_PUT) {
            if(var13 == null) {
                var13 = "PUT";
            } else {
                var13 = var13 + ", PUT";
            }
        }
 
        if(ALLOW_DELETE) {
            if(var13 == null) {
                var13 = "DELETE";
            } else {
                var13 = var13 + ", DELETE";
            }
        }
 
        if(ALLOW_TRACE) {
            if(var13 == null) {
                var13 = "TRACE";
            } else {
                var13 = var13 + ", TRACE";
            }
        }
 
        if(ALLOW_OPTIONS) {
            if(var13 == null) {
                var13 = "OPTIONS";
            } else {
                var13 = var13 + ", OPTIONS";
            }
        }
 
        resp.setHeader("Allow", var13);
    }
 
    protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String CRLF = "\r\n";
        String responseString = "TRACE " + req.getRequestURI() + " " + req.getProtocol();
 
        String out;
        for(Enumeration reqHeaderEnum = req.getHeaderNames(); reqHeaderEnum.hasMoreElements(); responseString = responseString + CRLF + out + ": " + req.getHeader(out)) {
            out = (String)reqHeaderEnum.nextElement();
        }
 
        responseString = responseString + CRLF;
        int responseLength = responseString.length();
        resp.setContentType("message/http");
        resp.setContentLength(responseLength);
        ServletOutputStream out1 = resp.getOutputStream();
        out1.print(responseString);
        out1.close();
    }
 
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long errMsg;
        if(method.equals("GET")) {
            errMsg = this.getLastModified(req);
            if(errMsg == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                if(ifModifiedSince < errMsg / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, errMsg);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if(method.equals("HEAD")) {
            errMsg = this.getLastModified(req);
            this.maybeSetLastModified(resp, errMsg);
            this.doHead(req, resp);
        } else if(method.equals("POST")) {
            this.doPost(req, resp);
        } else if(method.equals("PUT")) {
            this.doPut(req, resp);
        } else if(method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if(method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if(method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg1 = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg1 = MessageFormat.format(errMsg1, errArgs);
            resp.sendError(501, errMsg1);
        }
 
    }
 
    private void maybeSetLastModified(HttpServletResponse resp, long lastModified) {
        if(!resp.containsHeader("Last-Modified")) {
            if(lastModified >= 0L) {
                resp.setDateHeader("Last-Modified", lastModified);
            }
 
        }
    }
 
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException("non-HTTP request or response");
        }
 		
        this.service(request, response);
    }
}
  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Whitemeen太白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值