[springMvc] 源码分析笔记(一)

时间:2022-03-02 16:47:09

1. Servlet 结构图

   [springMvc] 源码分析笔记(一)

2. servlet接口

public interface Servlet {
//init方法在容器启动时被容器调用(当load-on-startup设置为负数或者不设置时会在Servlet第一次用到时才被调用),只调用一次 void init(ServletConfig var1) throws ServletException;   // ServletConfig getServletConfig(); //service方法用于具体处理一个请求 void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;   //获取Servlet相关的信息,如作者、版权等,需要自己实现,默认返回空字符串 String getServletInfo();   //主要用于在Servlet销毁(一般指关闭服务器)时释放一些资源,也只会调用一次 void destroy(); }

     Init方法被调用时会接收到一个 ServletConfig类型的参数,是容器传进去的。 ServletConfig顾名思义指的是 Servlet的配置,我们在 web.xml中定义 Servlet时通过 init-param标签 配置的参数就是通过ServletConfig来保存的,比如,定义Spring MVC的Servlet时指定配置 文件位置的contextConfigLocation参数就保存在ServletConfig中,例如下面的配置: 

<servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                classpath:applicationContext.xml,classpath:webmvc-config.xml
            </param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>

 Tomcat 中 Servlet 的 init 方法是在 org.apache.catalina.core.StandardWrapper 的 initServlet 方法中调用的。

 2.1 ServletConfig 接口

public interface ServletConfig {
   //获取Servlet的名字,也就是我们在web.xml中定义的servlet-name String getServletName();    //ServletContext代表 的是我们这个应用本身 ServletContext getServletContext();    //用于获取init-param配置的参数 String getInitParameter(String var1);    //用于获取配置 的所有init-param的名字集合 Enumeration<String> getInitParameterNames(); }

2.2 GenericServlet

    GenericServlet是Servlet的默认实现,主要做了三件事:①实现了 SbrvletConfig接口,我 们可以直接调用ServletConfig里面的方法;②提供了无参的ink方法;③提供了 log方法。

2.3 HttpServlet

  HttpServlet是 用 HTTP 协议实现的 Servlet的基类,写 Servlet时直接继承它就可以了, 不需要时从头实现 Servlet接口,我们要分析的 Spring MVC中 的 DispatcherServlet就是继承 的 HttpServlet。既然 HttpServlet是跟协议相关的,当然主要关心的是如何处理请求 ,所 以 HttpServlet主要重写了 service方法。在 service方法中首先将 ServletRequest和 ServletResponse 转换为 HttpServletRequest 和 HttpServletResponse, 然后根据 Http 请求的类型不同 将请求路由到不同的处理方法。

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
//如果请求不符合规范直接抛出异常 if(req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
//转换类型 HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)res; this.service(request, response); } else { throw new ServletException("non-HTTP request or response"); } }

   不同的请求路由到不同的处理方法

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);
        }
    }
 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(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }