Spring MVC 前端控制器 (DispatcherServlet)处理流程解析

作者:心城以北 时间:2023-02-03 03:56:50 

Spring MVC 请求处理流程

Spring MVC 前端控制器 (DispatcherServlet)处理流程解析

  • 用户发起请求,到 DispatcherServlet;

  • 然后到 HandlerMapping 返回处理器链(包含 * 和具体处理的 Handler);

  • 调用处理器链的适配器 HandlerAdapter 来处理;

  • 执行具体的方法,比如 @RequestMapper修饰的逻辑处理方法;

  • 返回结果的视图解析器;

  • 最后进行视图解析和渲染返回结果给用户;

DispatcherServlet

DispatcherServlet是前置控制器,配置在web.xml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自己定义,把拦截下来的请求,依据相应的规则分发到目标Controller来处理,是配置spring MVC的第一步。 DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处。

源码分析

org.springframework.web.servlet.DispatcherServlet#doDispatch 方法是主要处理请求的源码如下:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   try {
       try {
           // 文件上传相关
           processedRequest = checkMultipart(request);
           multipartRequestParsed = (processedRequest != request);
           // DispatcherServlet收到请求调用处理器映射器HandlerMapping。
           // 处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器 * )一并返回给DispatcherServlet。
           mappedHandler = getHandler(processedRequest);
           if (mappedHandler == null) {
               noHandlerFound(processedRequest, response);
               return;
           }
           4.DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter,
           HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
           // Process last-modified header, if supported by the handler.  HTTP缓存相关
           String method = request.getMethod();
           boolean isGet = HttpMethod.GET.matches(method);
           if (isGet || HttpMethod.HEAD.matches(method)) {
               long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
               if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                   return;
               }
           }
           // 前置 *
           if (!mappedHandler.applyPreHandle(processedRequest, response)) {
               // 返回false就不进行后续处理了
               return;
           }
           // 执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
           // 执行处理器Handler(Controller,也叫页面控制器)。
           // Handler执行完成返回ModelAndView
           // HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
           mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
           if (asyncManager.isConcurrentHandlingStarted()) {
               return;
           }
           // 如果没有视图,给你设置默认视图  json忽略
           applyDefaultViewName(processedRequest, mv);
           //后置 *
           mappedHandler.applyPostHandle(processedRequest, response, mv);
       }
       catch (Exception ex) {
           dispatchException = ex;
       }
       catch (Throwable err) {
           // As of 4.3, we're processing Errors thrown from handler methods as well,
           // making them available for @ExceptionHandler methods and other scenarios.
           dispatchException = new NestedServletException("Handler dispatch failed", err);
       }
       // DispatcherServlet将ModelAndView传给ViewReslover视图解析器
       // ViewReslover解析后返回具体View
       // DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
       // DispatcherServlet响应用户。
       processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   catch (Exception ex) {
       triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
   }
   catch (Throwable err) {
       triggerAfterCompletion(processedRequest, response, mappedHandler,
                              new NestedServletException("Handler processing failed", err));
   }
   finally {
       if (asyncManager.isConcurrentHandlingStarted()) {
           // Instead of postHandle and afterCompletion
           if (mappedHandler != null) {
               mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
           }
       }
       else {
           // Clean up any resources used by a multipart request.
           if (multipartRequestParsed) {
               cleanupMultipart(processedRequest);
           }
       }
   }
}

doDispatch方中已经涵盖了DispatcherServlet的主要职责: 1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析; 2、通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor * ); 3、通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器); 4、通过ViewResolver解析逻辑视图名到具体视图实现; 5、本地化解析; 6、渲染具体的视图等; 7、如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。

DispatcherServlet初始化的上下文加载的Bean是只对SpringMVC有效的Bean, 如Controller、HandlerMapping、HandlerAdapter等等,该初始化上下文只加载Web相关组件。

DispatcherServlet初始化主要做了如下两件事情: 1、初始化SpringMVC使用的Web上下文,并且可能指定父容器为(ContextLoaderListener加载了根上下文); 2、初始化DispatcherServlet使用的策略,如HandlerMapping、HandlerAdapter等。

Spring MVC 中的一些核心类

DispatcherServlet 默认使用 WebApplicationContext 作为上下文,该上下文 * 殊的Bean有一下几个:

类名描述
Controller处理器/页面控制器,做的是MVC中的C的事情,但控制逻辑转移到前端控制器了,用于对请求进行处理;
HandlerMapping请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor * )对象;如BeanNameUrlHandlerMapping将URL与Bean名字映射,映射成功的Bean就是此处的处理器;
HandlerMapping请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor * )对象;如BeanNameUrlHandlerMapping将URL与Bean名字映射,映射成功的Bean就是此处的处理器;
ViewResolverViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;如InternalResourceViewResolver将逻辑视图名映射为jsp视图;
LocalResover本地化解析,因为Spring支持国际化,因此LocalResover解析客户端的Locale信息从而方便进行国际化;
ThemeResovler主题解析,通过它来实现一个页面多套风格,即常见的类似于软件皮肤效果;
MultipartResolver文件上传解析,用于支持文件上传;
HandlerExceptionResolver处理器异常解析,可以将异常映射到相应的统一错误界面,从而显示用户友好的界面(而不是给用户看到具体的错误信息);
RequestToViewNameTranslator当处理器没有返回逻辑视图名等相关信息时,自动将请求URL映射为逻辑视图名;

来源:https://juejin.cn/post/7102440874449043469

标签:Spring,MVC,DispatcherServlet
0
投稿

猜你喜欢

  • C++继承详细介绍

    2022-08-18 10:05:42
  • java实现sftp客户端上传文件以及文件夹的功能代码

    2023-02-14 22:07:28
  • Java 远程调用失败重试的操作方法

    2021-08-26 21:42:58
  • Android RecyclerView详解之实现 ListView GridView瀑布流效果

    2023-11-26 10:09:00
  • C#实现用于操作wav声音文件的类实例

    2021-08-15 22:06:25
  • Flutter开发通用页面Loading组件示例详解

    2022-05-18 23:41:09
  • Android多个TAB选项卡切换效果

    2022-04-10 03:03:15
  • Java对象的XML序列化与反序列化实例解析

    2023-02-25 15:21:19
  • Unity制作小地图和方向导航

    2023-02-07 16:51:02
  • springboot 如何解决yml没有spring的小叶子标志问题

    2021-06-12 02:57:01
  • 详解Java对象结构与对象锁的升级

    2021-12-05 16:18:38
  • Java实现对两个List快速去重并排序操作示例

    2023-05-02 03:40:14
  • java类中生成jfreechart,返回图表的url地址 代码分享

    2023-09-08 00:54:07
  • C#通过重写Panel改变边框颜色与宽度的方法

    2021-07-09 05:57:52
  • C++编程中用put输出单个字符和cin输入流的用法

    2023-05-28 06:14:49
  • hibernate存取json数据的代码分析

    2022-01-18 15:00:08
  • Kotlin中常见内联扩展函数的使用方法教程

    2023-07-04 13:46:12
  • 云IDE:Eclipse Che:Eclipse下一代IDE(推荐)

    2023-04-01 05:58:27
  • mybatis mybatis-plus-generator+clickhouse自动生成代码案例详解

    2021-06-06 10:12:55
  • C#多线程及同步示例简析

    2022-02-25 22:12:43
  • asp之家 软件编程 m.aspxhome.com