Spring MVC DispatcherServlet源码 解析

一、前言 :

Spring Mvc执行流程:
在这里插入图片描述

Spring工作流程描述
1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法)
4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7. ViewResolver 结合Model和View,来渲染视图
8. 将渲染结果返回给客户端。

二、进入正题:

通过 https://blog.csdn.net/qq_36882793/article/details/100050561 可以了解到 DispatcherServlet 上下文的配置过程。并顺带对DispatcherServlet源码进行分析。
在Servlet3.0中,容器在启动时会在类路径中查找javax.servlet.ServletContainerInitializer 的实现类,如果能发现则会用它来配置Servlet容器。在Spring中Spring提供了其实现: SpringServletContainerInitializer。 而SpringServletContainerInitializer又会查找WebApplicationInitializer的类并将配置的任务交给他们来完成。Spring 3.2 为其引入了一个便利的基础实现类即 AbstractAnnotationConfigDispatcherServletInitializer 。即 当 部署到Servlet3.0容器中的时候,容器会发现AbstractAnnotationConfigDispatcherServletInitializer 具体实现类,并使用该类来配置Servlet上下文。

  1. AbstractDispatcherServletInitializer : onStartup -> registerDispatcherServlet -> createDispatcherServlet
    在这里插入图片描述
    由此,进入DispatcherServlet 类中的构造函数

1. 请求的处理 :

用户请求后,会由前端控制器DispatcherServlet来进行处理。

1. DispatcherServet继承于FrameworkServlet,一个servlet要想处理请求,必须重写doGet() doPost()等方法。所以FrameworkServlet 中实现了service(处理了PATCH 方法)、doGet、doPost方法。DispatcherServet继承了上述方法。
其逻辑处理都交给processRequest方法处理。在这里插入图片描述

2. processRequest了 执行doService方法,doService 方法的实现在DispatcherServlet中实现 , doService中调用了doDispatch方法.
FrameworkServlet 类中的 processRequest 方法
在这里插入图片描述
doService方法中
在这里插入图片描述
doDispatch中
在这里插入图片描述

2. HandlerExecutionChain getHandler(HttpServletRequest request)

1. 根据上图可以看到 doDispatch方法在第二步调用了getHandler方法。查看getHandler方法如下。在该方法中通过遍历找到支持当前请求的HandlerMapping(处理器映射器)。
在这里插入图片描述
2. HandlerMapper 又调用了 AbstractHandlerMapping类中的 HandlerExecutionChain getHandler(HttpServletRequest request) 方法来获取 HandlerExecutionChain
注: HandlerExecutionChain:
包含一个处理请求的处理器(Handler),同时包含若干个对该请求实施拦截的拦截器(HandlerInterceptor),当HandlerMapping 返回 HandlerExecutionChain 后, DispatchServlet 将请求交给定义在 HandlerExecutionChain 中的拦截器和处理器一并处理。

在这里插入图片描述
在这里插入图片描述
3. 查看 getHandlerExecutionChain 方法的实现
在这里插入图片描述
4. 综上, 完成了doDispatch 方法中的 getHandler 方法的调用,并返回了一个 HandlerExecutionChain 对象。里面包含若干个匹配的拦截器和请求的Handler

3. HandlerAdapter getHandlerAdapter(Object handler) 详解。

  1. getHandlerAdapter 即在众多处理器适配器中找到合适的适配器并返回
    在这里插入图片描述
    注: 三种适配器类型
    在这里插入图片描述

4. 拦截器相关: boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) 方法详解

DispatcherServlet 中的调用过程
DispatcherServlet 中的调用过程
applyPreHandle方法代码
applyPreHandle方法代码
根据上图可以看到,容器会通过 getInterceptors() 方法从 当前请求对应的 HandlerExecutionChain 类实例 mappedHandler 中 获取 拦截器(mappedHandler 在第二步产生,其内部的拦截器在第二步进行了过滤),并经过遍历调用拦截器的 preHandler 方法。
注意 :
1. preHandler() 方法的调用时正序调用,postHandlerafterCompletion 方法在调用拦截器的时候都是倒序。(具体后面讲解)
2. 当 preHandler() 方法返回false时,会直接调用triggerAfterCompletion方法,调用拦截器的afterCompletion 方法,并返回false,并且DispatcherServlet 中 会直接 return 结束此次请求

5. ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) 方法详解

在这里插入图片描述
在这里插入图片描述
因为 ha.handler() 方法调用 的是AbstractHandlerMethodAdapter中的handler方法,再调用 handleInternal方法,所以这里直接看 ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) 方法。
由handleInternal方法看出方法的执行其实都是由invokeHandlerMethod来执行。invokeHandlerMethod 方法又调用 invokeAndHandle 方法 ,invokeAndHandle 继续调用 invokeForRequest 方法, invokeForRequest 中调用 doInvoke 执行了本次请求的方法。
invokeForRequest代码

doInvoke 代码

6、7. 拦截器相关:applyPostHandle、triggerAfterCompletion 方法详解

(1). applyPostHandle 方法
applyPostHandle 调用
由代码可以发现,applyPostHandle是在方法执行后(mv = ha.handle(processedRequest, response, mappedHandler.getHandler());)执行。即拦截器的 postHandler 是在方法之后调用。

applyPostHandle 源码
源码可以看出,这个循环时倒序循环,类似于栈的形式,先进后出。 比如如果拦截器 12345 。在调用applyPreHandle 方法时(入栈)会按照12345的顺序调用preHandle 方法,但是在调用 postHandle方法时则是按照54321的顺序(出栈)。

(2) triggerAfterCompletion 方法
在这里插入图片描述
triggerAfterCompletion 内部实现还是调用 HandlerExecutionChain 的 triggerAfterCompletion 方法,因此我们进入看 HandlerExecutionChain 的 triggerAfterCompletion 方法
在这里插入图片描述
HandlerExecutionChain 的 triggerAfterCompletion 方法:
在这里插入图片描述
可以看出和applyPostHandle方法的执行过程基本类似,triggerAfterCompletion 方法在handler方法执行完之后执行,进行统一的异常处理。

以上:内容参考
https://www.jianshu.com/p/1bff57c74037。
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我会按照您的要求整理 spring mvc 的底层源码启动流程,但是由于我没有图形界面,无法提供您清晰的图示。 下面是 spring mvc 的底层源码启动流程: 1. Spring 容器的初始化 Spring容器的初始化是整个Spring MVC启动过程的第一步,这个过程通过Spring的配置文件来完成。一旦Spring容器初始化完成,它将自动以Bean的形式将Spring MVC的各个组成部分进行注册。 2. DispatcherServlet的初始化 DispatcherServletSpring MVC的核心组件,它的初始化是整个Spring MVC启动过程的第二步。DispatcherServlet将根据Spring容器中的Bean配置信息来注册一系列的拦截器、Handler映射器、视图解析器等组件。注册完成后,访问应用启动入口时,就可以通过DispatcherServlet处理请求和返回响应。 3. URL到Handler的映射 在DispatcherServlet完成初始化后,它会依据注册的Handler映射器对URL进行解析,并将其转化为对应的Handler对象,这个过程叫做映射。 4. Handler处理 Handler对象是真正的请求处理者,它会根据请求内的信息来进行处理并返回响应结果。Handler处理完成后,将会返回一个ModelAndView对象,该对象包含了处理后的数据和返回的视图。 5. 视图解析 视图解析器会通过ModelAndView中配置的视图,在Spring MVC中,视图可以是JSP、Thymeleaf等,最终将结果呈现给客户端浏览器。 6. 渲染视图 通过处理后的数据和视图,视图解析器会生成HTML代码,并将其交给HttpServletResponse对象的输出流进行输出。 7. 返回结果 最后,DispatcherServlet将结果返回给客户端浏览器。 希望这可以帮助您更好地理解Spring MVC的启动流程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猫吻鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值