1.SpringMVC的执行流程

2.SpringBoot申请映射原理

1.SpringMVC的执行流程

在咱们刚开始学习springMVC的时候,咱们必定学过springMVC的执行流程:

咱们简述一下SpringMVC的执行流程

1.客户端发送申请,申请被DispatcherServlet(中央处理器)捕捉。

2.DispatcherServlet对申请URL进行解析,取得资源标识符URI,依据URI调用HandlerMapping(处理器映射器)取得执行链(具体哪个Handler(Controller)执行该办法,以及该Handler的拦截器,参数转换器器等等),以HandlerExecutionChain对象返回给DispatcherServlet(中央处理器)。

3.DispatcherServlet依据取得的Handler,抉择对应的HandlerAdapter(如果胜利取得,就执行拦截器的preHandler(…)办法)。

4.HandlerAdapter对Request参数进行解析,并和Handlerr的参数进行绑定,调用反射执行Handlerr办法。

5.Handlerr执行结束当前,向Dispatcher返回一个ModelAndView对象。

6.依据返回的ModelAndView,抉择一个适合的ViewResolver返回给DispatcherServlet。

7.ViewResolver依据ModelAndView,渲染视图

8.返回后果

以往咱们通过这个流程只能死记硬背,不过咱们明天依据源码来剖析一下它的整体流程,并且着重剖析一下第2步(申请映射)。

2.SpringBoot申请映射原理

一句话解释:申请映射,就是通过拜访门路找到对应Controller的过程!

如何跟踪源码?咱们能够在Controller上打一个断点,并且跟踪断点的堆栈信息,就能够找到DispatcherServlet,并且找到对应的执行办法了。

而后dispatcherServlet的外围办法咱们就找到了doDispatch办法:

刨去一些预处理,查看,参数转换等逻辑,咱们能够看出,这执行逻辑和上图SpringMVC的执行逻辑截然不同。

    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                mappedHandler = getHandler(processedRequest);                if (mappedHandler == null) {                    noHandlerFound(processedRequest, response);                    return;                }                // Determine handler adapter for the current request.                //依据Handler找到 HandlerAdapter (处理器适配器)                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());                // Process last-modified header, if supported by the handler.                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)) {                    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);            }            //解决handler的执行后果(视图解析)            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);                }            }        }    }

这样咱们就对springMVC的执行逻辑有了一个hello Wrold级别的了解,接下来咱们着重解说一下通过申请是如何获取Handler的,也就是上面这一行,咱们能够在这一行下面打一个断点。

mappedHandler = getHandler(processedRequest);

再发送一个申请进入这个办法,咱们会发现这样一个逻辑:

    @Nullable    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {        if (this.handlerMappings != null) {            for (HandlerMapping mapping : this.handlerMappings) {                HandlerExecutionChain handler = mapping.getHandler(request);                if (handler != null) {                    return handler;                }            }        }        return null;    }

通过函数名称能够得出,Spring通过遍历的形式试图通过request来取得对应的hanler。咱们能够打个断点看看Spring里有多少种HandlerMapping。

其实看见这些对象的名字,咱们就能够得出咱们以后的自定义controller申请是通过RequestMappingHandlerMapping来解决的,RequestMappingHandlerMapping中的mappingRegistry更是证实了这一点,它保留了以后我的项目的所有controller门路

咱们查看获取handler的细节

咱们能够看到spring调用了一个办法来取得一个handler对象,咱们持续往里看:

发现还调用了一个办法,咱们持续往里看:

再往里面一层咱们发现,这里通过申请门路获取到了handler对象:

这是最初一个外围办法,咱们往里看,源码的逻辑就会高深莫测:

咱们最初来梳理一下申请映射逻辑:
1.先通过申请门路找出哪个处理器映射器能解决这个申请门路。
2.通过对应的处理器映射器来找到申请门路对应的handler,并返回。
3.RequestMappingHandlerMapping中保留@RequestMapping和handler的映射规定,当咱们容器启动的时候,SpringMVC就会扫描所有的Controller注解,并把对应关系保留在RequestMappingHandlerMapping外面。
4.SpringBoot也主动配置了一些初始门路,比方拜访“/”就能拜访到index.html。
5.当一个申请门路进入springMVC的时候,会挨个尝试所有的handlerMapping看是否有申请信息,如果没有则寻找下一个,如果咱们须要自定义的映射解决,也能够通过@Bean的形式给容器中减少。