DiapatcherServlet

SpringMVC的前端控制器(dispatcherServlet)本质就是一个Servlet,它接收并处理除了jsp页面之外的所有请求,其主要功能就是匹配并调用请求对应的controller控制器(处理器),并将控制器处理后的 ModelAndView(数据和视图) 进行渲染后响应给客户端

DispatcherServlet继承于HTTPServlet。当有请求发来时,首先执行HttpServletdoGet/doPost方法,而FrameworkServlet子类重写了doGet/doPost方法,并在其中调用了processRequest方法,而processRequest方法中又调用了抽象方法doService,该抽象方法是被DispatcherServlet实现,并在其中调用了doDispatch方法,doDispatch方法便是前端控制器(DispathcerServlet) 的核心方法,以下是该方法的分析:



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 {
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            // ①检查是否为多部件(文件上传)请求
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            /** ②根据请求地址确定相应的控制器(处理器)映射对象 **/
            // Determine handler for the current request.
            mappedHandler = getHandler(processedRequest);
            // ③如果没有找到对应的控制器来处理这个请求,则报404
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            /** ④根据控制器映射对象确定对应的适配器,该适配器(反射工具)用于调用控制器方法 **/
            // 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;
            }

            /** ⑥使用之前获取的适配器来调用控制器的业务方法,也就是Controller中的@RequestMapping方法,
            	并在执行完成后返回视图名。无论控制器业务方法中执行什么,
            	最终适配器调用完后的数据(模型和视图)都封装成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);
        }
        /** ⑧根据封装了数据和视图的ModelAndView处理转发的页面 **/
        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);
            }
        }
    }
}

其中第②、④、⑥、⑧步为关键:

getHandler()获取目标控制器

getHandlerAdapter()获取执行目标控制器方法的适配器

handle()使用适配器执行目标控制器方法

processDispatchResult处理转发结果



getHandler()
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;
}

handlerMappings是存放根据不同方式注册(xml配置和注解装配) 的处理器映射的集合。其中索引0为xml配置注册的,索引1为注解注册的(索引2暂时未知)。遍历handlerMappings,找到其中保存有handler的元素(HandlerMapping)并返回。

而使用注解的处理器对象就是索引为1的RequestMappingHandlerMapping处理器映射

这个注解处理器映射对象中有一个mappingRegistry属性,便是存放使用@RequestMapping注解配置的处理器的信息。

IOC容器启动创建Controller对象时,扫描每个处理器都能处理什么请求,并将这些处理器都保存在mappingRegistry属性中,以后发送的请求中,查找哪个HandlerMapping中有对应处理器即可。



getHandlerAdapter()
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");
}

此方法同上面的getHandler()一样,是遍历存放有不同注册方式的处理器对应的适配器,找到支持当前处理器对应的适配器

其中RequestMappingHandlerAdapter是通过注解注册的处理器对应的适配器,当遍历到它时,当前处理器会和它匹配然后返回这个适配器



handle()
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {

    return handleInternal(request, response, (HandlerMethod) handler);
}

通过适配器调用其抽象父类(AbstractHandlerMethodAdapter)的handle方法,其中又直接调用适配器(RequestMappingHandlerAdapter)的handleInternal()方法

handleInternal()

{

    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()方法中的第22行执行了invokeHandlerMethod(request, response, handlerMethod)方法,此方法就是实际调用的处理器方法,得到处理后的ModelAndView并返回。



processDispatchResult()
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
                                   @Nullable Exception exception) throws Exception {

    boolean errorView = false;

    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        }
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    // Did the handler return a view to render?
    if (mv != null && !mv.wasCleared()) {
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {
        if (logger.isTraceEnabled()) {
            logger.trace("No view rendering, null ModelAndView returned.");
        }
    }

    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        // Concurrent handling started during a forward
        return;
    }

    if (mappedHandler != null) {
        // Exception (if any) is already handled..
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

在第21行调用的render()方法,使用ModelAndView对转发的页面进行渲染

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐