关于spring:SpringMVC执行流程及源码分析

38次阅读

共计 25975 个字符,预计需要花费 65 分钟才能阅读完成。

SpringMVC 流程及源码剖析

前言

​ 学了一遍 SpringMVC 当前,想着做一个总结,温习一下。温习写上面的总结的时候才发现,其实本人学的并不彻底、牢固、也没有学全,视频跟书本是要联合起来一起,每一位老师的视频可能提到的货色都不统一,也导致也不是很全面,书本上会讲的笔记零碎、全面。同时我本人也是一个初学者,上面总结的可能并不欠缺、正确,心愿看到的大神给我指出,在此非常感谢。


[TOC]

一、Spring 外围模块

1、外围模块

​ Spring Web MVC(下文简称为 SpringMVC)是 Spring 提供 Web 利用的框架设计,属于体现层的框架。SpringMVC 是 Spring 框架的一部分。
Spring 框架包含大抵六大模块,外围容器(Core Container)、AOP 和设施反对、数据拜访及集成、Web、报文发送、Test

图片来源于 Spring 官网 5.0.0.M5:

​ https://docs.spring.io/spring-framework/docs/5.0.0.M5/spring-framework-reference/html/overview.html#overview-modules

对于 Spring5 模块图,有 2 点疑难:

1、不分明为什么在 Spring 官网上 5.0 版本当前,Release 版(稳定版)的都未找到模块图,然而在 M(里程碑版)版找到          了,如果有人在 5.0 当前的 Release 版(稳定版)找到,麻烦给我留个言,谢谢。2、在其余博文中看到 Spring5 模块结构图是这样的:

挺奇怪这个图是哪里来的?(路过的大神请指导)

对于问题 2,我在 Spring5.2.13.RELEASE GA 中,找到了如下所示信息:

拷贝以上信息:

Spring Framework Documentation

Version 5.2.13.RELEASE

What’s New, Upgrade Notes, Supported Versions, and other topics, independent of release cadence, are maintained externally on the project’s Github Wiki.

Overview history, design philosophy, feedback, getting started.
Core IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP.
Testing Mock Objects, TestContext Framework, Spring MVC Test, WebTestClient.
Data Access Transactions, DAO Support, JDBC, O/R Mapping, XML Marshalling.
Web Servlet Spring MVC, WebSocket, SockJS, STOMP Messaging.
Web Reactive Spring WebFlux, WebClient, WebSocket.
Integration Remoting, JMS, JCA, JMX, Email, Tasks, Scheduling, Caching.
Languages Kotlin, Groovy, Dynamic Languages.

依照以上信息的 Web Servlet、Web Reactive 曾经是分属于不同的模块了。

  • Web Servlet:Spring MVC, WebSocket, SockJS, STOMP Messaging.
  • Web Reactive:Spring WebFlux, WebClient, WebSocket.

Spring 官网文档:https://spring.io/projects/spring-framework#learn/

2、Spring 版本命名规定(补充)

下面提到了 Spring 又不同的版本,在此记录一下各个版本的意义。

形容形式 阐明 含意
Snapshot 快照版 尚不稳固,仍处于开发中的版本
Release 稳定版 性能绝对稳固,能够对外发行,但有工夫限度
GA 正式版 代表宽泛可用的稳定版(General Availability)
M 里程碑版 (M 是 Milestone 的意思)具备一些全新的性能或是有意义的版本
RC 终测版 Release Candidate(最终测试),行将作为正式版公布

二、SpringMVC 流程及原理

1、执行流程

SpringMVC 执行流程图
<font size=4 color=red> 图片起源:三、援用参考资料 </font>

1.1、执行流程

  • 01、用户发送出申请到前端控制器(中央处理器)DispatcherServlet 进行解决。
  • 02、前端控制器 DispatcherServlet 收到申请后,调用处理器映射器 HandlerMapping。
  • 03、处理器映射器 HandlerMapping(处理器映射器)依据 request 申请的 URL 等信息查找可能进行解决的 Handler,以及相干拦截器 interceptor,并结构 HandlerExecutionChain 执行链,而后将结构好的 HandlerExecutionChain 执行链对象返回给前端控制器 DispatcherServlet。
  • 04、前端控制器 DispatcherServlet 依据处理器映射器 HandlerMapping 的
  • 05、处理器适配器 HandlerAdapter 通过适配调用具体的处理器(Handler/Controller),即业务中本人写的 Controller。
  • 06、Controller 解决完后返回 ModelAndView(springmvc 的封装对象,将 model 和 view 封装在一起)给处理器适配器 HandlerAdapter;
  • 07、处理器适配器 HandlerAdapter 将 Controller 执行后果 ModelAndView 返回给前端控制器 DispatcherServlet。
  • 08、前端控制器 DispatcherServlet 调用视图解析器 ViewReslover 解决 ModelAndView。
  • 09、视图解析器 ViewReslover 解析后依据逻辑视图名解析成物理视图名即具体的页面地址,生成并返回具体对象 View(springmvc 封装对象,是一个接口)。
  • 10、前端控制器 DispatcherServlet 依据对象 View 进行视图渲染, 填充 Model。
  • 11、前端控制器 DispatcherServlet 向用户返回响应

1.2、执行流程阐明:

1.2.1、第 02、03 阐明

(1) 处理器映射器:springmvc 框架中的一种对象,框架把实现了 HandlerMapping 接口的类都叫做映射器(多个);

(2) 处理器映射器作用: 依据申请,从 springmvc 容器对象中获取处理器对象(MyController controller = ctx.getBean(“some”)

(3) 框架把找到的处理器对象放到一个叫做处理器执行链 (HandlerExecutionChain) 的类保留

(4) HandlerExecutionchain: 类中保留着
 a:处理器对象(MyController);
 b:我的项目中的所有的拦截器 List<HandlerInterceptor>

(5) 办法调用:HandlerExecutionChain mappedHandler – getHandler (processedRequest);

1.2.2、第 04 阐明

(1) HandlerExecutionChain 执行链找到对应的处理器映射器 HandlerAdapter。
(2) 处理器适配器:springmvc 框架中的对象,须要实现 HandlerAdapter 接口,
(3) 处理器适配器作用:执行处理器办法 (调用 MyController.doSome() 失去返回值 ModelAndView )
(4) 前端控制器中调用适配器:HandlerAdapter ha =getHandlerAdapter (mappedHandler.getHandler());
(5) 执行处理器办法:mv= ha.handle (processedRequest, response, mappedHandler.getHandler());

第 08 阐明:
(1) 视图解析器:springmvc 中的对象,须要实现 ViewResoler 接口(能够有多个)
(2) 视图解析器作用:组成视图残缺门路,应用前缀,后缀。并创立 View 对象。
(3) view 是一个接口,示意视图的,在框架中 jsp,htm1 不是 string 示意,而是应用 view 和他的实现类示意视图。

InternalResourceview:视图类,示意 jsp 文件,视图解析器会创立 InternalResourceView 类对象。这个对象的外面,有一个属性 url-/WEB-INF/view/show.jsp

1.2.2、SpringMVC 组件阐明

  • (1). 前端控制器(DispatcherServlet):接管申请,响应后果,相当于电脑的 CPU。
  • (2). 处理器映射器(HandlerMapping):依据 URL 去查找处理器.
  • (3). 处理器(Handler):(须要程序员去写代码解决逻辑的).
  • (4). 处理器适配器(HandlerAdapter):会把处理器包装成适配器,这样就能够反对多种类型的处理器,类比笔记本的适配器(适配器模式的利用).
  • (5). 视图解析器(ViewResovler):进行视图解析,多返回的字符串,进行解决,能够解析成对应的页面.

1.2.3、SpringMVC 具体流程图

综上所述,总结下 SpringMVC 的具体流程图:


<font size=4 color=red> 图片起源:三、援用参考资料 </font>

二、源码剖析

以下源码起源 jar 包:spring-webmvc-5.25.RELEASE.jar

1、初始化

1.1、ApplicationContext

​ ApplicationContext 初始化入口类:ApplicationObjectSupport 的 setApplicationContext 办法,setApplicationContext 办法中外围局部就是初始化容器 initApplicationContext(context),子类 AbstractDetectingUrlHandlerMapping 实现了该办法。
类图:

UML 图:

​ RequestMappingHandlerMapping , 用于注解 @Controller,@RequestMapping 来定义 controller.
初始化时,3 个类的大抵分工如下:

  • AbstractHandlerMethodMapping 定义整个算法流程;
  • RequestMappingInfoHandlerMapping 提供匹配条件 RequestMappingInfo 的解析解决;
  • RequestMappingHandlerMapping 依据 @RequestMapping 注解生成 RequestMappingInfo, 同时提供 isHandler 实现

2、前端控制器(中央处理器)DistepcherServlet

​ 从下面的流程图能够看到前端控制器(中央处理器)DistepcherServlet 是 SpringMVC 外围,查看 DistepcherServlet 类的继承状况。
UML 图:

从继承关系看出:
​ DistepcherServlet —> FrameworkServlet —> HttpServletBean—> HttpServlet
​ 那就阐明 DistepcherServlet 类也是一个 Servlet 类,那最终外围的办法就是 service()办法,即 Servlet 的外围办法。
​ 那就找 service()办法,在 DistepcherServlet 中没有 servic()办法,在父类 FrameworkServlet 有 service()办法,源码如下:
起源:

org.springframework.web.servlet.FrameworkServlet.service(HttpServletRequest request, HttpServletResponse response)

/**
     * Override the parent class implementation in order to intercept PATCH requests.
     */
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
        if (httpMethod == HttpMethod.PATCH || httpMethod == null) {processRequest(request, response);
        }
        else {super.service(request, response);
        }
    }

能够看到:

FrameworkServlet.service(HttpServletRequest request, HttpServletResponse response)拿到 request 申请,判断以后申请是否是 PATCH 申请,不是的就调用父类的 servic()办法,掉用父类中的 service 办法就是去调用该类中 doPost(),doGet()办法,依据不同的申请形式而后走 doPost()或者 doGet(),调用中以 doGet()为例,

FrameworkServlet 类的 doGet()源码:

/**
     * Delegate GET requests to processRequest/doService.
     * <p>Will also be invoked by HttpServlet's default implementation of {@code doHead},
     * with a {@code NoBodyResponse} that just captures the content length.
     * @see #doService
     * @see #doHead
     */
    @Override
    protected final void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {processRequest(request, response);
    }

​ doGet()又调用 FrameworkServlet 类中的 processRequest(request, response);

/**
     * Process this request, publishing an event regardless of the outcome.
     * <p>The actual event handling is performed by the abstract
     * {@link #doService} template method.
     */
    protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {long startTime = System.currentTimeMillis();
        Throwable failureCause = null;

        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        LocaleContext localeContext = buildLocaleContext(request);

        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

        initContextHolders(request, localeContext, requestAttributes);

        try {doService(request, response);
        }
        catch (ServletException | IOException ex) {
            failureCause = ex;
            throw ex;
        }
        catch (Throwable ex) {
            failureCause = ex;
            throw new NestedServletException("Request processing failed", ex);
        }

        finally {resetContextHolders(request, previousLocaleContext, previousAttributes);
            if (requestAttributes != null) {requestAttributes.requestCompleted();
            }
            logResult(request, response, failureCause, asyncManager);
            publishRequestHandledEvent(request, response, startTime, failureCause);
        }
    }

​ processRequest(request, response)办法中最要害的又调用了 doService(request, response);查看 FrameworkServlet 类中的 doService(request, response),或者是调试跟踪可知,doService(request, response)由子类 DispatcherServlet 实现。

源码起源:

org.springframework.web.servlet.FrameworkServlet.doService(HttpServletRequest request, HttpServletResponse response)

/**
     * Subclasses must implement this method to do the work of request handling,
     * receiving a centralized callback for GET, POST, PUT and DELETE.
     * <p>The contract is essentially the same as that for the commonly overridden
     * {@code doGet} or {@code doPost} methods of HttpServlet.
     * <p>This class intercepts calls to ensure that exception handling and
     * event publication takes place.
     * @param request current HTTP request
     * @param response current HTTP response
     * @throws Exception in case of any kind of processing failure
     * @see javax.servlet.http.HttpServlet#doGet
     * @see javax.servlet.http.HttpServlet#doPost
     */
    protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
            throws Exception;

​ 查看 DispatcherServlet 中的 doService(HttpServletRequest request, HttpServletResponse response)办法

/**
     * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
     * for the actual dispatching.
     */
    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {logRequest(request);

        // Keep a snapshot of the request attributes in case of an include,
        // to be able to restore the original attributes after the include.
        Map<String, Object> attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {attributesSnapshot = new HashMap<>();
            Enumeration<?> attrNames = request.getAttributeNames();
            while (attrNames.hasMoreElements()) {String attrName = (String) attrNames.nextElement();
                if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
        }

        // Make framework objects available to handlers and view objects.
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

        if (this.flashMapManager != null) {FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
            if (inputFlashMap != null) {request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
            }
            request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
            request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
        }

        try {doDispatch(request, response);
        }
        finally {if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                // Restore the original attribute snapshot, in case of an include.
                if (attributesSnapshot != null) {restoreAttributesAfterInclude(request, attributesSnapshot);
                }
            }
        }
    }

​ DispatcherServlet 的 doService()办法中最终调用 doDispatch(request, response),查看源码如下:
org.springframework.web.servlet.DispatcherServlet.doDispatch()

/**
     * Process the actual dispatching to the handler.
     * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
     * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
     * to find the first that supports the handler class.
     * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
     * themselves to decide which methods are acceptable.
     * @param request current HTTP request
     * @param response current HTTP response
     * @throws Exception in case of any kind of processing failure
     */
    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);
                // 获得解决以后申请的 controller, 这里也称为 hanlder 处理器, 第一个步骤的意义就在这里体现了. 这里并不是间接返回 controller, 而是返回的 HandlerExecutionChain 申请处理器链对象, 该对象封装了 handler 和拦截器 interceptors.
                // Determine handler for the current request.
                mappedHandler = getHandler(processedRequest);
                // 如果 handler 为空, 则返回 404
                if (mappedHandler == null) {noHandlerFound(processedRequest, response);
                    return;
                }
                //3. 获取解决 request 的处理器适配器 HandlerAdapter
                // 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;}
                }
                // 处理器适配器执行之前,查看拦截器的办法
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}
                // 处理器适配器依据找到,执行 handler,返回 ModelAndView
                // 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);
                }
            }
        }
    }

​ 能够看出 doDispatch()就是 SpringMVC 的外围代码了,剖析 doDispatch():

2.1、查找处理器映射器 HandlerMapping

​ 首先看下处理器映射器 HandlerMapping 类图:

doDispatch()要害代码:

HandlerExecutionChain mappedHandler = null;

mappedHandler = getHandler(processedRequest);

​ mappedHandler 是一个执行链 HandlerExecutionChain 对象,这里封装了 handler 和拦截器 interceptors,getHandler(processedRequest)办法就是从处理器映射器 HandlerMapping 中找到 url 和 controller 的对应关系,并返回给前端控制器 DispatchServlet。
查看 getHandler(processedRequest); 源码:

/**
     * Return the HandlerExecutionChain for this request.
     * <p>Tries all handler mappings in order.
     * @param request current HTTP request
     * @return the HandlerExecutionChain, or {@code null} if no handler could be found
     */
    @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;
    }

调试代码如下:

从代码调试中能够看到 handlerMapping 中有三个对象:

this.handlerMappings = {ArrayList@4662}  size = 3
 0 = {BeanNameUrlHandlerMapping@4791} 
 1 = {RequestMappingHandlerMapping@4792} 
 2 = {RouterFunctionMapping@4793} 
  • BeanNameUrlHandlerMapping:初始化时会将 urlpath 做映射存储(xml);
  • RequestMappingHandlerMapping:初始化时会将 Controller 中配置 @RequestMapping 注解的办法做映射存储(注解);
  • RouterFunctionMapping:

(这个对象不是太了解)
这也就是为什么要去 HandlerMapping 找一个 Handler 了,因为处理器映射器 HandlerMapping 有不同的实现:

  • 1、xml 形式
  • 2、注解形式

接着看 getHandler(HttpServletRequest request)办法,先遍历 HandlerMappers,查找控制器找到之后就返回执行链 HandlerExecutionChain 类型的 Handler。

能够看到返回的 Handler 中,拿到的就是咱们本人编码的 Controller 类,以及拦截器(演示我的项目中未编写,所以调试汇总返回的 Handler 最初是 0 interceptors)
HandlerExecutionChain with [com.bjpowernode.controller.MyController#doSome()] and 0 interceptors

将正在调试的 idea 关上本人编写的 Controller 来对照,发现统一:

2.2、依据处理器映射器 HandlerMapping 返回后果调用处理器适配器 HandlerAdapter

doDispatch()外面的要害代码:

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

源码如下:

/**
     * Return the HandlerAdapter for this handler object.
     * @param handler the handler object to find an adapter for
     * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
     */
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {if (this.handlerAdapters != null) {for (HandlerAdapter adapter : this.handlerAdapters) {if (adapter.supports(handler)) {return adapter;}
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

为什么还要获取处理器适配器 HandlerAdapter:与获取处理器映射器 HandlerMapping 一样,Spring 提供了不通的处理器适配器。
调试如下:


查看 DEBUG 调试模式中 getHandlerAdapter()办法在中的:
handler、adapter、this.handlerAdapters


以下是拷贝的后果:
handler

handler = {HandlerMethod@4792} "com.bjpowernode.controller.MyController#doSome()"
 logger = {LogAdapter$JavaUtilLog@4858} 
 bean = {MyController@4859} 
 beanFactory = {DefaultListableBeanFactory@4847} "org.springframework.beans.factory.support.DefaultListableBeanFactory@56b5a4c3: defining beans [myController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.web.servlet.view.InternalResourceViewResolver#0]; root of factory hierarchy"
 beanType = {Class@3782} "class com.bjpowernode.controller.MyController"
 method = {Method@4860} "public org.springframework.web.servlet.ModelAndView com.bjpowernode.controller.MyController.doSome()"
 bridgedMethod = {Method@4860} "public org.springframework.web.servlet.ModelAndView com.bjpowernode.controller.MyController.doSome()"
 parameters = {MethodParameter[0]@4861} 
 responseStatus = null
 responseStatusReason = null
 resolvedFromHandlerMethod = {HandlerMethod@4863} "com.bjpowernode.controller.MyController#doSome()"
 interfaceParameterAnnotations = null
 description = "com.bjpowernode.controller.MyController#doSome()"

adapter

adapter = {RequestMappingHandlerAdapter@4827} 
 customArgumentResolvers = null
 argumentResolvers = {HandlerMethodArgumentResolverComposite@4833} 
 initBinderArgumentResolvers = {HandlerMethodArgumentResolverComposite@4834} 
 customReturnValueHandlers = null
 returnValueHandlers = {HandlerMethodReturnValueHandlerComposite@4835} 
 modelAndViewResolvers = null
 contentNegotiationManager = {ContentNegotiationManager@4836} 
 messageConverters = {ArrayList@4837}  size = 4
 requestResponseBodyAdvice = {ArrayList@4838}  size = 0
 webBindingInitializer = null
 taskExecutor = {SimpleAsyncTaskExecutor@4839} 
 asyncRequestTimeout = null
 callableInterceptors = {CallableProcessingInterceptor[0]@4840} 
 deferredResultInterceptors = {DeferredResultProcessingInterceptor[0]@4842} 
 reactiveAdapterRegistry = {ReactiveAdapterRegistry@4844} 
 ignoreDefaultModelOnRedirect = false
 cacheSecondsForSessionAttributeHandlers = 0
 synchronizeOnSession = false
 sessionAttributeStore = {DefaultSessionAttributeStore@4845} 
 parameterNameDiscoverer = {DefaultParameterNameDiscoverer@4846} 
 beanFactory = {DefaultListableBeanFactory@4847} "org.springframework.beans.factory.support.DefaultListableBeanFactory@56b5a4c3: defining beans [myController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.web.servlet.view.InternalResourceViewResolver#0]; root of factory hierarchy"
 sessionAttributesHandlerCache = {ConcurrentHashMap@4848}  size = 0
 initBinderCache = {ConcurrentHashMap@4849}  size = 0
 initBinderAdviceCache = {LinkedHashMap@4850}  size = 0
 modelAttributeCache = {ConcurrentHashMap@4851}  size = 0
 modelAttributeAdviceCache = {LinkedHashMap@4852}  size = 0
 order = 2147483647
 supportedMethods = null
 allowHeader = "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS"
 requireSession = false
 cacheControl = null
 cacheSeconds = -1
 varyByRequestHeaders = null
 useExpiresHeader = false
 useCacheControlHeader = true
 useCacheControlNoStore = true
 alwaysMustRevalidate = false
 servletContext = {ApplicationContextFacade@4754} 
 logger = {LogAdapter$JavaUtilLog@4854} 
 applicationContext = {XmlWebApplicationContext@4665} "WebApplicationContext for namespace'myweb-servlet', started on Tue Mar 02 23:25:35 CST 2021"
 messageSourceAccessor = {MessageSourceAccessor@4855} 

this.handlerAdapters

this.handlerAdapters = {ArrayList@4658}  size = 4
 0 = {HttpRequestHandlerAdapter@4810} 
 1 = {SimpleControllerHandlerAdapter@4820} //XML 形式
 2 = {RequestMappingHandlerAdapter@4827} // 注解形式
 3 = {HandlerFunctionAdapter@4832} 

能够看到找到 4 个处理器适配器。通过 DEBUG 模式能够看到,此次取到的处理器适配器 HandlerAdapter 是:RequestMappingHandlerAdapter

ha = {RequestMappingHandlerAdapter@4827} 

2.3、查看拦截器 Interceptor

doDispatch()中的要害代码:

if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}
org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle

applyPreHandle(processedRequest, response)源码:

/**
     * Apply preHandle methods of registered interceptors.
     * @return {@code true} if the execution chain should proceed with the
     * next interceptor or the handler itself. Else, DispatcherServlet assumes
     * that this interceptor has already dealt with the response itself.
     */
    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {for (int i = 0; i < interceptors.length; i++) {HandlerInterceptor interceptor = interceptors[i];
                if (!interceptor.preHandle(request, response, this.handler)) {triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }

2.3、处理器适配器 HandlerAdapter 执行 Handler(Controller)返回 ModelAndView

doDispatch()中的要害代码:

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

DEBUG 模式调试,是跳到了:
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
源码如下:

/**
     * This implementation expects the handler to be an {@link HandlerMethod}.
     */
    @Override
    @Nullable
    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {return handleInternal(request, response, (HandlerMethod) handler);
    }

再往下看 handleInternal(request, response, (HandlerMethod) handler)办法,
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal

@Override
    protected ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        ModelAndView mav;
        checkRequest(request);

        // Execute invokeHandlerMethod in synchronized block if required.
        if (this.synchronizeOnSession) {HttpSession session = request.getSession(false);
            if (session != null) {Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {mav = invokeHandlerMethod(request, response, handlerMethod);
                }
            }
            else {
                // No HttpSession available -> no mutex necessary
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            // No synchronization on session demanded at all...
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }

        if (!response.containsHeader(HEADER_CACHE_CONTROL)) {if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
            }
            else {prepareResponse(response);
            }
        }

        return mav;
    }

留神,handleInternal(request, response, (HandlerMethod) handler)办法的返回值是 ModelAndView,这里就实现了处理器适配器 HandlerAdapter 执行 Handler(Controller)并将后果 ModelAndView 返回给前端控制器 DistepchServlet

2.4、视图解析器 ViewResolver

  接上 2.3:前端控制器 DistepchServlet 接管到处理器适配器 HandlerAdapter 返回的 ModelAndView 当前,这里分 2 种状况:

  • (1)、如果 ModelAndView 外面是逻辑视图

前端控制器 DistepchServlet 调用视图解析器 ViewResolver 通过逻辑视图查找真正的视图对象 View,并返回给前端控制器 DistepchServlet。

  • (2)、如果 ModelAndView 外面是非逻辑视图:

如:MappingJackson2JsonView(把以后数据转为为 JSON 数据,并不需要对视图逻辑名称进行转换)

总结一下:
视图解析器 ViewResolver 接口次要作用是解析前端控制器 DispatcherServlet 传递的逻辑视图名,并将解析后果的真正的视图对象 View 传回给前端控制器 DispatcherServlet

ViewResolverd 的实现类:


ViewResolver 的 UML:

2.5、视图 View

2.5.1、视图对象的作用

  • (1)、将控制器返回的数据处理渲染,最终返回客户端展现给用户,次要就是实现转发或者是重定向的操作.。
  • (2)、为了实现视图模型和具体实现技术的解耦(指的是 Spring 在 org.springframework.web.servlet 包中定义的形象 View 接口),详见 2.5.2View 接口图。
  • (3)、视图对象 View 由视图解析器负责实例化。因为视图是无状态(每一次申请都会创立一个新的 view 对象)的,所以不会有线程平安的问题.

2.5.2、View 接口图

2.5.3、View 的实现类图

2.5.4、View 的 UML 图

.png)

2.5.5、罕用的 View 视图类

视图类型 简介
URL 视图资源图 InternalResourceView 将 JSP 或其余资源封装成一个视图。被视图解析器 InternalResourceViewResolver 默认应用。
JstlView InternalResourceView 的子类。如果 JSP 中应用了 JSTL 的国际化标签,就须要应用该视图类。
文档视图 AbstractExcelView Excel 文档视图的抽象类。
AbstractPdfView PDF 文档视图的抽象类
报表视图 ConfigurableJasperReportsView 罕用的 JasperReports 报表视图
JasperReportsHtmlView
JasperReportsPdfView
JasperReportsXlsView
JSON 视图 MappingJackson2JsonView 将数据通过 Jackson 框架的 ObjectMapper 对象,以 JSON 形式输入

2.6、其余重要的点

2.6.1、DispatcherServlet.properties

DispatcherServlet.properties 文件是在 SpringMVC 架包中:

DispatcherServlet.properties 内容:

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=
    org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=
    org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=
    org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
    org.springframework.web.servlet.function.support.RouterFunctionMapping

org.springframework.web.servlet.HandlerAdapter=
    org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
    org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
    org.springframework.web.servlet.function.support.HandlerFunctionAdapter


org.springframework.web.servlet.HandlerExceptionResolver=
    org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
    org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
    org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=
    org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=
    org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=
    org.springframework.web.servlet.support.SessionFlashMapManager

SpringMVC 为什么能加载不同处理器映射器 HandlerMapping、处理器适配器 handlerAdapter,就是因为框架配置了这个 DispatcherServlet.properties 文件。

三、援用参考资料

1、援用材料

  • SpringMVC 流程图援用地址:https://www.iqiyi.com/w_19s2gmyazh.html
  • SpringMVC 流程图援用地址 2:https://blog.csdn.net/win7system/article/details/90674757
  • View 视图作用援用地址:https://blog.csdn.net/qq_43193797/article/details/84928603
  • Spring 官网文档:https://spring.io/projects/spring-framework#learn/

    在写此文的时候可能还有少部分是参考了其余材料,然而整顿的时候我曾经找不到原文出处了,如果原文作者看到,请及时分割我,我在文章中加上援用出处,谢谢!

2、参考资料

  • 参考:w3cschool-Spring MVC 4.2.4.RELEASE 中文文档:

    https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/

  • 参考:https://www.cnblogs.com/leftthen/category/790002.html

免责申明:

 本文中应用的局部图片来自于网络(地址见:三、援用参考资料),如有侵权, 请分割博主进行删除。

转载申明:

** 写博客不易,请尊重原作者!!**
欢送大家浏览、转载,如果是 ** 整文转载 ** 请在文章结尾或者结尾处 ** 注明 原文地址、作者 **,如果是 ** 大段参考 ** 请 ** 备注 参考链接 **。

正文完
 0