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

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
    题记:
    为了解SpringMVC加载过程的细节,最近阅读了其部分源码,并自己手写实现了一个简单的SpringMVC框架,现记录作为总结。

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

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

1.Spring MVC上下文初始化

首先看下图:
20191102100683\_1.png
这个继承体系说明,Servlet容器(如Tomcat)可以读取到SpringMVC运行的整个过程(init -> service -> destroy)。
当Request请求来的时候,先到Servlet容器环境,通过继承关系将Request请求传入到SpringMVC中处理。

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

第二步:查看模板方法initServletBean,也就来到了FrameworkServlet类中初始化SpringMVC自己持有的上下文:
20191102100683\_3.png
继续查看initWebApplicationContext方法的实现:
20191102100683\_4.png
基本完成SpringMVC上下文环境(WebApplicationContext)的初始化:
20191102100683\_5.png

第三步:查看onRefresh方法,来到DispatcherServlet类中:
20191102100683\_6.png

小结:
20191102100683\_7.png

2.SpringMVC服务执行流程细节

注意了,这个是理解SpringMVC的重点内容,手写自己的SpringMVC框架就是模仿简化这个流程来的。
查看DispatcherServlet的doService方法源码:
20191102100683\_8.png
接着查看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);
                }
            }
        }
    }

小结(记住这张图!!!):
20191102100683\_9.png

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


来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » 源码分析之Spring MVC上下文的加载细节(二)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏