Java Servlet源码走读一:Servlet接口

servlet:Server Applet 服务端应用程序,是java web开发的基础

首先需要理解web容器的概念:

  • web容器:web容器是一种服务程序,在服务器一个端口就有一个提供相应服务的程序,而这个程序就是处理从客户端发出的请求,比如tomcat、webSphere、weblogic
Servlet源码结构

Servlet的源码主要包括2个package:
1.在javax.servlet包中定义了所有的Servlet类都必须实现或扩展的的通用接口和类。
2.在javax.servlet.http包中定义了采用HTTP通信协议的HttpServlet类。

源码目录结果

Servlet接口

javax.servlet.Servlet是核心接口,见Servlet接口注释的第一句:定义了所有servlet都要实现的方法

Servlet接口注释

Servlet接口中定义的方法:


  • init:只会调用一次,在创建servlet时由web容器调用
  • getServletConfig:返回ServletConfig对象,包括servlet的初始化和启动参数信息
  • service:web容器调用service()来处理来自客户端的请求,service()会根据请求类型,在适当的时候调用doGetdoPost等方法
  • getServletInfo:见注释说明:返回作者、版本、版权等servlet信息
  • destroy:
    只会调用一次,在 Servlet 生命周期结束时被调用。destroy()可以让 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。在调用destroy()方法之后,servlet 对象被标记为垃圾回收
Servlet的生命周期

Servlet 通过调用 init ()方法进行初始化。
Servlet 调用 service()方法来处理客户端的请求。
Servlet 通过调用 destroy()方法终止(结束)。
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

ServletContext/ServletRequest/ServletResponse

3个接口,接口的主要注释分别如下

/**
 * Defines a set of methods that a servlet uses to communicate with its
 * servlet container, for example, to get the MIME type of a file, dispatch
 * requests, or write to a log file.
 */
public interface ServletContext {
}
/**
 * Defines an object to provide client request information to a servlet. The
 * servlet container creates a <code>ServletRequest</code> object and passes it
 * as an argument to the servlet's <code>service</code> method.
 */
public interface ServletRequest {
}
/**
 * Defines an object to assist a servlet in sending a response to the client.
 * The servlet container creates a <code>ServletResponse</code> object and
 * passes it as an argument to the servlet's <code>service</code> method.
 */
public interface ServletResponse {
}

从注释看:
1、ServletContext定义了用来和servlet容器通信的方法(获取servlet容器的一些信息)
2、ServletRequest由servlet容器创建,包含了客户端请求的信息
3、ServletResponse由servlet容器创建,帮助servlet向客户端发送应答信息

HttpServlet

先看类图:


  • GenericServlet:

GenericServlet中并没有实现destroy()service()2个接口,而是留给了具体应用的servlet实现类去扩展

GenericServlet中对于init的实现:

public void init(ServletConfig config) throws ServletException {
  this.config = config;
  this.init();
}

public void init() throws ServletException {

}

具体的servlet实现类只需要重写init()方法即可,而不需要重写init(ServletConfig)

以spring mvc为例,HttpServletBean重写了GenericServletinit()方法来实现自己独特的初始化逻辑

  • HttpServlet

HttpServlet实现了service()接口

    /**
     * Receives standard HTTP requests from the public
     * <code>service</code> method and dispatches
     * them to the <code>do</code><i>XXX</i> methods defined in 
     * this class. This method is an HTTP-specific version of the 
     * {@link javax.servlet.Servlet#service} method. There's no
     * need to override this method.
     *
     * @param req   the {@link HttpServletRequest} object that
     *                  contains the request the client made of
     *                  the servlet
     *
     * @param resp  the {@link HttpServletResponse} object that
     *                  contains the response the servlet returns
     *                  to the client                                
     *
     * @exception IOException   if an input or output error occurs
     *                              while the servlet is handling the
     *                              HTTP request
     *
     * @exception ServletException  if the HTTP request
     *                                  cannot be handled
     * 
     * @see javax.servlet.Servlet#service
     */
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();

        if (method.equals(METHOD_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);
        }
    }

从源码可以看到,HttpServletservice()方法中主要做的事情是根据request的method类型调用具体的doXXX()方法进行处理,起到的是一个根据method类型分发的作用

对于更下面一层的实现类,需要重写HttpServletdoXXX()方法来实现自己的特殊处理逻辑:
举例:spring mvc中FrameworkServlet重写了HttpServletdoXXX()方法来实现对Http请求的拦截

总结下:
1、Servlet的重点在于定义了init(ServletConfig),destroy(),service()这3个接口
2、GenericServlet重点在于对init(ServletConfig)接口的重写和提供了init()接口以供扩展
3、HttpServlet重点在于service()方法中的分发逻辑,以及定义了doGet/doPost等一系列接口以供扩展

具体的HttpServlet实现类通过重写上面的一系列接口实现自己的独特逻辑

遗留问题:
web容器是在什么时候,如何去调用servlet定义的生命周期方法init(),service(),destroy()?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容