SpringMVC源码解析之RequestMappingHandlerAdapter(下)

简介: SpringMVC源码解析之RequestMappingHandlerAdapter(下)

handleInternal

使用给定的处理器方法处理请求。

AbstractHandlerMethodAdapter中定义的 protected 抽象方法,专门由该子类实现。

开始处理请求,返回一个ModelAndView。

@Override
protected ModelAndView handleInternal(HttpServletRequest request, 
    HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  ModelAndView mav;
  checkRequest(request);
  // 如果需要,在同步块中执行invokeHandlerMethod,默认不
  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);
  }
  // 处理Cache-Control请求头(若你没有set
  if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
    if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
      applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
    } else {
      prepareResponse(response);
    }
  }
  return mav;
}

剩下的便是本适配器最为重要的一个方法:invokeHandlerMethod():

  // 它的作用就是执行目标的HandlerMethod,然后返回一个ModelAndView 
  @Nullable
  protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    // 注意:此处只有try-finally 哦
    // 因为invocableMethod.invokeAndHandle(webRequest, mavContainer)是可能会抛出异常的(交给全局异常处理)
    try {
      // 最终创建的是一个ServletRequestDataBinderFactory,持有所有@InitBinder的method方法们
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      // 创建一个ModelFactory,@ModelAttribute啥的方法就会被引用进来
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
      // 把HandlerMethod包装为ServletInvocableHandlerMethod,具有invoke执行的能力喽
      // 下面这几部便是一直给invocableMethod的各大属性赋值~~~
      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      if (this.argumentResolvers != null) {
        invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      }
      if (this.returnValueHandlers != null) {
        invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
      }
      invocableMethod.setDataBinderFactory(binderFactory);
      invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
      ModelAndViewContainer mavContainer = new ModelAndViewContainer();
      // 把上个request里的值放进来到本request里
      mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
      // model工厂:把它里面的Model值放进mavContainer容器内(此处@ModelAttribute/@SessionAttribute啥的生效)
      modelFactory.initModel(webRequest, mavContainer, invocableMethod);
      mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
      AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
      asyncWebRequest.setTimeout(this.asyncRequestTimeout);
      WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      asyncManager.setTaskExecutor(this.taskExecutor);
      asyncManager.setAsyncWebRequest(asyncWebRequest);
      asyncManager.registerCallableInterceptors(this.callableInterceptors);
      asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
      // 它不管是不是异步请求都先用AsyncWebRequest 包装了一下,但是若是同步请求
      // asyncManager.hasConcurrentResult()肯定是为false的~~~
      if (asyncManager.hasConcurrentResult()) {
        Object result = asyncManager.getConcurrentResult();
        mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
        asyncManager.clearConcurrentResult();
        LogFormatUtils.traceDebug(logger, traceOn -> {
          String formatted = LogFormatUtils.formatValue(result, !traceOn);
          return "Resume with async result [" + formatted + "]";
        });
        invocableMethod = invocableMethod.wrapConcurrentResult(result);
      }
      // 此处其实就是调用ServletInvocableHandlerMethod#invokeAndHandle()方法喽
      // 关于它你可以来这里:https://fangshixiang.blog.csdn.net/article/details/98385163
      // 注意哦:任何HandlerMethod执行完后都是把结果放在了mavContainer里(它可能有Model,可能有View,可能啥都木有~~)
      // 因此最后的getModelAndView()又得一看
      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      if (asyncManager.isConcurrentHandlingStarted()) {
        return null;
      }
      return getModelAndView(mavContainer, modelFactory, webRequest);
    } finally {
      webRequest.requestCompleted();
    }
  }
任何处理器执行完后,最终返回的的都是一个ModelAndView对象,这得益于getModelAndView()这个方法的适配处理:
  // @Nullable:表示它返回的可以是个null哦~(若木有视图,就直接不会render啦~因为response已经写入过值了)
  @Nullable
  private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
    // 把session里面的内容写入
    modelFactory.updateModel(webRequest, mavContainer);
    // Tips:若已经被处理过,那就返回null喽~~(比如若是@ResponseBody这种,这里就是true)
    if (mavContainer.isRequestHandled()) {
      return null;
    }
    // 通过View、Model、Status构造出一个ModelAndView,最终就可以完成渲染了
    ModelMap model = mavContainer.getModel();
    ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
    if (!mavContainer.isViewReference()) { // 是否是String类型
      mav.setView((View) mavContainer.getView());
    }
    // 对重定向RedirectAttributes参数的支持(两个请求之间传递参数,使用的是ATTRIBUTE)
    if (model instanceof RedirectAttributes) {
      Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
      HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
      if (request != null) {
        RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
      }
    }
    return mav;
  }

执行完HandlerMethod后得到一个ModelAndView,它可能是null(比如已被处理过),那最终交给DispatcherServlet就没有后续处理了,否则会做视图渲染:render()。


Spring MVC默认装配了哪些HandlerAdapter呢?

开启@EnableWebMvc:

总结

RequestMappingHandlerAdapter作为HandlerAdapter适配模式的实现,由于@RequestMapping成为了使用Spring MVC的几乎唯一选择,所以它成为了实际意义上的标准实现

目录
相关文章
|
4天前
|
缓存 Java 开发者
10个点介绍SpringBoot3工作流程与核心组件源码解析
Spring Boot 是Java开发中100%会使用到的框架,开发者不仅要熟练使用,对其中的核心源码也要了解,正所谓知其然知其所以然,V 哥建议小伙伴们在学习的过程中,一定要去研读一下源码,这有助于你在开发中游刃有余。欢迎一起交流学习心得,一起成长。
|
5天前
|
安全 网络协议 Java
Netty核心NioEventLoop源码解析(下)
Netty核心NioEventLoop源码解析(下)
19 0
|
5天前
|
算法 Java 索引
Netty核心NioEventLoop源码解析(上)
Netty核心NioEventLoop源码解析(上)
18 0
|
5天前
|
消息中间件 缓存 前端开发
Netty消息编码及发送源码解析
Netty消息编码及发送源码解析
7 0
|
7天前
|
移动开发 网络协议 Java
Netty解码器源码解析
Netty解码器源码解析
12 0
|
7天前
|
SQL XML Java
Mybatis源码解析
Mybatis源码解析
18 0
|
8天前
|
SQL 缓存 Java
|
8天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
10天前
|
安全 Java Shell
Android13 adb input 调试命令使用和源码解析
Android13 adb input 调试命令使用和源码解析
17 0
Mixtral MOE 部分源码解析
Mixtral MOE 部分源码解析
15 0

推荐镜像

更多