SpringMVC面试题总结「建议收藏」

SpringMVC面试题总结「建议收藏」前言:SpringMVC的面试题常见的也就那几种,本文我打算分为两个方向为大家介绍SpringMVC的面试题。第一部分将从源码的执行的角度分析SpringMVC(以后简称MVC)第二部分将从面试官常问的SpringMVC面试题取介绍SpringMVC源码介绍1.http://localhost:8000/hello这个路径的执行流程是怎么走的流程大致分析一下:首先会请求会进入前…

大家好,又见面了,我是你们的朋友全栈君。

前言:SpringMVC的面试题常见的也就那几种,本文我打算分为两个方向为大家介绍SpringMVC的面试题。

第一部分将从源码的执行的角度分析SpringMVC(以后简称MVC)

第二部分将从面试官常问的SpringMVC面试题取介绍

SpringMVC源码介绍

1.http://localhost:8000/hello这个路径的执行流程是怎么走的

流程大致分析一下:首先会请求会进入前端控制器的doService方法->调用doDispatch方法->调用handle方法->这个handle方法需要从RequestMappingHandlerAdapter的父类找到AbstractHandlerMethodAdapter里面的handle方法,这个方法又调用RequestMappingHandlerAdapter的handleInternal方法->调用this的invokeHandlerMethod->invokeAndHandle->invokeForRequest->doInvoke方法->doInvoke里面调用this.getBridgedMethod().invoke其中this.getBridgedMethod()这个就是controller里面的那个方法,这就利用了反射机制,这就是MVC的执行流程,期间经历了RequestMappingHandlerAdapter这个处理器适配器,ServletInvocableHandlerMethod Servlet处理控制方法,InvocableHandlerMethod执行方法反射这主要的三个类

下面将用截图代码分析MVC的执行流程

首先进入前端控制器的doservice方法,调用doDispatch方法

SpringMVC面试题总结「建议收藏」xa

下面看下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 {
            try {
                //返回modelAndView对象
                ModelAndView mv = null;
                Object dispatchException = null;
                //做检查
                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
                    //这个比较重要,创建一个请求的处理器适配器
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if (this.logger.isDebugEnabled()) {
                            this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                        }

                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    //这个就比较重要了,调用处理器适配器来处理
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }

下面我们来看下mv = ha.handle(processedRequest, response, mappedHandler.getHandler());做了什么事吧

SpringMVC面试题总结「建议收藏」

说白了,这就是调用了RequestMappingHandlerAdapter里面的handleInternal方法

SpringMVC面试题总结「建议收藏」

可以看下invokeForRequest方法,最后调用doInvok方法

SpringMVC面试题总结「建议收藏」

第二种介绍:springmvc的流程图分析:

SpringMVC面试题总结「建议收藏」

1.用户请求进入前端控制器,调用doservice在调用doDispatch方法,调用getHandler方法,返回一个HandlerExecutionChain,里面包含一个你自己写的controller和mvc的拦截器,获得这个执行链mappedHandler之后,调用getHandlerAdapter(mappedHandler.getHandler())方法,获取适配器,这就是上图右半部分的分析,左半部分暂时未做分析

代码截图分析:

不要意思,纠正下错误,默认提供的映射器只有两种

SpringMVC面试题总结「建议收藏」

 

SpringMVC面试题总结「建议收藏」

拿到handler,来调用适配器的代码分析如下:

SpringMVC面试题总结「建议收藏」

后面的视图解析器部分以后再补充

2.映射路径的初始化源码分析

2.首先我们需要知道的是,我们写在controller里面的请求路径可是在应用程序加载启动时就被MVC加载好了的,存放到了一个Map里面。我们来分析下源码:

2.1在前端控制器中有一个initHandlerMappings方法,我们在这个方法打一个断点,程序在启动的时候就会进来

SpringMVC面试题总结「建议收藏」

2.2我们debug走到我们打断点的地方

SpringMVC面试题总结「建议收藏」

点开这些内容:

SpringMVC面试题总结「建议收藏」

我们会发现,MVC已经把对对应的关系放到了mappLookup中了,后续只需要取这个map里面取就行

3.MVC参数封装的原理分析(以最基础的类型参数封装为例)

前面的请求啥的都和前面分析的一样,我们直接看ServletInvocableHandlerMethod类里面的invoForRequest方法

SpringMVC面试题总结「建议收藏」

进去getMethodArgumentValues方法里面发现,主要是有一个argumentResove在起作用

SpringMVC面试题总结「建议收藏」

进入HandlerMethodArgumentResolverComposite类里面

SpringMVC面试题总结「建议收藏」

进入RequestParamMethodArgumentResolver这个类,通过servlet原始的封装getParamtermValues获取参数的值

SpringMVC面试题总结「建议收藏」

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/150799.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • MySQL自增主键值回溯问题

    MySQL自增主键值回溯问题平时我们使用MySQL时,通常每一个表都会有一个自增主键ID,每新增一条数据,ID值就会自增1。但在8.0之前版本的MySQL中,这个自增值会存在一个回溯的问题。例如,在一个新表中插入三条主键为1、2、3的数据行,这时候用SHOWCREATETABLE命令查看该表的AUTO_INCREMENT的值是4,这是没问题的。然后把ID=3的数据行删掉,再次查询AUTO_INCREMENT的值,依然是4,这也是没问题的。但如果重启一下MySQL,这个值就会变回3,而不是4,发生了回溯。这是因为AUTO_I

  • 张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)

    张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)使用Opencv实现张正友法相机标定之前,有几个问题事先要确认一下,那就是相机为什么需要标定,标定需要的输入和输出分别是哪些?相机标定的目的:获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。相机标定的输入:标定图像上所有内角点的图像坐标,标定板图像上所有内角点的空间三维坐标(一般情况下…

  • 摄像头-MIPI接口、DVP接口和CSI接口[通俗易懂]

    摄像头-MIPI接口、DVP接口和CSI接口[通俗易懂]本文转自摄像头的MIPI接口、DVP接口和CSI接口-百度经验(baidu.com),感谢作者分享一般来讲,摄像头的接口主要有MIPI接口、DVP接口、CSI接口三大类;我们常用的电脑摄像头接口是USB接口,而常见的智能手机上的摄像头是MIPI接口,还有一部分的摄像头(比如说某些支持DVP接口的硬件)是DVP接口;通俗的讲,USB是串行通用串行总线(UniversalSerialBus)的简称,而MIPI是移动行业处理器接口(MobileIndustryProcessorInterf

  • 图像识别算法

    图像特征包括颜色特征、纹理特征、形状特征以及局部特征点等。局部特点具有很好的稳定性,不容易受外界环境的干扰。1.局部特征点图像特征提取是图像分析与图像识别的前提,它是将高维的图像数据进行简化表达最有效的方式,从一幅图像的M×N×3的数据矩阵中,我们看不出任何信息,所以我们必须根据这些数据提取出图像中的关键信息,一些基本元件以及它们的关系。局部特征点是图像特征的局部

  • kali更新源(源、软件更新,附kali源)

    kali更新源(源、软件更新,附kali源)很多系统安装好以后都需要进行更新源,或者软件需要更新,小编在这里进行一次更新源和软件的记录,还请路过大牛指出不足。1、在/etc/apt下有文件sources.list文件,将下方提供的源粘贴一个即可#命令vi/etc/apt/sources.list输入i进行编辑,把文章下方附有的kali源粘贴一个即可2、执行命令更新源#命令apt-getupdate3、更…

  • turtle(海龟作图),C++版「建议收藏」

    turtle(海龟作图),C++版「建议收藏」海龟作图引言turtle来源Logo的原型来自另一个计算机语言LISP,派普特修改了LISP的语法使其更易于阅读。Logo常被称作没有括号的Lisp。Logo是一种解释型语言,和其他语言不同的是,它内置一套海龟绘图(TurtleGraphics)系统,通过向海龟发送命令,用户可以直观地学习程序的运行过程,因此很适于儿童学习。它亦适合用作数学教学。海龟绘图使得Logo用户可以通过简单的编程创作出丰富多彩的视觉效果或图案。假想一只带着画笔的海龟可以接受简单的命令,例如向前走100步,或者左转30度。

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号