源码分析之Spring MVC上下文的加载细节(二)

题记:
为了解SpringMVC加载过程的细节,最近阅读了其部分源码,并自己手写实现了一个简单的SpringMVC框架,现记录作为总结。

分为三篇博客:
源码分析之Spring MVC上下文的加载细节(一)
• 源码分析之Spring MVC上下文的加载细节(二)【本篇】
源码分析之动手实现手写一个自己的SpringMVC框架(三)

阅读完这三篇博客,将了解到:
• Spring容器整套技术是如何与我们web容器的耦合?
• Spring MVC启动自己持有的MVC上下文之前需要IOC容器的支持,Spring是如何驱动IOC容器的初始化的细节的?
• Spring MVC上下文初始化以及组件和服务初始化细节?
• 完成一个属于的自己SpringMVC框架

1.Spring MVC上下文初始化

首先看下图:
《源码分析之Spring MVC上下文的加载细节(二)》
这个继承体系说明,Servlet容器(如Tomcat)可以读取到SpringMVC运行的整个过程(init -> service -> destroy)。
当Request请求来的时候,先到Servlet容器环境,通过继承关系将Request请求传入到SpringMVC中处理。

传入之前,SpringMVC要先初始化,现在我们来阅读源码(注意代码注释),了解SpringMVC上下文的初始化(init)。
第一步:HttpServletBean是对接Servlet容器接收传入参数的类,我们首先查看HttpServletBean中init方法:
《源码分析之Spring MVC上下文的加载细节(二)》
这样做的最终目的是初始化各个Bean组件信息。而需要初始化Bean组件信息前提需要宿主环境,于是进入第二步。

第二步:查看模板方法initServletBean,也就来到了FrameworkServlet类中初始化SpringMVC自己持有的上下文:
《源码分析之Spring MVC上下文的加载细节(二)》
继续查看initWebApplicationContext方法的实现:
《源码分析之Spring MVC上下文的加载细节(二)》
基本完成SpringMVC上下文环境(WebApplicationContext)的初始化:
《源码分析之Spring MVC上下文的加载细节(二)》

第三步:查看onRefresh方法,来到DispatcherServlet类中:
《源码分析之Spring MVC上下文的加载细节(二)》

小结:
《源码分析之Spring MVC上下文的加载细节(二)》

2.SpringMVC服务执行流程细节

注意了,这个是理解SpringMVC的重点内容,手写自己的SpringMVC框架就是模仿简化这个流程来的。
查看DispatcherServlet的doService方法源码:
《源码分析之Spring MVC上下文的加载细节(二)》
接着查看doDispatch源码,深入理解service的处理:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 1.用户请求
    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.
            // 2.根据Request查询找到handler,3.并返回处理器执行链
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null || mappedHandler.getHandler() == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // Determine handler adapter for the current request.
            // 4.请求执行handler,根据handler找到HandlerAdapter
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            // 处理Get、Head请求的Last-Modified
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                // 是否使用缓存页面
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }
            // 执行相应的Interceptor的preHandle
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // Actually invoke the handler.
            // 5.HandlerAdapter执行Handler处理请求(6.返回ModelAndView),
            // 7.返回ModelAndView到DispatcherServlet
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            // 如果需要异步处理直接返回
            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
            // 当mv的view为空时,根据request设置默认view
            applyDefaultViewName(request, mv);
            // 执行相应的Interceptor的preHandle
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        // 8、9、10.处理返回结果。(包括处理异常,渲染页面,发出完成通知触发Interceptor的afterCompletion)
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Error err) {
        triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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);
            }
        }
    }
}

小结(记住这张图!!!):
《源码分析之Spring MVC上下文的加载细节(二)》

完毕,下一篇文章:源码分析之动手实现手写一个自己的SpringMVC框架(三)

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/honhong1024/article/details/79531586
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞