文章目录
- 一、前言 :
- 二、进入正题:
- 1. 请求的处理 :
- 2. HandlerExecutionChain getHandler(HttpServletRequest request)
- 3. HandlerAdapter getHandlerAdapter(Object handler) 详解。
- 4. 拦截器相关: boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) 方法详解
- 5. ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) 方法详解
- 6、7. 拦截器相关:applyPostHandle、triggerAfterCompletion 方法详解
一、前言 :
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上下文。
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) 详解。
- getHandlerAdapter 即在众多处理器适配器中找到合适的适配器并返回
注: 三种适配器类型
4. 拦截器相关: boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) 方法详解
DispatcherServlet 中的调用过程
applyPreHandle方法代码
根据上图可以看到,容器会通过 getInterceptors()
方法从 当前请求对应的 HandlerExecutionChain
类实例 mappedHandler 中 获取 拦截器(mappedHandler 在第二步产生,其内部的拦截器在第二步进行了过滤),并经过遍历调用拦截器的 preHandler 方法。
注意 :
1. preHandler()
方法的调用时正序调用,postHandler
和afterCompletion
方法在调用拦截器的时候都是倒序。(具体后面讲解)
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
执行了本次请求的方法。
6、7. 拦截器相关:applyPostHandle、triggerAfterCompletion 方法详解
(1). applyPostHandle 方法
由代码可以发现,applyPostHandle是在方法执行后(mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
)执行。即拦截器的 postHandler 是在方法之后调用。
源码可以看出,这个循环时倒序循环,类似于栈的形式,先进后出。 比如如果拦截器 12345 。在调用applyPreHandle
方法时(入栈)会按照12345的顺序调用preHandle 方法,但是在调用 postHandle方法时则是按照54321的顺序(出栈)。
(2) triggerAfterCompletion 方法
triggerAfterCompletion 内部实现还是调用 HandlerExecutionChain 的 triggerAfterCompletion 方法,因此我们进入看 HandlerExecutionChain 的 triggerAfterCompletion 方法
HandlerExecutionChain 的 triggerAfterCompletion 方法:
可以看出和applyPostHandle方法的执行过程基本类似,triggerAfterCompletion
方法在handler方法执行完之后执行,进行统一的异常处理。
以上:内容参考
https://www.jianshu.com/p/1bff57c74037。
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正。