SpringBoot学习笔记【part10】请求映射原理

SpringBoot学习笔记【part10】请求映射原理,第1张

SpringBoot学习笔记【part10】请求映射原理 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。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5715506.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存