SpringBoot学习笔记【part10】Web开发——请求映射原理

导读:本篇文章讲解 SpringBoot学习笔记【part10】Web开发——请求映射原理,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

SpringBoot 学习笔记 Part10

1. 请求映射

从@RequestMapping标注处理什么请求,到控制器方法的方法体返回值,这个过程就叫做请求映射,如下:

    @RequestMapping("hello")
    public String hello(){
        return "Hello SpringBoot 2 !";
    }

2. 请求映射原理

2.1 DispatcherServlet

springboot 所有的请求过来都会经过 DispatcherServlet,因为springboot底层仍用的是 springmvc,所以 DispatcherServlet 是处理所有请求的开始。

前往底层,我们可以发现 DispatcherServlet 最终继承于原生Servlet—— HttpServlet,其中继承树为 DispatcherServlet -> FrameworkServlet -> HttpServletBean -> HttpServlet。

现在我们想知道在哪个派生类中重写了 doGet 和 doPost,前往底层源码可以发现,在 FrameworkServlet 中有如下代码:

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
    /* 略 */
    protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.processRequest(request, response);
    }

    protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.processRequest(request, response);
    }

    protected final void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.processRequest(request, response);
    }

    protected final void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.processRequest(request, response);
    }
    /* 略 */
}

在 FrameworkServlet 的处理请求方法中都调用了本类的 processRequest( ) 方法,这个方法经分析,有大量初始化和清理操作,其中最重要的是它调用的 doService( ) 方法。

protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    /* 略 */
	this.doService(request, response);
    /* 略 */
}

追踪该 doService( ) 方法,我们发现这也是一个本类的方法,是一个抽象方法。不难推测,这个抽象方法将在下一个派生类也就是 DispatcherServlet 中实现。

protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception;

在 DispatcherServlet 的 doService 的实现方法中,有大量的处理,但我们最终把目光聚集到 doDispatcher 方法上。

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    /* 略 */
    this.doDispatch(request, response);
    /* 略 */
}

我们最终发现, doDispatcher 方法才是真正有功能的方法,它检查文件上传、确定当前请求的处理程序(找到当前请求使用哪个Controller方法处理) 等。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	/* 略 */
    processedRequest = this.checkMultipart(request);
    mappedHandler = this.getHandler(processedRequest);
    /* 略 */
}

总结:当有请求进来时,调用顺序为:HttpServlet.doGet() -> FrameworkServlet.processRequest().doService() -> DispatcherServlet.doService().doDispatch()

2.2 doDispatch方法

doDispatcher 方法才是真正有请求处理功能的方法,它检查文件上传、确定当前请求的处理程序(找到当前请求使用哪个Controller方法处理) 等。节选源码如下,逐步分析。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	/* 略 */
    processedRequest = this.checkMultipart(request); //检查是不是文件上传
    multipartRequestParsed = processedRequest != request;
    mappedHandler = this.getHandler(processedRequest); //找到当前请求使用哪个Controller方法处理
	/* 其他功能,略 */
}

2.3 getHandler方法

从 doDispatch方法 进入 getHandler方法。

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null)
    /* 略 */
}

HandlerMappings 译为处理器映射,即 /xxx 将被映射为 xxx,所有的处理器映射都被存在 handlerMappings 对象里。对第一行handlerMappings判空代码进行debug调试,可以发现存在5个handlerMapping。

在这里插入图片描述

其中下标为1的就是我们之前学习过的欢迎页,即springmvc在该对象里储存了欢迎页的映射规则。不难发现,下标为0的 RequestMappingHandlerMapping的前半段RequestMapping酷似我们之前学习过的注解 @RequestMapping,经过验证,这里就保存着我们所有被 @RequestMapping 标注过的 Controller 方法和handler的映射规则。其实项目一启动,@RequestMapping的映射规则就被springmvc解析并存储了。

继续 getHandler 方法的分析,下面是一个循环,遍历所有 @RequestMapping 映射规则意在找到对应的handler方法。通过debug,可以找到mappingRegistry对象,我之前编写的rest请求映射,都存在这里面。

在这里插入图片描述

总结:所有的请求映射都存在HandlerMappings中。

2.4 HandlerMappings

SpringBoot 中所有的请求映射都在 HandlerMappings 里。

在这里插入图片描述

在handlerMappings容器中我们可以发现,SpringBoot 自动配置了默认的 RequestMappingHandlerMapping、自动配置了欢迎页的 WelcomePageHandlerMapping(即使用 / 能访问到 index.html),以及之后学习的 BeanNameHandlerMapping、RouterFunctionMapping以及 SimpleUrlHandlerMapping。

SpringBoot的请求进来,会在getHandler方法里挨个尝试所有的 HandlerMapping 看其是否有对应的请求信息。若有则找到这个请求对应的 handler 并调用,若没有则去找下一个 HandlerMapping。

自定义HandlerMapping
若在一些场景(如不同版本的方法调用:/api/v1/user、/api/v2/user)我们需要自定义一些映射处理,我们也可以自己给容器中放 自定义HandlerMapping。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/93561.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!