【Spring MVC 源码学习一】 核心流程

流程说明直接看源码理解起来会比较吃力,先放张图在这,让我们对核心处理流程有个初步印象。前端控制器dispacherServlet是spring mvc框架的核心类,控制整个请求处理的逻辑,由它调用HanlderMapping 、 HandlerAdapter、ViewResolver和View组件的方法完成请求的处理流程。开始读源码1,准备工作首先spring mvc框架把刚用户请求交...
摘要由CSDN通过智能技术生成

流程说明

直接看源码理解起来会比较吃力,先放张图在这,让我们对spring mvc核心处理流程有个初步印象。
在这里插入图片描述
前端控制器DispacherServlet是spring mvc框架的核心类,控制整个请求处理的逻辑,由它调用HanlderMappingHandlerAdapterViewResolverView组件的方法完成请求的处理流程。

开始读源码

1,准备工作

首先spring mvc框架把刚用户请求交给DispacherServlet类的doService方法对请求进行初步加工

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
	//一些准备工作
	...
	//将spring上下文信息存储至request,方便后面的处理器和视图用到
	request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
	// 存储其他框架信息
	...
	//分发请求
    try {
      doDispatch(request, response);
    }
    // 后续工作
    ...
}

2,开始分发请求

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
   HandlerExecutionChain mappedHandler = null;
   int interceptorIndex = -1;

   try {
      ModelAndView mv;
      boolean errorView = false;

      try {
         processedRequest = checkMultipart(request);

         // 步骤1,获取请求的处理器(handler)
         // Determine handler for the current request
         mappedHandler = getHandler(processedRequest, false);
         if (mappedHandler == null || mappedHandler.getHandler() == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // 步骤2,获取支持处理器的适配器(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 (logger.isDebugEnabled()) {
               String requestUri = urlPathHelper.getRequestUri(request);
               logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
            }
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
               return;
            }
         }

         // Apply preHandle methods of registered interceptors.
         HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
         if (interceptors != null) {
            for (int i = 0; i < interceptors.length; i++) {
               HandlerInterceptor interceptor = interceptors[i];
               if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
                  triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
                  return;
               }
               interceptorIndex = i;
            }
         }

         // 步骤3,调用适配器的handle方法处理请求
         // Actually invoke the handler.
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         // Do we need view name translation?
         if (mv != null && !mv.hasView()) {
            mv.setViewName(getDefaultViewName(request));
         }

         // Apply postHandle methods of registered interceptors.
         if (interceptors != null) {
            for (int i = interceptors.length - 1; i >= 0; i--) {
               HandlerInterceptor interceptor = interceptors[i];
               interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
            }
         }
      }
      catch (ModelAndViewDefiningException ex) {
         logger.debug("ModelAndViewDefiningException encountered", ex);
         mv = ex.getModelAndView();
      }
      catch (Exception ex) {
         Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
         mv = processHandlerException(processedRequest, response, handler, ex);
         errorView = (mv != null);
      }

      // 步骤4,将mv中的模型数据填充(渲染)到response中
      // Did the handler return a view to render?
      if (mv != null && !mv.wasCleared()) {
         render(mv, processedRequest, 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");
         }
      }

      // Trigger after-completion for successful outcome.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
   }

   catch (Exception ex) {
      // Trigger after-completion for thrown exception.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
      throw ex;
   }
   catch (Error err) {
      ServletException ex = new NestedServletException("Handler processing failed", err);
      // Trigger after-completion for thrown exception.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
      throw ex;
   }

   finally {
      // Clean up any resources used by a multipart request.
      if (processedRequest != request) {
         cleanupMultipart(processedRequest);
      }
   }
}

步骤1

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   for (HandlerMapping hm : this.handlerMappings) {
      if (logger.isTraceEnabled()) {
         logger.trace(
               "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
      }
      HandlerExecutionChain handler = hm.getHandler(request);
      if (handler != null) {
         return handler;
      }
   }
   return null;
}

HandlerMapping是一个请求路径(URL)与处理器(Handler)的映射表。spring有多种处理请求的处理器,常用的如HttpRequestHandler, Controller等,因此也有多个HandlerMapping。getHandler方法中,遍历每种HandlerMapping直到获取到,获取的结果是一个HandlerExecutionChain对象,他包含了Handler和各种配置的处理器拦截器(HandlerInterceptor)

步骤2

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
   for (HandlerAdapter ha : this.handlerAdapters) {
      if (logger.isTraceEnabled()) {
         logger.trace("Testing handler adapter [" + ha + "]");
      }
      if (ha.supports(handler)) {
         return ha;
      }
   }
   throw new ServletException("No adapter for handler [" + handler +
         "]: Does your handler implement a supported interface like Controller?");
}

根据处理器获取处理器适配器(HandlerAdaptor),这里用到了适配器模式,我另外一篇学习笔记中单独写了SpringMVC中的适配器模式,这里就不展开了。也是用遍历的方法,调用处理器适配器的supports方法判断适配器是否支持处理器,直到找到为止

步骤3
调用处理器适配器的handler方法,内部是调用具体处理器的处理方法,返回ModelAndView对象。此时ModelAndView中,只有Model即数据对象,没有视图对象View

步骤4

 protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
        response.setLocale(locale);
        String viewName = mv.getViewName();
        View view;
        if (viewName != null) {
           // 步骤4.1 根据视图名称,获取视图对象View
            view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
            if (view == null) {
                throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
            }
        } else {
            view = mv.getView();
            if (view == null) {
                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
            }
        }

        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'");
        }

        try {
            if (mv.getStatus() != null) {
                response.setStatus(mv.getStatus().value());
            }
            // 步骤4.2 调用视图对象的render方法,将数据模型model以视图规定的格式填充到response中
            view.render(mv.getModelInternal(), request, response);
        } catch (Exception var8) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'", var8);
            }

            throw var8;
        }
    }

步骤4.1

    @Nullable
    protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
        if (this.viewResolvers != null) {
            Iterator var5 = this.viewResolvers.iterator();

            while(var5.hasNext()) {
                ViewResolver viewResolver = (ViewResolver)var5.next();
                View view = viewResolver.resolveViewName(viewName, locale);
                if (view != null) {
                    return view;
                }
            }
        }

        return null;
    }

遍历视图解析器集合ViewResolvers获取视图。视图解析器使用到了策略模式,在我的另外一篇学习笔记中有关于SpingMVC中策略模式的说明。
常用的视图解析器是内容协商解析器ContentNegotiatingViewResolver,它不自己解析视图,而是委托给defaultViews属性中关联的视图去解析。可以自己实现View接口加到defaultViews中。

步骤4.2
视图对象的render方法,将数据Model按照视图规定的格式填充到response中。到此已经得到可以返回给客户的响应。

总结流程及组件

spring mvc处理请求的流程和用到的组件,总结为如下脑图
在这里插入图片描述

参考资料

1, SpringMVC 官方中文文档
2, SpringMVC系列(一)核心:处理请求流程
3, SpringMVC执行流程及工作原理

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值