详述 Spring MVC 的核心组件

 2022-07-26
原文作者:程序员青峰

简介

SpringMVC的核心都是围绕着前端调度器-DispatcherServlet设计的,DispatcherServlet负责请求统一的调度,实际的工作交给相应的组件执行,各司其职,如下图:

202207262312279781.png

SpringMVC请求流程

组件

DispatcherServlet

DispatcherServlet-前端调度器 负责拦截前端的请求 然后分发到各个处理器的方法中

HandlerMapping

处理器映射器负责通过请求的url 匹配 对应的执行器链。

HandlerAdapter

处理器适配器,负责执行处理器的具体方法,返回ModelAndView

ModelAndView

封装视图和数据

ViewReslover

解析ModelAndView 返回view

现在大部分项目都是前后端分离以JSON的方式进行数据交互,所以后面我们重点讲解DispatcherServlet、HandlerMapping、HandlerAdapter 这三个组件。

源码

202207262312291622.png

DispatcherServlet 类图

dispatcherServlet 是Servlet的一个实现类吗,所以在请求进来时会进入到Servlet#Service方法,然后根据类图 一顿分析 可以得出 请求会进入到 DispatcherServlet#doService方法

doService

入口函数
:org.springframework.web.servlet#doService

    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logRequest(request);
        .....省略代码
        try {
            // 调度逻辑找到了 继续跟
            doDispatch(request, response);
        }
        .....省略代码
    }
    

doDispatch

请求调度开始
:org.springframework.web.servlet#doDispatch

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ..... 代码省略 
    
        HandlerExecutionChain mappedHandler = null;
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
            try {
                // 检查是否为文件上传
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
    
                // 根据reaquest 获取处理器链 
                //  HandlerExecutionChain 对象 除了处理器handler 还包含拦截器等其他信息
                mappedHandler = getHandler(processedRequest);
    
                if (mappedHandler == null) {
                    // url没有对应的处理器 返回404  noHandlerFound 此处简单逻辑大家自己跟一下就好了
                    noHandlerFound(processedRequest, response);
                    return;
                }
    
                // 根据处理器获取到处理器适配器 为后面执行处理器准备
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                ..... 代码省略 
                //  执行处理器链 中 拦截器的 preHandle 方法
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    // false直接返回
                    return;
                }
    
                //  处理器适配器执行具体的 处理器方法 返回 ModelAndView
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                // 设置viewName
                applyDefaultViewName(processedRequest, mv);
                //  执行处理器链 中 拦截器的 postHandle 方法
                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);
            }
            // 5.解析并渲染视图ModelAndView 正常执行拦截器afterCompletion 方法
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            // 异常执行拦截器afterCompletion 方法
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            // 异常执行拦截器afterCompletion 方法
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        ..... 代码省略 
    }
    

processDispatchResult

渲染视图
:org.springframework.web.servlet#processDispatchResult

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
                @Nullable Exception exception) throws Exception {
    
        .....省略代码
    
        if (mv != null && !mv.wasCleared()) {
            // 渲染视图 
            render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        }
        .....省略代码
        if (mappedHandler != null) {
            // 执行拦截器 afterCompletion 方法
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }
    
    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    
        ...
    
        View view;
        String viewName = mv.getViewName();
        if (viewName != null) {
            // 此处会获取 视图解析器 viewResolvers 解析视图
            view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
            if (view == null) {
                throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
                        "' in servlet with name '" + getServletName() + "'");
            }
        }
        ...
    
        try {
            if (mv.getStatus() != null) {
                response.setStatus(mv.getStatus().value());
            }
            // 渲染视图
            view.render(mv.getModelInternal(), request, response);
        }
        catch (Exception ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error rendering view [" + view + "]", ex);
            }
            throw ex;
        }
    }
    

总结

本文将SpringMVC 整体的一个请求流程粗略的过了一遍,主要分下面几个步骤

  1. DispatcherServlet#doDispatch: 前端控制器开始调度请求流程.
  2. getHandler(processedRequest): 根据request 获取处理器 mappedHandler( HandlerExecutionChain 对象包括拦截器)
  3. getHandlerAdapter(mappedHandler.getHandler()): 根据处理器获取处理器适配器 ha
  4. mappedHandler.applyPreHandle(): 执行mappedHandler中拦截器的preHandle 方法
  5. ha.handle(): 处理器适配器 执行 处理器方法 返回视图
  6. mappedHandler.applyPostHandle() 执行mappedHandler中拦截器的postHandle 方法
  7. processDispatchResult():解析视图然后进行视图渲染 返回给客户端