spring

Java Servlet源码走读一:Servlet接口

2017-03-20  本文已影响0人  测试你个头

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

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

Servlet源码结构

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

源码目录结果
Servlet接口

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

Servlet接口注释

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中并没有实现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实现了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()?

上一篇下一篇

猜你喜欢

热点阅读