• Spring MVC


    SpringMVC的执行流程

    1) 用户向服务器发送请求,请求被SpringMVC前端控制器DispatcherServlet捕获
    2) DispatcherServlet对请求URL进行解析,得到请求资源标识符URI,判断请求URI对应的映射:
    A) 不存在
    I) 再判断是否配置了mvc:default-servlet-handler
    II) 如果没有配置,则在控制台报映射查找不到,客户端展示404错误
    III) 如果有配置,则访问目标资源(一般为静态资源:JS,CSS,HTML)。找不到资源客户端也会展示404错误;
    IV)
    B) 存在则执行下面的流程
    3) 根据该URI,调用HandlerMapping获得该Handler配置的所有相关对象(Handler对象以及Handler对象对应的拦截器),最后以HandlerExcutionChain执行链对象的形式返回。
    4) DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter;
    5) 如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler;
    6) 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮助你做一些额外的工作;
    a) HttpMessageConveter:将请求(json,xml)装换成一个对象,将对象转换为指定的响应信息;
    b) 数据转换:对请求新进行数据转换。如String转换成Integer,Double等
    c) 数据格式化:对请求信息进行数据格式化。如字符串转换格式化数字或者格式化日期等;
    d) 数据验证:验证数据的有效性(长度,格式等),验证结果存储到BindingResult或者Error中
    7) Handler执行完成后,向 DispatcherServlet 返回一个ModelAndView对象
    8) 此时开始执行拦截器的postHandle
    9) 根据返回的ModelAndView选择一个合适的ViewResolver进行视图解析,根据Model和View来渲染视图;
    渲染视图完毕执行拦截器的afterCompletion
    将渲染结果返回给客户端‘

    DispatcherServlet的初始化过程

    DispatcherServlet本质上是一个Servlet,所有天然的遵循Servlet的生命周期。所有宏观上是Servlet生命周期来进行调度。
    DispatcherServlet --> FrameworkServlet – > HttpServletBean – > HttpServlet – > GenericServlet – > Servlet

    GenericServlet::init(ServletConfig) -> HttpServletBean::init() -> FrameworkServlet::initServletBean():

    1. FrameworkServlet::initWebApplicationContext()
      FrameworkServlet::createWebApplicationContext()-> DispatcherServlet::onRefresh() -> DispatcherServlet::initStrategies: 初始化DispatcherServlet的各个组件(组件扫描、视图解析器、view-controller、default-servlet-handler、拦截器、异常处理、注解驱动、文件上传解析器)
      将创建的 applicationcontext 共享到 Servlet全局域中(ServletContext(attrname:value))

    DispatcherServlet调用组件处理请求

    HttpServlet::service(ServletRequest req, ServletResponse resp)
    -> FrameworkServlet::service(HttpServletRequest, HttpServletResponse) -> 如果method是PATCH或者为null则调用 processRequest(); 否则调用HttpServlet::service(HttpServletRequest, HttpServletResponse)
    -> FrameworkServlet::doPost/doGet(HttpServletRequest request, HttpServletResponse response) -> processRequest()
    ->DispatcherServlet::doService(request, response) -> doDispatch()
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    try {
    ModelAndView mv = null;
    Exception dispatchException = null;
    try {
    processedRequest = checkMultipart(request);
    multipartRequestParsed = (processedRequest != request);
    // Determine handler for the current request.
    //这里包含了 我们实现的Handler、Interceptors
    mappedHandler = getHandler(processedRequest);
    if (mappedHandler == null) {
    noHandlerFound(processedRequest, response);
    return;
    }
    // Determine handler adapter for the current request.
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    // Process last-modified header, if supported by the handler.
    String method = request.getMethod();
    boolean isGet = “GET”.equals(method);
    if (isGet || “HEAD”.equals(method)) {
    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    return;
    }
    }
    //调用拦截器的preHandle
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
    }
    // Actually invoke the handler.
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    if (asyncManager.isConcurrentHandlingStarted()) {
    return;
    }
    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);
    }
    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);
    }
    }
    }
    }

  • 相关阅读:
    MySQL进阶—索引1
    leetcode解题思路分析(一百四十九)1297 - 1304 题
    Linux 下配置 hosts 并设置免密登录
    C语言实现简单通讯录,malloc,calloc,realloc,free动态内存分配的学习。
    电子招标初学者指南
    由面试题“Redis是否为单线程”引发的思考【文末送书-23】
    代码随想录 Day26贪心算法01-上
    【无标题】【教3妹学编程-算法题】2918. 数组的最小相等和
    【前端知识】+new Date()是什么?
    LeetCode二叉树系列——144.二叉树的前序遍历
  • 原文地址:https://blog.csdn.net/qq_38328148/article/details/127590069