专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

SpringMVC源码分析一、Servlet体系结构分析

引入

Servlet是一个JavaWeb规范, 对应了Java中的Servlet接口, 回想很早之前直接利用Servlet开发的时候, 我们需要
继承Servlet接口,重写其service方法, 然后在web.xml中配置该servlet与域名的映射关系, 当利用Tomcat来启动的
时候, 请求到来时自动会映射到对应的Servlet中, 调用我们重写的service方法执行请求, Java中Servlet的主要继
承关系是HttpServlet->GenericServlet->Servlet, 接下来我们分析下这三个类

web.xml配置一个Servlet

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <servlet>
    <servlet-name>dispatchServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatchServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

分析:
    如果要让一个Servlet生效, 则我们在web.xml需要配置一个servlet和servlet-mapping标签, 如果该Servlet
    配置的load-on-startup大于0的话, 则该Servlet的init方法就会被调用, 否则仅仅在该Servlet第一次被访问
    的时候才会调用, 而在init-param标签配置的内容, 会被放入到一个ServletConfig中进行保存, 当调用
    Servlet的init方法的时候, 该ServletConfig对象就会被作为参数传入

Servlet接口

public interface Servlet {
    public void init(ServletConfig config) throws ServletException;

    public ServletConfig getServletConfig();

    public void service(ServletRequest req, ServletResponse res) 

    public String getServletInfo();

    public void destroy();
}

分析:
    Servlet接口一共定义了五个接口方法, 在容器启动时, 如果该Servlet配置的load-on-startup大于0的话, 则
    该Servlet的init方法就会被调用, 否则仅仅在该Servlet第一次被访问的时候才会调用, 可以看到, 
    ServletConfig被作为参数传入了, 而getServletConfig仅仅是一个抽象方法, 需要由子类来实现, 在
    GenericServlet中, 就是利用一个ServletConfig属性来保存init方法传入的ServletConfig, 然后实现
    getServletConfig方法, 即返回的就是属性ServletConfig, service方法是请求过来时被触发的, 当Servlet
    拦截到对应的请求的时候, 就会触发其service方法, 该方法有两个参数, 分别是req, res, 利用这两个参数,
    我们能获取整个的请求信息, 并设置返回的数据等, getServletInfo方法返回的是一个字符串, 通常我们实现的
    时候就是返回当前Servlet的类名, 或者其他描述信息也可以, destroy方法则在容器被关闭的时候会被触发调用,
    即tomcat被关闭时会被调用

GenericServlet抽象类

public abstract class GenericServlet  implements Servlet, ServletConfig, java.io.Serializable {
    private transient ServletConfig config;

    public void destroy() {}

    public ServletConfig getServletConfig() {
        return config;
    }

    public String getServletInfo() { return ""; }

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

    public void init() throws ServletException {}

    public abstract void service(ServletRequest req, ServletResponse res)
}

分析:
    GenericServlet抽象类实现了Servlet接口, 实现了Servlet接口中除了service方法外的所有方法, 对于init
    方法, 其利用一个成员变量来将容器调用时传入的ServletConfig保存了下来, 其次getServletConfig方法就是
    将这个保存下来的ServletConfig返回而已, 与此同时, 提供了一个空参的init方法, 在有参的init方法中调用
    了该空参的init方法, 这样做的好处就是, 子类仅仅可以利用空参init方法来完成初始化的功能, 并且利用
    getServletConfig方法来获得ServletConfig, getServletInfo仅仅返回了一个空字符串, destroy方法也仅
    仅做了空的实现, 从而只有service方法需要子类进行实现, 其他方法子类可以选择性实现

ServletConfig接口

 public interface ServletConfig {
    public String getServletName();

    public ServletContext getServletContext();

    public String getInitParameter(String name);

    public Enumeration<String> getInitParameterNames();
}

分析:
    GenericServlet实现了这个ServletConfig接口, 目的是提供给开发者对ServletConfig的访问而已, 因为
    GenericServlet中已经保存了init方法中容器传入的ServletConfig了, GenericServlet实现这些接口其实很
    简单, 就是调用了保存下来的属性servletConfig的这些方法而已

HttpServlet类

public abstract class HttpServlet extends GenericServlet {
    public void service(ServletRequest req, ServletResponse res) {
        HttpServletRequest  request;
        HttpServletResponse response;

        if (!(req instanceof HttpServletRequest &&
                res instanceof HttpServletResponse)) {
            throw new ServletException("non-HTTP request or response");
        }

        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;

        service(request, response);
    }

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

        if (method.equals(METHOD_GET)) {
            doGet(req, resp);
        } else if (method.equals(METHOD_HEAD)) {
            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 {
            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);
        }
    }
}

分析:
    HttpServlet的实现很简单, 继承GenericServlet, 并实现其抽象方法service方法, 可以清晰的看到, 先将
    ServletRequest以及ServletResponse转为HttpServletRequest和HttpServletResponse, 然后利用
    getMethod方法判断当前请求是什么类型的, 从而调用对应的doXXX方法, 在HttpServlet中, 这些doXXX方法都
    是返回一个错误的, 因为这是要子类去实现的

ServletContext接口

SerlvetContext, 表示的是整个Servlet的上下文, 即当前项目下所有的Servlet都能共享该ServletContext, 上面
所聊到的ServletConfig是单个Servlet独有的, 由此可见, 如果我们期望多个Servlet共享某一块内容, 可以利用这
个ServletContext来进行传递, 在之后我们实现无xml完成SpringMVC环境搭建的时候也可以清晰的看到, 我们会利用
这个ServletContext来添加Servlet, 而不是在web.xml中进行添加了, 在ServletContext中, 有setAttribute、
getAttribute、removeAttribute等等方法, 例如:
    public void setAttribute(String name, Object object);

可以看到, 其实在ServletContext中可能维护了一个Map, setAttribute方法就是往这个Map中添加一个键值对而已,
并且这个值还是Object类型的

文章永久链接:https://tech.souyunku.com/36507

未经允许不得转载:搜云库技术团队 » SpringMVC源码分析一、Servlet体系结构分析

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们