SpringMVC源码分析(二)

本文详细剖析了SpringMVC的请求处理流程,从DispatcherServlet的启动到HandlerAdapter的调用,再到ModelAndView的渲染过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  上一篇博文SpringMVC源码分析(一) 中已经对SpringMVC中的Servlet(GenericServlet,HttpServlet,HttpServletBean,FrameworkServlet,DispatcherServlet)源码进行分析,今天接着分析SpringMVC请求处理过程。

  SpringMVC请求处理过程主要由DispatchServlet来负责完成,FrameworkServlet是DispatchServlet的父类,先看一下FrameWorkServlet的处理请求过程。
  
  当接收到请求时会调用service方法,代码如下:

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
        if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
            processRequest(request, response);//如果请求方式是PATCH时直接调用
        }
        else {
            super.service(request, response);//调用父类的service方法,也就是HttpServlet的service方法
        }
    }

  service方法中会根据请求类型选择处理方式,比如get请求就会调用doGet()方法,
FrameworkServlet中重写doGet()方法,代码如下:

@Override
    protected final void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        processRequest(request, response);
    }

  所以最后会调用processRequest处理请求,processRequest是FrameworkServlet类处理请求的核心方法。

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;
        //获取LocalContextHolder中保存LocalContext(保存了本地化信息,比如zh-cn)
        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        //获取当前请求的LocalContext(保存了本地化信息,比如zh-cn)
        LocaleContext localeContext = buildLocaleContext(request);
        //获取RequestContextHolder保存的RequestAttributes
        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        //获取当前请求的RequestAttributes
        ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
        //将当前的LocalContext和RequestAttributes分别放置到LocalContextHolder和RequestContextHolder中
        initContextHolders(request, localeContext, requestAttributes);

        try {
            //实际处理请求的入口
            doService(request, response);//在DispatchServlet中实现
        }
        catch (ServletException ex) {
            failureCause = ex;
            throw ex;
        }
        catch (IOException ex) {
            failureCause = ex;
            throw ex;
        }
        catch (Throwable ex) {
            failureCause = ex;
            throw new NestedServletException("Request processing failed", ex);
        }

        finally {
            //恢复原来的LocalContext和ServletRequestAttributes到LocalContextHolder和RequestContextHolder中
            resetContextHolders(request, previousLocaleContext, previousAttributes);
            if (requestAttributes != null) {
                requestAttributes.requestCompleted();//执行完这个方法后isRequestActive()返回值为false
            }

            if (logger.isDebugEnabled()) {
                if (failureCause != null) {
                    this.logger.debug("Could not complete request", failureCause);
                }
                else {
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        logger.debug("Leaving response open for concurrent processing");
                    }
                    else {
                        this.logger.debug("Successfully completed request");
                    }
                }
            }
            //发送servletRequestHandlerEvent消息
            publishRequestHandledEvent(request, response, startTime, failureCause);
        }
    }

  ServletRequestAttributes中封装了我们平时使用setAttribute和getAttribute方法,根据scope参数来判断是request还是session。

    @Override
    public void setAttribute(String name, Object value, int scope) {
        if (scope == SCOPE_REQUEST) {
            if (!isRequestActive()) {//上面调用了requestCompleted之后就会变为false也就是不进行操作了
                throw new IllegalStateException(
                        "Cannot set request attribute - request is not active anymore!");
            }
            this.request.setAttribute(name, value);
        }
        else {
            HttpSession session = getSession(true);
            this.sessionAttributesToUpdate.remove(name);
            session.setAttribute(name, value);
        }
    }

  publishRequestHandledEvent方法是请求处理结束后会发出消息,无论请求是否成功都会发出。

  接下来继续看service()处理请求,service方法会调用doService方法,doService是个模板方法,DispatcherServlet中重写了这个方法,我们转到ServletDispatcherServlet上分析处理请求过程,DispatcherServlet是Spring 的最核心的类。整个处理请求的过程的顶层设计都在这里。我们来看看DispatcherServlet的doService方法。

@Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (logger.isDebugEnabled()) {
            String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
            logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
                    " processing " + request.getMethod() + " request for [" + getRequestUri(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;
        //当include请求时把request中的atrribute备份一份
        if (WebUtils.isIncludeRequest(request)) {
            attributesSnapshot = new HashMap<String, Object>();
            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());//设置webApplication
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);//设置localResolver
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);//设置themeResolver
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());//设置themeResource

        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);//用于redirect中attribute的数据传递
        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) {
                    //还原request中的attribute
                    restoreAttributesAfterInclude(request, attributesSnapshot);
                }
            }
        }
    }

  继续追踪doDispatch方法,doDispatch主要的任务是根据request找到Handler,根据handler找到相对应的HandlerAdapter,用HandlerAdapter处理Handler,最后把结果通过processDispatchResult()返回,实现代码如下:

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);//通过请求找到handler(这里的handler就是我们说的Controller中处理请求的方法)
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);//没有找到handler则调用此方法处理
                    return;
                }

                // Determine handler adapter for the current request.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//通过handler找到HandlerAdapter

                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();//获取请求方式
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    //处理GET、HEAD请求的Last-Modified
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                //执行相应Interceptor的preHandler方法
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                //handlerAdapter使用handler处理请求
                // Actually invoke the handler.
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                //当View为空时,比如我们写的Controller中处理请求的方法为空时,根据request的设置view
                applyDefaultViewName(processedRequest, mv);
                //执行相应Intercerptor的postHandler方法
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {

                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            //返回处理结果,包括异常处理、渲染页面、发出通知出发Interceptor的afterCompletion方法
            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方法中的核心工作就是
  1.根据当前Request找到handler;
  2.根据Handler找到对应的HandlerAdapter;
  3.使用HandlerAdapter处理handler
  4.调用processDispatchResult方法处理上面请求之后的结果

补充几个重要的概念:
  Handler:也就是处理器,他直接对应着MVC的Controller层,他的表现形式很多,标注了@RequestMapping的所有方法都可以看出一个handler,只要能处理实际请求的就可以是Handler。
  HandlerMapping:用来查找Handler的,SpringMVC的请求很多,每个请求都需要一个handler来处理,收到的请求由那个handler来处理就由HandlerMapping来确定。
  HandlerAdapter:他就是一个适配器,SpringMVC中handler的形式可以任意,主要能处理请求就OK,但是Servlet处理请求的方法结构是固定的。如何让固定的servlet处理方法调用灵活的handler来处理就由HandlerAdapter来实现。

  接着分析handlerAdpter中调用handler方法处理请求。

public interface HandlerAdapter {
    //判断是否可以用某个handler
    boolean supports(Object handler);
    //具体使用Handler处理请求
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
    //返回LastModified的值
    long getLastModified(HttpServletRequest request, Object handler);
}

我们只要实现HandlerAdapter接口就可以处理请求,SimpleControllerHandlerAdapter实现了HandlerAdapter,实现代码如下:

public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    //判断是否可以用某个handler
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof Controller);
    }
    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        //调用Controller接口中的handleRequest方法,我们如果继承了Controller接口就需要重写这个方法,然后在里面处理逻辑即可。
        return ((Controller) handler).handleRequest(request, response);
    }
    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }
}

  请求处理完的结果会封装在ModelAndView中,我们通过processDispatchResult方法把结果渲染到页面中,实现代码如下:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            HandlerExecutionChain mappedHandler, ModelAndView mv, 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.isDebugEnabled()) {
                logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                        "': assuming HandlerAdapter completed request handling");
            }
        }

        if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Concurrent handling started during a forward
            return;
        }
        //发出请求处理完成的通知,出发Interceptor的afterCompletion
        if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }

  在render方法中会去查找视图解析器,然后转化成View类型的视图(比如jsp,html,freemaker等)显示在页面上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值