HandlerAdapter体系

HandlerAdapter接口

* supports(Object handler)

  适配器模式的固定接口,表示是否支持对此Object handler进行适配调用

* ModelAndView handle

  向外统一暴露的接口方法,其方法内的实现,不同的底层Object handler有不同的方法

* getLastModified

 为了支持HTTP的缓存机制,进行服务器资源是否修改的判断,通常请求为get方法且会携带If-Modified-Since头

public interface HandlerAdapter {
    boolean supports(Object var1);
    ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
    long getLastModified(HttpServletRequest var1, Object var2);
}

实现类

* 上一步获取的Handler处理器有多种,所以需要一个接口进行适配,主要的处理器适配器有:

RequestMappingHandlerAdapter:处理基于@RequstMapping注解的处理器

SimpleControllerHandlerAdapter:处理基于实现Controller接口或者Controller子类的处理器

HttpRequestHandlerAdapter:处理访问静态资源的请求

  等等

SimpleControllerHandlerAdapter

* 例如BeanNameUrlHandlerMapping 支持使用容器bean的名称进行匹配

其中对应的处理器bean是需要实现Controller接口的


@FunctionalInterface
public interface Controller {
    @Nullable
    ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}

public class myController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView mv = new ModelAndView();
        mv.setViewName("KAKA");
        return mv;
    }
}

* SimpleControllerHandlerAdapter的实现

  - supports基于实现Controller接口或者Controller子类的处理器

  - handle底层就是直接调用((Controller) handler).handleRequest(request, response)


public class SimpleControllerHandlerAdapter implements HandlerAdapter {

   @Override
   public boolean supports(Object handler) {
      return (handler instanceof Controller);
   }

   @Override
   @Nullable
   public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
         throws Exception {

      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;
   }

}

HandlerFunctionAdapter

* 对RouterFunctionMapping中收集的基于RouterFunction类型的处理器

是轻量级函数式编程模型,其中函数用于路由和处理请求
  @Bean
  public RouterFunction<ServerResponse> student() {
      return route()
            .GET("/student/{id}", accept(MediaType.APPLICATION_JSON), request -> {
                    return ServerResponse.ok().body("name = " + request.param("name").get()) ;})
            .build() ;
  }

* HandlerFunctionAdapter


public class HandlerFunctionAdapter implements HandlerAdapter, Ordered {

    private int order = Ordered.LOWEST_PRECEDENCE;
    
    @Override
    public boolean supports(Object handler) {
        return handler instanceof HandlerFunction;
    }

    @Nullable
    @Override
    public ModelAndView handle(HttpServletRequest servletRequest,
                               HttpServletResponse servletResponse,
                               Object handler) throws Exception {
        //handler转为HandlerFunction后,调用其handle(serverRequest),在使用serverResponse.writeTo即可
        HandlerFunction<?> handlerFunction = (HandlerFunction<?>) handler;
        ServerRequest serverRequest = getServerRequest(servletRequest);
        ServerResponse serverResponse = handlerFunction.handle(serverRequest);

        return serverResponse.writeTo(servletRequest, servletResponse,
                new org.springframework.web.servlet.function.support.HandlerFunctionAdapter.ServerRequestContext(serverRequest));
    }

    ...
}

RequestMappingHandlerAdapter实现类

概述

* AbstractHandlerMethodAdapter只是简单的增加了order的支持,其他核心方法都需要子类实现

  子类需要实现supportsInternal(在RequestMappingHandlerAdapter直接返回true)和handleInternal方法

  @Override
public final boolean supports(Object handler) {
   return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

protected abstract boolean supportsInternal(HandlerMethod handlerMethod);

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

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

@Nullable
protected abstract ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;

...

}

主要成员变量


// ======================相关成员变量们======================
 // 装载RequestBodyAdviceResponseBodyAdvice的实现类们~
private List<Object> requestResponseBodyAdvice = new ArrayList<>();

// @ModelAttribute注解相关
// 这里意思是:含有@ModelAttribute,但是但是但是不含有@RequestMapping注解的方法~~~~~
public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method -> (!AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) && AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class));
// 存储标注了@ModelAttribute注解的方法的缓存~~~~
private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap<>();

//@InitBinder注解相关
// 标注了注解@InitBinder的方法~~~
public static final MethodFilter INIT_BINDER_METHODS = method -> AnnotatedElementUtils.hasAnnotation(method, InitBinder.class);
// 存储标注了@InitBinder注解的方法的缓存~~~~
private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap<>();

//参数相关解析器
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
private HandlerMethodArgumentResolverComposite argumentResolvers;
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;

//返回值相关解析器
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;

//ModelAndView解析器
private List<ModelAndViewResolver> modelAndViewResolvers;

//mediaTypes、消息转换支持器
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
private List<HttpMessageConverter<?>> messageConverters;

//其他
private WebBindingInitializer webBindingInitializer;
private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync");
private Long asyncRequestTimeout;
private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0];
private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor[0];
private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance();
private boolean ignoreDefaultModelOnRedirect = false;
private int cacheSecondsForSessionAttributeHandlers = 0;
private boolean synchronizeOnSession = false;
private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
private ConfigurableBeanFactory beanFactory;
private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64);

afterPropertiesSet收集@ControllerAdvice和参数/结果解析器

实现了InitializingBean的afterPropertiesSet()方法,

* 从容器中获取添加@ControllerAdvice注解的实例使用ControllerAdviceBean封装起来,且排序,进行遍历每一个ControllerAdviceBean控制器增强对象

  - 找到添加了@ModelAttributed但没有@RequestMapping的方法加入到Map<ControllerAdviceBean,Set<Method>> modelAttributeAdviceCache

  - 找到添加@InitBinder的方法,加入到Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache

  - 如果此实例实现了ResponseBodyAdvice/RequestBodyAdvice接口的对象,会加入List<Object> requestResponseBodyAdvice

* 创建默认的参数解析器组合(存在上下顺序)

  - 基于注解的参数,例如@RequestParam、、@PathVariable、@ModelAttribute、@RequestBody等

  - 基于类型的参数,ServletRequest、HttpSession、InputStream、ServletResponse、HttpEntity、Model等

- 用户定义的类型

- 设置最后兜底(可处理所有类型)

* 创建默认的Binder绑定参数解析器组合,它默认支持的比参数解析器少一些

  支持@RequestParam、@PathVariable、@PathVariable等,不支持@RequestBody、@ModelAttributed、@RequestPart等

* 创建默认的结果解析器组合

  - 基于返回类型的处理,如ModelAndView、HttpEntity、DeferredResult等

  - 基于注解,如标注了@ModelAttribute、@esponseBody

  - Map、CharSequence或者void的返回类型

  - 自定义

public void afterPropertiesSet() {
    this.initControllerAdviceCache();
    List handlers;
    if (this.argumentResolvers == null) {
        handlers = this.getDefaultArgumentResolvers();
        this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
    }

    if (this.initBinderArgumentResolvers == null) {
        handlers = this.getDefaultInitBinderArgumentResolvers();
        this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
    }

    if (this.returnValueHandlers == null) {
        handlers = this.getDefaultReturnValueHandlers();
        this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
    }

}


public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext context) {
   List<ControllerAdviceBean> adviceBeans = new ArrayList<>();
   for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, Object.class)) {
      if (!ScopedProxyUtils.isScopedTarget(name)) {
         ControllerAdvice controllerAdvice = context.findAnnotationOnBean(name, ControllerAdvice.class);
         if (controllerAdvice != null) {
            // Use the @ControllerAdvice annotation found by findAnnotationOnBean()
            // in order to avoid a subsequent lookup of the same annotation.
            adviceBeans.add(new ControllerAdviceBean(name, context, controllerAdvice));
         }
      }
   }
   OrderComparator.sort(adviceBeans);
   return adviceBeans;
}


  private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
      List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

      //基于注解的参数,例如@RequestParam@RequestBody@PathVariable
      resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
      resolvers.add(new RequestParamMapMethodArgumentResolver());
      resolvers.add(new PathVariableMethodArgumentResolver());
      resolvers.add(new PathVariableMapMethodArgumentResolver());
      resolvers.add(new MatrixVariableMethodArgumentResolver());
      resolvers.add(new MatrixVariableMapMethodArgumentResolver());
      resolvers.add(new ServletModelAttributeMethodProcessor(false));
      resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
      resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
      resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
      resolvers.add(new RequestHeaderMapMethodArgumentResolver());
      resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
      resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
      resolvers.add(new SessionAttributeMethodArgumentResolver());
      resolvers.add(new RequestAttributeMethodArgumentResolver());

      //基于类型的参数,ServletRequestHttpSessionInputStreamServletResponseHttpEntityModel
      resolvers.add(new ServletRequestMethodArgumentResolver());
      resolvers.add(new ServletResponseMethodArgumentResolver());
      resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
      resolvers.add(new RedirectAttributesMethodArgumentResolver());
      resolvers.add(new ModelMethodProcessor());
      resolvers.add(new MapMethodProcessor());
      resolvers.add(new ErrorsMethodArgumentResolver());
      resolvers.add(new SessionStatusMethodArgumentResolver());
      resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

      // 用户定义的类型
      if (getCustomArgumentResolvers() != null) {
          resolvers.addAll(getCustomArgumentResolvers());
      }

      //设置默认
      resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
      resolvers.add(new ServletModelAttributeMethodProcessor(true));

      return resolvers;
  }

  //同上,只不过少了一些
  private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
      List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

      // Annotation-based argument resolution
      resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
      resolvers.add(new RequestParamMapMethodArgumentResolver());
      resolvers.add(new PathVariableMethodArgumentResolver());
      resolvers.add(new PathVariableMapMethodArgumentResolver());
      resolvers.add(new MatrixVariableMethodArgumentResolver());
      resolvers.add(new MatrixVariableMapMethodArgumentResolver());
      resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
      resolvers.add(new SessionAttributeMethodArgumentResolver());
      resolvers.add(new RequestAttributeMethodArgumentResolver());

      // Type-based argument resolution
      resolvers.add(new ServletRequestMethodArgumentResolver());
      resolvers.add(new ServletResponseMethodArgumentResolver());

      // Custom arguments
      if (getCustomArgumentResolvers() != null) {
          resolvers.addAll(getCustomArgumentResolvers());
      }

      // Catch-all
      resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));

      return resolvers;
  }

  //
  private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
      List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();

      // 基于返回类型的处理,如ModelAndViewHttpEntity
      handlers.add(new ModelAndViewMethodReturnValueHandler());
      handlers.add(new ModelMethodProcessor());
      handlers.add(new ViewMethodReturnValueHandler());
      handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
              this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
      handlers.add(new StreamingResponseBodyReturnValueHandler());
      handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
              this.contentNegotiationManager, this.requestResponseBodyAdvice));
      handlers.add(new HttpHeadersReturnValueHandler());
      handlers.add(new CallableMethodReturnValueHandler());
      handlers.add(new DeferredResultMethodReturnValueHandler());
      handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

      //基于注解,如标注了@ModelAttribute@esponseBody
      handlers.add(new ModelAttributeMethodProcessor(false));
      handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
              this.contentNegotiationManager, this.requestResponseBodyAdvice));

      //MapCharSequence或者void的返回类型
      handlers.add(new ViewNameMethodReturnValueHandler());
      handlers.add(new MapMethodProcessor());

      //自定义
      if (getCustomReturnValueHandlers() != null) {
          handlers.addAll(getCustomReturnValueHandlers());
      }

      // Catch-all
      if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
          handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
      }
      else {
          handlers.add(new ModelAttributeMethodProcessor(true));
      }

      return handlers;
  }

handleInternal方法主流程

实现了handleInternal方法,其内调用invokeHandleMethod以处理核心逻辑

HandlerAdapter.handle -> AbstractHandlerMethodAdapter.handleInternal(略) -> RequestMappingHandlerAdapter->invokeHandleMethod

具体解析见下节:执行HandlerAdapter.handle(以RequestMappingHandlerAdapter为例)

* 把原生request和response封装为ServletWebRequest ,主要提供一些属性处理方法,如果getSession

* 获取数据绑定工厂WebDataBinderFactory ,会收集所有@initBinder方法作为绑定对象,在后续进行类型转换的时候可能会用到

* 把最初的handlerMethod封装为ServletInvocableHandlerMethod,增加了参数解析和返回结果处理的功能

* 数据模型ModelAndView的处理,包括数据模型处理工厂ModelFactory 和ModelAndViewContainer 的创建和设置

* 异步请求的处理

* 调用ServletInvocableHandlerMethod.invokeAndHandle,先进行参数解析,再对结果进行处理

private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    //再次封装了TomcatHttpServletRequestHttpServletResponse,主要提供属性处理,集中了requestsessiond
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    //数据绑定工厂,会收集所有@initBinder方法作为绑定对象,
    WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
    //数据模型处理工厂
    ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
    //把最初的handlerMethod封装为ServletInvocableHandlerMethod,增加了参数解析和返回结果处理的功能
    ServletInvocableHandlerMethod requestMappingMethod = this.createRequestMappingMethod(handlerMethod, binderFactory);
    //ModelAndView模块的处理
    ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
    modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
    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);
    if (asyncManager.hasConcurrentResult()) {
        Object result = asyncManager.getConcurrentResult();
        mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
        asyncManager.clearConcurrentResult();
        requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
    }
    //调用ServletInvocableHandlerMethod,先进行参数解析,再对结果进行处理
    requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);

//进行ModelAndView处理
    return asyncManager.isConcurrentHandlingStarted() ? null : this.getModelAndView(mavContainer, modelFactory, webRequest);
}

执行拦截器链的前置方法

使用HandlerExecutionChain的applyPreHandle方法

* 获取当前HandlerExecutionChain处理器执行链的配置的拦截器集合

* 遍历每一个拦截器的applyPreHandle,当有一个失败时返回false中断处理,

在调用triggerAfterCompletion,会逆序调用每一个拦截器的afterCompletion清理作用

@Nullable
public HandlerInterceptor[] getInterceptors() {
   if (this.interceptors == null && this.interceptorList != null) {
      this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]);
   }
   return this.interceptors;
}

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
   if (getInterceptors() != null) {
      for (int i = 0; i < getInterceptors().length; i++) {
         HandlerInterceptor interceptor = getInterceptors()[i];
         if (!interceptor.preHandle(request, response, this.handler)) {
            triggerAfterCompletion(request, response, null);
            return false;
         }
         this.interceptorIndex = i;
      }
   }
   return true;
}


void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
      throws Exception {
   if (getInterceptors() == null) {
      return;
   }
   for (int i = this.interceptorIndex; i >= 0; i--) {
      HandlerInterceptor interceptor = getInterceptors()[i];
      interceptor.afterCompletion(request, response, this.handler, ex);
   }
}

执行HandlerAdapter.handle(以RequestMappingHandlerAdapter为例)

概述

实现了handleInternal方法,其内调用invokeHandleMethod以处理核心逻辑

HandlerAdapter.handle -> AbstractHandlerMethodAdapter.handleInternal() -> RequestMappingHandlerAdapter->invokeHandleMethod

* 把原生request和response封装为ServletWebRequest ,主要提供一些属性处理方法,如果getSession

* 获取数据绑定工厂WebDataBinderFactory ,会收集所有@initBinder方法作为绑定对象,在后续进行类型转换的时候可能会用到

* 把最初的handlerMethod封装为ServletInvocableHandlerMethod,增加了参数解析和返回结果处理的功能

* 数据模型ModelAndView的处理,包括数据模型处理工厂ModelFactory 和ModelAndViewContainer 的创建和设置

* 异步请求的处理

* 调用ServletInvocableHandlerMethod.invokeAndHandle,先进行参数解析,再对结果进行处理

private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    //再次封装了TomcatHttpServletRequestHttpServletResponse,主要提供属性处理,集中了requestsessiond
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    //数据绑定工厂,会收集所有@initBinder方法作为绑定对象,
    WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
    //数据模型处理工厂
    ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
    //把最初的handlerMethod封装为ServletInvocableHandlerMethod,增加了参数解析和返回结果处理的功能
    ServletInvocableHandlerMethod requestMappingMethod = this.createRequestMappingMethod(handlerMethod, binderFactory);
    //ModelAndView模块的处理
    ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
    modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
    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);
    if (asyncManager.hasConcurrentResult()) {
        Object result = asyncManager.getConcurrentResult();
        mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
        asyncManager.clearConcurrentResult();
        requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
    }
    //调用ServletInvocableHandlerMethod,先进行参数解析,再对结果进行处理
    requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);

//进行ModelAndView处理
    return asyncManager.isConcurrentHandlingStarted() ? null : this.getModelAndView(mavContainer, modelFactory, webRequest);
}

获取WebDataBinderFactory数据绑定工厂

创建工厂流程

* 在RequestMappingHandlerAdapter.invokeHandleMethod中调用getDataBinderFactory经获取WebDataBinderFactory,

  会先遍历@ControllerAdvice类中的,和本@Controller类中的方法@InitBinder注解的所有方法。封装为InvocableHandlerMethod缓存起来

* 在把上一步的方法集合作为参数创建数据绑定工厂createDataBinderFactory(initBinderMethods);

  把@InitBinder注解的方法和类封装为InvocableHandlerMethod即可,因为只需要进行方法的参数解析

  在使用WebDataBinder.convertIfNecessary进行转换获取(这一步骤详情见上几节),这里就会优先用到上一步注册的自定义转换器,进行类型转换

private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
    //当前控制器类对象,即添加了@Controller注解的类对象,获取其中添加了@InitBinder注解的所有方法
    Class<?> handlerType = handlerMethod.getBeanType();
    Set<Method> methods = (Set)this.initBinderCache.get(handlerType);
    if (methods == null) {
        methods = HandlerMethodSelector.selectMethods(handlerType, INIT_BINDER_METHODS);
        this.initBinderCache.put(handlerType, methods);
    }

    //RequestMappingHandlerAdapterafterPropertiesSet初始化的所有添加@ControllerAdvice类中添加@InitBinder注解的所有方法
    List<InvocableHandlerMethod> initBinderMethods = new ArrayList();
    Iterator var5 = this.initBinderAdviceCache.entrySet().iterator();

    //代码略,先遍历@ControllerAdvice类中的,在@Controller类中的方法@InitBinder注解的所有方法。封装为InvocableHandlerMethod缓存起来
    initBinderMethods.add(this.createInitBinderMethod(bean, method));
    

return this.createDataBinderFactory(initBinderMethods);


}

//@InitBinder注解的方法和类封装为InvocableHandlerMethod即可,因为只需要进行方法的参数解析
private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {
   InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
   if (this.initBinderArgumentResolvers != null) {
      binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
   }
   binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
   binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
   return binderMethod;
}

//最终创建的ServletRequestDataBinderFactory,会把RequestMappingHandlerAdapter里用户设置的WebBindingInitializer传递过去
//WebBindingInitializer默认为ConfigurableWebBindingInitializer,是用于自定义配置最终使用的WebDataBinder绑定器

protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods) throws Exception {
    return new ServletRequestDataBinderFactory(binderMethods, this.getWebBindingInitializer());
}

@InitBinder使用实例

最终转为添加自定义的PropertyEditor

(1)举例使用

public class StringToListPropertyEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        String[] resultArr = null;
        if (!StringUtils.isEmpty(text)) {
            resultArr = text.split("_");
        }
        setValue(resultArr);
    }
}

@RequestMapping("/myStringToList")
@Controller
public class StringToListController {

    @InitBinder
    public void myStringToListBinder(WebDataBinder dataBinder) {
        dataBinder.registerCustomEditor(String[].class, new StringToListPropertyEditor());
    }

    //请求strToListArr = 1_2_3
    @RequestMapping(value = "/test", method = RequestMethod.GET)
    @ResponseBody
    public String myStringToListTest(String[] strToListArr, HttpServletResponse response) {
        return Arrays.asList(strToListArr).toString();//返回数组{123}
    }
}

工厂使用的时机

一般在参数解析解析的节点,在获取到指定参数对应原始值后,必要的时候会用到数据绑定工厂进行类型转换,如下@RequestParam解析棋类继承抽象解析类:

* 先使用工厂创建一个WebDataBinder对象(见其他章节),并对其进行初始化,收集所有符合@InitBinder注解方法,执行方法体。

其最终目的就是为传递进去的dataBinder设置自定义的转换器

   @InitBinder
        public void myStringToListBinder(WebDataBinder dataBinder) {
            dataBinder.registerCustomEditor(String[].class, new StringToListPropertyEditor());
        }

* 在使用WebDataBinder.convertIfNecessary进行转换获取(这一步骤详情见上几节),这里就会优先用到上一步注册的自定义转换器,进行类型转换

WebDataBinder最终使用委托类TypeConverterDelegate,TypeConverterDelegate在处理最终转换的时候,

会用到PropertyEditorRegistrySupport 收集的默认和用户自定义的Editor和Conversion

public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {

   //略

   @Override
   public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
         NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

      Class<?> paramType = parameter.getParameterType();
      NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
      Object arg = resolveName(namedValueInfo.name, parameter, webRequest);
     

       //略


      if (binderFactory != null) {
         WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
         arg = binder.convertIfNecessary(arg, paramType, parameter);
      }

      handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
      return arg;
   }

}

public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
        throws Exception {
    WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
    //执初始化器,比如为dataBinder设置自定义的ConversionService
    if (this.initializer != null) {
        this.initializer.initBinder(dataBinder, webRequest);
    }
    //找到对应的@InitBinder注解方法,解析参数,最终执行方法
    initBinder(dataBinder, webRequest);
    return dataBinder;
}


public void initBinder(WebDataBinder binder, NativeWebRequest request) throws Exception {
    for (InvocableHandlerMethod binderMethod : this.binderMethods) {
        //如果注解内有指定name就需要进校验,没有就为共用的
        if (isBinderMethodApplicable(binderMethod, binder)) {
            //这个和解析控制器@RquestMapping方法一样,目的就是为了执行方法
            Object returnValue = binderMethod.invokeForRequest(request, null, binder);
            if (returnValue != null) {
                throw new IllegalStateException("@InitBinder methods should return void: " + binderMethod);
            }
        }
    }
}

获取ModelFactory数据模型处理工厂

* 先获取类上@SessionAttribute注解的信息,取name和type,封装到SessionAttributesHandler

* 再获取本类上添加了@ModelAttribute且没有@RequestMapping的方法

  这些方法标可以用于把方法结果作为一个或多个属性添加到Model上

* 再获取modelAttributeAdviceCache事先收集的全局controllerAdviceBean中实例

  - 调用其controllerAdviceBean.isApplicableToBeanType(handlerType),一般为相同包路径,相同类型、相同注解即可匹配

  - 类匹配的话,即可收集controllerAdviceBean上添加了@ModelAttribute且没有@RequestMapping的方法

* 在把上一步的方法集合作为参数创建数据绑定工厂createModelAttributeMethod

  把@ModelAttribut注解的方法和类封装为InvocableHandlerMethod即可,因为只需要进行方法的参数解析

* 组合创建ModelFactory(attrMethods, binderFactory, sessionAttrHandler)返回接口

    

private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
   SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
   Class<?> handlerType = handlerMethod.getBeanType();
   Set<Method> methods = this.modelAttributeCache.get(handlerType);
   if (methods == null) {
      methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
      this.modelAttributeCache.put(handlerType, methods);
   }
   List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
   // Global methods first
   this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
      if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
         Object bean = controllerAdviceBean.resolveBean();
         for (Method method : methodSet) {
            attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
         }
      }
   });
   for (Method method : methods) {
      Object bean = handlerMethod.getBean();
      attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
   }
   return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}

private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) {
   InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method);
   if (this.argumentResolvers != null) {
      attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
   }
   attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
   attrMethod.setDataBinderFactory(factory);
   return attrMethod;
}

把HandlerMethod封装为ServletInvocableHandlerMethod

* ServletInvocableHandlerMethod 增加了参数解析和返回结果处理的功能

  所以ServletInvocableHandlerMethod需要设置参数解析器、返回结果解析器、以及参数名称发现器

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);

  

private ServletInvocableHandlerMethod createRequestMappingMethod(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
    ServletInvocableHandlerMethod requestMethod = new ServletInvocableHandlerMethod(handlerMethod);
    //需要4个关联组件

requestMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
    requestMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
    requestMethod.setDataBinderFactory(binderFactory);
    requestMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    return requestMethod;
}

* 三者关系

* HandlerMethod

- 在HandlerMappings初始化的时候就会对指定的控制器方法封装为HandlerMethod对象,主要封装了如下信息

private final Object bean; //控制器类对象

private final BeanFactory beanFactory;

private final Method method;  //控制器方法

private final Method bridgedMethod;

private final MethodParameter[] parameters; //控制器方法参数

@RequestMapping(value = "/list", headers = "",consumes = "")
@ResponseBody
public List<User> list() {
         //..
         return List<User> users = userService.list();;
}

* InvocableHandlerMethod

- 封装了参数解析器组合的处理

- 提供invokeForRequest方法,借助HandlerMethodArgumentResolver集合和DataBinderFactory数据转换工厂

先进行一个个的参数解析,获取最终的参数列表,才反射调用方法

* ServletInvocableHandlerMethod

- 封装了结果解析器组合的处理

- 提供invokeAndHandle方法,,借助HandlerMethodReturnValueHandlers集合和DataBinderFactory数据转换工厂对结果解析

创建ModelAndViewContainer并初始化

ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

ModelAndViewContainer介绍

* ModelAndViewContainer可以把它定义为ModelAndView上下文的容器,它承担着整个请求过程中的数据传递工作–>保存着Model和View

  - 它维护了模型model:包括defaultModle和redirectModel

   defaultModel是默认使用的Model,redirectModel是用于传递redirect时的Model

  - 在Controller处理器入参写了Model或ModelMap类型时候,实际传入的是defaultModel。

   defaultModel它实际是BindingAwareModel,底层就是个Map。而且继承了ModelMap又实现了Model接口,所以在处理器中使用Model或ModelMap时,其实都是使用同一个对象~~~

   可参考MapMethodProcessor,它最终调用的都是mavContainer.getModel()方法

  - 若处理器入参类型是RedirectAttributes类型,最终传入的是redirectModel。

- 维护视图view(兼容支持逻辑视图名称)

  - 维护是否redirect信息,及根据这个判断HandlerAdapter使用的是defaultModel或redirectModel

  - 维护@SessionAttributes注解信息状态

  - 维护handler是否处理标记(重要)

    例如在最后的getModelAndView方法会判断此属性,如果ModelAndViewContainer已经被处理过,此处直接返回null,也就是不会再继续处理Model和View了~

public class ModelAndViewContainer {
    // =================它所持有的这些属性还是蛮重要的=================
    // redirect,是否忽略defaultModel 默认值是false:不忽略
    private boolean ignoreDefaultModelOnRedirect = false;
    // 此视图可能是个View,也可能只是个逻辑视图String
    @Nullable
    private Object view;
    // defaultModel默认的Model
    // 注意:ModelMap 只是个Map而已,但是实现类BindingAwareModelMap它却实现了org.springframework.ui.Model接口
    private final ModelMap defaultModel = new BindingAwareModelMap();
    // 重定向时使用的模型(提供set方法设置进来)
    @Nullable
    private ModelMap redirectModel;
    // 控制器是否返回重定向指令
    // 如:使用了前缀"redirect:xxx.jsp"这种,这个值就是true。然后最终是个RedirectView
    private boolean redirectModelScenario = false;
    // Http状态码
    @Nullable
    private HttpStatus status;

    private final Set<String> noBinding = new HashSet<>(4);
    private final Set<String> bindingDisabled = new HashSet<>(4);

    // 很容易想到,它和@SessionAttributes标记的元素有关
    private final SessionStatus sessionStatus = new SimpleSessionStatus();
    // 这个属性老重要了:标记handler是否**已经完成**请求处理
    // 在链式操作中,这个标记很重要
    private boolean requestHandled = false;
   ...

    public void setViewName(@Nullable String viewName) {
        this.view = viewName;
    }
    public void setView(@Nullable Object view) {
        this.view = view;
    }
    // 是否是视图的引用
    public boolean isViewReference() {
        return (this.view instanceof String);
    }

    // 是否使用默认的Model
    private boolean useDefaultModel() {
        return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect));
    }

    // 注意子方法和下面getDefaultModel()方法的区别
    public ModelMap getModel() {
        if (useDefaultModel()) { // 使用默认视图
            return this.defaultModel;
        } else {
            if (this.redirectModel == null) { // 若重定向视图为null,就new一个空的返回
                this.redirectModel = new ModelMap();
            }
            return this.redirectModel;
        }
    }
    // @since 4.1.4
    public ModelMap getDefaultModel() {
        return this.defaultModel;
    }

    // @since 4.3 可以设置响应码,最终和ModelAndView一起被View渲染时候使用
    public void setStatus(@Nullable HttpStatus status) {
        this.status = status;
    }

    // 以编程方式注册一个**不应**发生数据绑定的属性,对于随后声明的@ModelAttribute也是不能绑定的
    // 虽然方法是set 但内部是add  ~~~~
    public void setBindingDisabled(String attributeName) {
        this.bindingDisabled.add(attributeName);
    }
    public boolean isBindingDisabled(String name) {
        return (this.bindingDisabled.contains(name) || this.noBinding.contains(name));
    }
    // 注册是否应为相应的模型属性进行数据绑定
    public void setBinding(String attributeName, boolean enabled) {
        if (!enabled) {
            this.noBinding.add(attributeName);
        } else {
            this.noBinding.remove(attributeName);
        }
    }

    // 这个方法需要重点说一下:请求是否已在处理程序中完全处理
    // 举个例子:比如@ResponseBody标注的方法返回值,无需View继续去处理,所以就可以设置此值为true
    // 说明:这个属性也就是可通过源生的ServletResponseOutputStream来达到同样效果的
    public void setRequestHandled(boolean requestHandled) {
        this.requestHandled = requestHandled;
    }
    public boolean isRequestHandled() {
        return this.requestHandled;
    }

    // =========下面是Model的相关方法了==========
    // addAttribute/addAllAttributes/mergeAttributes/removeAttributes/containsAttribute
}

initModel方法为Model初始化属性

modelFactory.initModel(webRequest, mavContainer, invocableMethod);

会获取到当前方法,所需要的属性值,在保存到mavContainer上下文中

①获取SessionAttributesHandler里名先获取类上明确指定的@SessionAttribute的信息,即name和type,这里的数据以及封装在modelFactory了

  再从request对象里获取会话中对应的属性值,加入到ModelAndViewContainer的model中,底层执行request.getAttribute(name, WebRequest.SCOPE_SESSION);

②执行工厂收集到的@ModelAttribute方法

  把注解上的name属性作为name,为空默认为返回类型的泛型+类型名,

方法返回值作为vaule

设置到ModelAndViewContainer中

③遍历处理器handlerMethod上的标注ModelAttribute注解的参数,如果在①中获得的不存在,那么尝试从从request对象里获取会话中对应的属性值,

不存在报错,存在再加入到ModelAndViewContainer中


public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod)
        throws Exception {

    //获取SessionAttributesHandler里名先获取类上@SessionAttribute的信息,即nametype
    //request对象里获取会话中对应的属性值,加入到ModelAndViewContainer
    //request.getAttribute(name, WebRequest.SCOPE_SESSION);
    Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
    container.mergeAttributes(sessionAttributes);
    //执行工厂收集到的@ModelAttribute方法
    //注解上的name属性作为name,为空默认为返回类型的泛型+类型名,方法放入返回值作为vaule
    invokeModelAttributeMethods(request, container);

    //遍历处理器handlerMethod上的标注ModelAttribute注解且同时是@SessionAttributesHandler里面指定存在的会话属性
    //作为从request对象里获取会话中对应的属性值,加入到ModelAndViewContainer
    for (String name : findSessionAttributeArguments(handlerMethod)) {
        if (!container.containsAttribute(name)) {
            Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
            if (value == null) {
                throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
            }
            container.addAttribute(name, value);
        }
    }
}


public Map<String, Object> retrieveAttributes(WebRequest request) {
   Map<String, Object> attributes = new HashMap<>();

//knownAttributeNames即为收集到的类上@SessionAttributes信息
   for (String name : this.knownAttributeNames) {
      Object value = this.sessionAttributeStore.retrieveAttribute(request, name);
      if (value != null) {
         attributes.put(name, value);
      }
   }
   return attributes;
}

@Override
@Nullable
public Object retrieveAttribute(WebRequest request, String attributeName) {

//getAttributeNameInSession默认返回attributeName
   String storeAttributeName = getAttributeNameInSession(request, attributeName);

//从底层的请求对象中获取
   return request.getAttribute(storeAttributeName, WebRequest.SCOPE_SESSION);
}


private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container)
      throws Exception {

   while (!this.modelMethods.isEmpty()) {
      InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();
      ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class);
      if (container.containsAttribute(ann.name())) {
         if (!ann.binding()) {
            container.setBindingDisabled(ann.name());
         }
         continue;
      }

      Object returnValue = modelMethod.invokeForRequest(request, container);
      if (!modelMethod.isVoid()){
         String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
         if (!ann.binding()) {
            container.setBindingDisabled(returnValueName);
         }
         if (!container.containsAttribute(returnValueName)) {
            container.addAttribute(returnValueName, returnValue);
         }
      }
   }
}

private List<String> findSessionAttributeArguments(HandlerMethod handlerMethod) {
   List<String> result = new ArrayList<>();
   for (MethodParameter parameter : handlerMethod.getMethodParameters()) {
      if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
         String name = getNameForParameter(parameter);
         Class<?> paramType = parameter.getParameterType();
         if (this.sessionAttributesHandler.isHandlerSessionAttribute(name, paramType)) {
            result.add(name);
         }
      }
   }
   return result;
}

异步请求WebAsyncManager的处理(略)

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);

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

执行InvocableMethod.invokeAndHandle方法

整体流程

* 调用invokeForRequest(webRequest, mavContainer)获取处理的返回值,此时不带providedArgs

  - 会先进行参数解析,对参数进行赋值

  - 反射执行处理器内容,返回结果

* 判断处理器是否结束

  如果结束,就直接return,而不必走后续的流程

* 调用handleReturnValue,处理返回值,返回处理后的结果

  

//RequestMappingHandlerAdapter

invocableMethod.invokeAndHandle(webRequest, mavContainer);

//ServletInvocableHandlerMethod

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {

//解析参数、执行处理器方法,返回结果
    Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);

//结果处理(见下节)
setResponseStatus(webRequest);
if (returnValue == null) {
   if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
      mavContainer.setRequestHandled(true);
      return;
   }
}
else if (StringUtils.hasText(this.responseReason)) {
   mavContainer.setRequestHandled(true);
   return;
}
mavContainer.setRequestHandled(false);
try {
   this.returnValueHandlers.handleReturnValue(
         returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {throw ex;}

}

参数解析

主要流程

* 从对应的HandlerMethod处理器方法对象获取对应的参数信息数组MethodParameter[] parameters,这里封装了每一个参数的注解、参数类型等信息。

使用Spring自带的MethodParameter来获取方法参数信息(有缓存处理),会使用一些native方法、字节码解析等获取方法信息,而不是反射

* 遍历每一个MethodParameter参数对象,设置下参数名称、参数类型的辅助解析对象

* 如果方法参数的类型,在providedArgs中存在,那直接获取(这里是处理@Initbandler时会用到),而无需在参数解析器处理

* 在参数解析器组合找到第一个合适的,调用其resolveArgument方法进行解析,返回结果

* 解析后的参数数组作为参数,对方法进行反射调用获取返回值

//InvocableHandlerMethod

public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {
    //参数解析核心方法
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    //反射调用
    Object returnValue = doInvoke(args);
    return returnValue;
}

//参数解析核心方法
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
                                         Object... providedArgs) throws Exception {
    //从底层HandlerMethod获取控制器方法的参数列表
    MethodParameter[] parameters = getMethodParameters();
    Object[] args = new Object[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
        MethodParameter parameter = parameters[i];
        //设置参数名称发现对象
        parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
        //设置参数对象的参数类型
        GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
        //是否提前返回providedArgs
        args[i] = resolveProvidedArgument(parameter, providedArgs);
        if (args[i] != null) {
            continue;
        }
        //在参数解析器组合找到第一个合适的,进行解析即可
        if (this.argumentResolvers.supportsParameter(parameter)) {
            try {
                args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
                continue;
            }
            catch (Exception ex) {
                throw ex;
            }
        }
        if (args[i] == null) {throw new IllegalStateException(msg);
        }
    }
    return args;
}

默认的参数解析器列表(顺序由上往下)

(1)基于注解的参数


    * RequestParamMethodArgumentResolver(getBeanFactory(), false)); 

- 支持条件:@RequestParam(value="sum",defaultValue="10" , required=false) int sum

类型MultipartFile/Part、内嵌/集合类型为MultipartFile/Part

    - 取值处理:name优先取@RequestParam注解的,否则取参数名称

                从multipartRequest.getFile(name)、r equest.getParameterValues(name)(url + 表单参数值)

                使用WebDataBinder进行必要的类型转换(不必对对象内部属性转换)

* RequestParamMapMethodArgumentResolver());   

- 支持条件:@RequestParam Map<String,String> map

- 取值逻辑同上


    * PathVariableMethodArgumentResolver()); 

- 支持条件:@PathVariable("username") String username

- 取值处理:在RequestMappingInfoHandlerMapping里的handleMatch的方法里,即位于把请求匹配到一个处理器的过程中

就以及通过getUrlPathHelper()对路径解析好存于请求request的属性中,在这里已经取值即可

使用WebDataBinder进行必要的类型转换
     * PathVariableMapMethodArgumentResolver());  

- 支持条件:@PathVariableMap注解

- 取值逻辑同上

 
     * MatrixVariableMethodArgumentResolver());  

- 支持条件:@MatriVariable(pathVar="hotelId "value="floor") int floor ; //http://localhost:8080/hotel/43;floor=7;room=15/guest

- 取值处理:在RequestMappingInfoHandlerMapping里的handleMatch的方法里,即位于把请求匹配到一个处理器的过程中

就以及通过getUrlPathHelper().decodePathVariables(request, uriVariables)解析好存于请求request的属性中,在这里已经取值即可

使用WebDataBinder进行必要的类型转换
     * MatrixVariableMapMethodArgumentResolver());  

- 支持条件:@MatrixVariableMap注解

- 取值逻辑同上


     * ServletModelAttributeMethodProcessor(false));  

- 支持条件:存在@ModelAttribute注解

- 取值处理: ①name优先取@ModelAttribute注解的,否则取参数名称,作为Model里对应的key

            ②设置@ModelAttribute中binding属性,解决Model里是否可用

            ③如果在Model里存在name的值,直接取返回

            ④如果没有,走创建流程:

从路径参数、request中获取name对应的值,再转换为对应类型,如果成功就返回

                如果没有,就在尝试使用参数类型的构造方法(存在构造参数从request.getParameterNames()参数中获取)创建实例

            ⑤对创建成功的实例,使用equest.getParameterNames()进行实例内属性数据类型转换、Model里更新

⑥如果创建失败,则必要返回BindingResult或抛出异常


      * RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));  

- 支持条件:@RequestBody

- 取值处理:见下


      * RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));  

- 支持条件:@RequestPart("name"),注:它和@RequestParam是互斥的

- 取值逻辑:略


      * RequestHeaderMethodArgumentResolver(getBeanFactory()));    

- 支持条件:@RequestBody

- 取值处理:request.getHeaderValues
      * RequestHeaderMapMethodArgumentResolver());  

- 支持条件:@RequestHeaderMap

- 取值处理:见下


      * ServletCookieValueMethodArgumentResolver(getBeanFactory()));  //@CookieValue  

- 支持条件:@CookieValue

- 取值处理:request.getCookies()


      * ExpressionValueMethodArgumentResolver(getBeanFactory()));  
        - 支持条件:@Value

- 取值处理:${}占位符解析配置文件的值和解析Spring EL 表达式,获取最终的结果)


      * SessionAttributeMethodArgumentResolver());  

- 支持条件:@SessionAttribute

- 取值处理:name优先取@SessionAttribute注解的,否则取参数名称

request.getAttribute(name, RequestAttributes.SCOPE_SESSION)

* RequestAttributeMethodArgumentResolver());  
        - 支持条件:@RequestAttribute

- 取值处理:name优先取@RequestAttribute注解的,否则取参数名称

request.getAttribute(name, RequestAttributes.SCOPE_REQUEST)


(2)基于类型的参数

* ServletRequestMethodArgumentResolver());

- 支持条件:WebRequest/ServletRequest/MultipartRequest/HttpSession/Principal/InputStream/Reader/HttpMethod/Locale等

- 取值处理:取值均是从当前的请求request对象中获取到的


    * ServletResponseMethodArgumentResolver()); 

- 支持条件:ServletResponse/OutputStream/Writer

- 取值处理:取值均是从当前的请求request对象中获取到的,如response.getOutputStream(); response.getWriter();


    * HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice)); //HttpEntity/RequestEntity

- 支持条件:HttpEntity<T>

- 取值处理:获取泛型T的类型,使用AbstractMessageConverterMethodArgumentResolver的readWithMessageConverters方法的进行基于Contenty-type和accept

            的消息流读取和转换获取到最终的格式化后的body,在返回new HttpEntity<>(body, inputMessage.getHeaders());


    * RedirectAttributesMethodArgumentResolver()); 

- 支持条件:RedirectAttributes

- 取值处理:创建ModelMap redirectAttributes= new RedirectAttributesModelMap(dataBinder);,再mavContainer.setRedirectModel(redirectAttributes);后

直接返回redirectAttributes
   

* ModelMethodProcessor()); 

- 支持条件:Model

- 取值处理:直接返回mavContainer.getModel()


    * MapMethodProcessor());  

- 支持条件:无注解Map

- 取值处理:直接返回mavContainer.getModel()


    * ErrorsMethodArgumentResolver()); 

- 支持条件:Errors

- 取值处理:判断mavContainer.getModel()里最后一个对象是否为BindingResult,是的返回,否则抛出异常


    * SessionStatusMethodArgumentResolver()); 

- 支持条件:SessionStatus

- 取值处理:直接返回mavContainer.getSessionStatus()

* UriComponentsBuilderMethodArgumentResolver()); 

- 支持条件:UriComponentsBuilder

- 取值处理:返回基于当前request构建的ServletUriComponentsBuilder



(3)用户定义的类型
     resolvers.addAll(getCustomArgumentResolvers());
      
(4)设置最后兜底(可处理所有类型)
    * RequestParamMethodArgumentResolver(getBeanFactory(), true)); //

- 支持条件:(非Void下的基本类型) /Enum/CharSequence/Number/Date/Temporal/URI./URL/Locale/Class

- 取值处理:同上RequestParamMethodArgumentResolver(getBeanFactory(), false)); 

  * ServletModelAttributeMethodProcessor(true)); 

- 支持条件:上面RequestParamMethodArgumentResolver(getBeanFactory(), true))需要的类型除外,无需存在@ModelAttribute注解

- 取值处理:同上ServletModelAttributeMethodProcessor(false));

RequestResponseBodyMethodProcessor解析@RequestBody

对应的解析器为RequestResponseBodyMethodProcessor

  

参数解析接口

public interface HandlerMethodArgumentResolver {

//支持解析的类型
   boolean supportsParameter(MethodParameter parameter);

//进行解析
   Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
         NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}

(1)AbstractMessageConverterMethodArgumentResolver

此抽象类实现了HandlerMethodArgumentResolver但是没有实现接口方法,交于子类实现RequestResponseBodyMethodProcessor,

但子类最终会回调readWithMessageConverters进行数据转换

此抽象类主要提供了:

* 在构造器参数中传入了收集了解析器、requestResponseBodyAdvice

①接收各种http的报文解析器List<HttpMessageConverter<?>>messageConverters messageConverters

获取这些报文解析器支持的类型MediaTypes,并进行排序,q大的会排在前面,q一样,参数多的排在前面

  如,audio/*;q=0.7 > audio/*;q=0.3

      audio/basic;level=1 > audio/basic

②接收了requestResponseBodyAdvice类型集合,和封装到RequestResponseBodyAdviceChain

 
public AbstractMessageConverterMethodArgumentResolver(List<HttpMessageConverter<?>> converters,
      @Nullable List<Object> requestResponseBodyAdvice) {
   this.messageConverters = converters;
   this.allSupportedMediaTypes = getAllSupportedMediaTypes(converters);
   this.advice = new RequestResponseBodyAdviceChain(requestResponseBodyAdvice);
}

* 核心方法readWithMessageConverters实现

     ①把Tomcat的原生网络输入流HttpServletRequest封装为ServletServerHttpRequest(servletRequest) inputMessage

- HttpHeaders getHeaders()处理ContentType、ContentLength请求头

 先收集Headers集合:从底层HttpServletRequest.getHeaderNames()获取所有请求头键值对,如果其中ContentType为空,使用HttpServletRequest.getContentType()获取

 如果获取到的ContentType的Charset为空,则使用HttpServletRequest.getCharacterEncoding

- 实现InputStream getBody()方法

如果请求是表单:调用request.getParameterMap()获取原始HttpServletRequest以及解析好的参数表,使用k=v&k2=v2形式拼接为字符串,再转为ByteArrayInputStream

如果请求不是:直接返回HttpServletRequest.getInputStream().

需要主要的是,表单的处理会进行读取输入流,获取url和请求体中的所有参数封装到InputStream,这里就把原生的请求输入流读取了,流数据将清空,

无法再次读取,如果后续需要用到,应当在调用此方法之后使用一个变量保存起来

②从请求头获取contentType,如果为空,默认为application/octet-stream

      ③contextClass为null;argetClass为参数的实际类型,例如List<A>,则为A

      ④对入参HttpInputMessage inputMessage进行简单封装,保存了headers和body InputStream引用

      ⑤遍历收集到的报文解析器

- 如果converter是GenericHttpMessageConverter类型,则使用canRead(targetType, contextClass, contentType)判断

          否则使用canRead(targetClass, contentType))判断

        - 可以转换时

          如果存在请求body,则前置Advice().beforeBodyRead方法-> converter.read方法->getAdvice().afterBodyRead方法

          否则,执行advice.handleEmptyBody方法

      ⑥最终解析的body为空对象时,不为空就直接返回了

        - 如果本次请求的方法头为空或者不是常规方法,或者请求不指定ContentType且无请求体,返回null

          if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) || (noContentType && !message.hasBody())) {

                return null;

          }


protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
      Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
   HttpInputMessage inputMessage = createInputMessage(webRequest);
   return readWithMessageConverters(inputMessage, parameter, paramType);
}

 
protected ServletServerHttpRequest createInputMessage(NativeWebRequest webRequest) {
   HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
   return new ServletServerHttpRequest(servletRequest);
}


@Nullable
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
                                               Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

    //从请求头获取contentType,如果为空,默认为application/octet-stream
    MediaType contentType;
    boolean noContentType = false;
    try {
        contentType = inputMessage.getHeaders().getContentType();
    }
    catch (InvalidMediaTypeException ex) {
        throw new HttpMediaTypeNotSupportedException(ex.getMessage());
    }
    if (contentType == null) {
        noContentType = true;
        contentType = MediaType.APPLICATION_OCTET_STREAM;
    }

    //contextClassnull
    //targetClass为参数的实际类型,例如List<A>,则为A
    Class<?> contextClass = parameter.getContainingClass();
    Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
    if (targetClass == null) {
        ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
        targetClass = (Class<T>) resolvableType.resolve();
    }

    HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
    Object body = NO_VALUE;

    //对入参HttpInputMessage inputMessage进行简单封装,保存了headersbody InputStream引用
    EmptyBodyCheckingHttpInputMessage message;
    try {
        message = new EmptyBodyCheckingHttpInputMessage(inputMessage);

        for (HttpMessageConverter<?> converter : this.messageConverters) {
            Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
            GenericHttpMessageConverter<?> genericConverter =
                    (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
            //如果converterGenericHttpMessageConverter类型,则使用canRead(targetType, contextClass, contentType)判断
            //否则使用canRead(targetClass, contentType))判断
            if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
                    (targetClass != null && converter.canRead(targetClass, contentType))) {
                //可以转换时
                if (message.hasBody()) {
                    //存在请求头body,则前置Advice().beforeBodyRead方法-> converter.read方法->getAdvice().afterBodyRead方法
                    HttpInputMessage msgToUse =
                            getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
                    body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
                            ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
                    body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
                }
                else {
                    //否则,执行advice.handleEmptyBody方法
                    body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
                }
                break;
            }
        }
    }
    catch (IOException ex) {
        throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
    }


    if (body == NO_VALUE) {
        if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
                (noContentType && !message.hasBody())) {
            return null;
        }
        throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
    }

    MediaType selectedContentType = contentType;
    Object theBody = body;

    return body;
}

(2)RequestResponseBodyMethodProcessor

* 调用对应的MessageConverter进行转换,实际调用父类的AbstractMessageConverterMethodProcessor的readWithMessageConverters(见上)

* 如果添加了@Validated/@Valid注解,使用WebDataBinder对转换后返回的参数进行校验,

校验失败时,失败信息会封装到底层的BindingResult中,如果下一个参数不为org.springframework.validation.Error会直接抛出校验失败异常


public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {

    //
    //参数的注解@RequestBody即可
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestBody.class);
    }

    //解析处理流程
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        //调用对应的MessageConverter进行转换,调用父类的AbstractMessageConverterMethodProcessorreadWithMessageConverters
        //如果是json,对应的解析器为MappingJackson2HttpMessageConverter
        Object argument = this.readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
        //获取解析结果对象的驼峰命名
        String name = Conventions.getVariableNameForParameter(parameter);
        // 如果添加了@Validated/@Valid注解,使用WebDataBinder对返回参数进行校验
        WebDataBinder binder = binderFactory.createBinder(webRequest, argument, name);
        if (argument != null) {
            //校验失败时,失败信息会封装到底层的BindingResult中,如果下一个参数不为org.springframework.validation.Error会直接抛出校验失败异常
            this.validate(binder, parameter);
        }
        mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
        return argument;
    }

}

判断处理器是否结束(@ResponseStatus/isRequestHandled方法)

* 存在处理器方法上存在@ResponseStatus注解,先执行setResponseStatus处理下@ResponseStatus注解

  - 如果注解里有reson属性,使用response.sendError(status.value(), reason);,否则使用response.setStatus(status.value());

  - 设置下请求属性:setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);

@ResponseStatus(value=HttpStatus.NOT_FOUND,reason="Spittle Not Found")

* 判断处理器是否结束,如果判断需要结束,则设置mavContainer.setRequestHandled(true);

  - 当处理器的返回值为null,满足如下3个条件之一,就结束处理

①请求时没有修改,这涉及HTTP的缓存机制,webRequest.isNotModified()

②存在@ResponseStatus注解

③mavContainer已经是结束处理的标志mavContainer.isRequestHandled()

  - 当处理器的返回值不为nulL且@ResponseStatus注解里有reason属性,就判断为结束处理

如果结束,就直接return,而不必走后续的流程

setResponseStatus(webRequest);
if (returnValue == null) {
   if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
      disableContentCachingIfNecessary(webRequest);
      mavContainer.setRequestHandled(true);
      return;
   }
}
else if (StringUtils.hasText(getResponseStatusReason())) {
   mavContainer.setRequestHandled(true);
   return;
}

private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
   HttpStatus status = getResponseStatus();
   if (status == null) {
      return;
   }

   HttpServletResponse response = webRequest.getResponse();
   if (response != null) {
      String reason = getResponseStatusReason();
      if (StringUtils.hasText(reason)) {
         response.sendError(status.value(), reason);
      }
      else {
         response.setStatus(status.value());
      }
   }

   // To be picked up by RedirectView
   webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
}

结果处理

* Consumes 限制处理器方法处理指定Content-Type的http请求

* Produces 指定要求处理器方法返回的内容格式,仅当request请求头中的Accept类型中包含该指定类型才返回

* Accept类型代表发送端(客户端)希望接受的数据类型

如果Accept指定了多个MediaType,并且服务端也支持多个MediaType,那么Accept应该同时指定各个MediaType的QualityValue(也就是如图中的q值),服务端根据q值的大小来决定这几个MediaType类型的优先级,一般是大的优先。q值不指定时,默认视为q=1。

例如Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3为Chrome浏览器的默认请求头的值。

主要流程

* 开始进行结果解析处理

  - 遍历结果解析器组合,找到第一个支持此控制器方法的解析器HandlerMethodReturnValueHandler

    执行解析器handler.supportsReturnType(returnType)

  - 调用其HandlerMethodReturnValueHandler.handleReturnValue开始处理

RequestMappingHandlerAdapter.invokeHandleMethod

-> ServletInvocableHandlerMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);

//ServletInvocableHandlerMethod

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    //解析参数、执行处理器方法,返回结果

Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);


setResponseStatus(webRequest);
if (returnValue == null) {
   if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
      mavContainer.setRequestHandled(true);
      return;
   }
}
else if (StringUtils.hasText(this.responseReason)) {
   mavContainer.setRequestHandled(true);
   return;
}
mavContainer.setRequestHandled(false);
try {

//结果处理
   this.returnValueHandlers.handleReturnValue(
         returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {throw ex;}

}

@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
   HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
   handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

默认的结果解析器列表(顺序由上往下)

(1)基于返回类型的处理

    

* ModelAndViewMethodReturnValueHandler()

- 支持条件:ModelAndView类型

  - 处理处理:如果返回值为null,那么mavContainer.setRequestHandled(true);,结束整个流程

              如果不为null,把当前返回值的内容拷贝到上下文mavContainer中即可

* ModelMethodProcessor())

- 支持条件:Model类型

  - 处理处理:类似ModelAndViewMethodReturnValueHandler,只拷贝了属性值mavContainer.addAllAttributes(((Model) returnValue).asMap());

* ViewMethodReturnValueHandler()

- 支持条件:View类型

  - 处理处理:类似ModelAndViewMethodReturnValueHandler,只拷贝了View值mavContainer.setView(view)/etRedirectModelScenario(true);

    * ResponseBodyEmitterReturnValueHandler(getMessageConverters(),this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));

- 支持条件:ResponseBodyEmitter 类型

  - 处理处理:类似DeferredResult,支持异步处理,底层时长轮询原理


@RequestMapping("/async/responseBodyEmitter")
public ResponseBodyEmitter responseBodyEmitter(){
    ResponseBodyEmitter responseBodyEmitter=new ResponseBodyEmitter();
    Executors.newSingleThreadExecutor().submit(() -> {
        try {
            responseBodyEmitter.send("demo");
            responseBodyEmitter.send("test");
            responseBodyEmitter.complete();
        } catch (Exception ignore) {}
    });
    return responseBodyEmitter;
}

      * StreamingResponseBodyReturnValueHandler());

- 支持条件:StreamingResponseBody类型

        - 处理处理:直接将结果写出到Response的OutputStream中,使用异步线程池去写入

                   

* HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice));

- 支持条件:HttpEntity类型

        - 处理处理:获取结果对象指定的所有请求头

                    如果是ResponseEntity类型,获取设置的状态码:如果是200且get/head方法且NotModified直接return

                    调用writeWithMessageConverters对ResponseEntity里封装的结果 T对象转码。处理的流程和@ResponseBody的一样

                    执行outputMessage.flush();


@RequestMapping(value=)
public ResponseEntity<T> f() throws IOException{
    //...
    return new ResponseEntity<byte[]>(
            T,headers,
            HttpStatus.XX);
}

* HttpHeadersReturnValueHandler());

- 支持条件:HttpHeaders类型

  - 处理处理:把请求头写入响应流

      * CallableMethodReturnValueHandler())

- 支持条件:Callable类型

        - 处理处理:WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);

      * DeferredResultMethodReturnValueHandler());

- 支持条件:DeferredResult类型

        - 处理处理:WebAsyncUtils.getAsyncManager(webRequest).startDeferredResultProcessing(result, mavContainer);

* AsyncTaskMethodReturnValueHandler(this.beanFactory));

- 支持条件:WebAsyncTask类型

        - 处理处理:WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer);

(2)基于注解

* ModelAttributeMethodProcessor(false));

- 支持条件:@ModelAttribute标注在方法上

  - 处理处理:返回值将会被解释为model的一个属性,mavContainer.addAttribute(name, returnValue);

      

* RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice));

- 支持条件:@ResponseBody标注在方法上或者类上

  - 处理处理:执行其父类的readWithMessageConverters方法进行报文格式转换(见下节)

      * ViewNameMethodReturnValueHandler());

- 支持条件:CharSequence(字符串)或者void的返回类型

- 处理处理:如果返回值为CharSequence类型,设置到mavContainer.setViewName(viewName);,否则报错

      handlers.add(new MapMethodProcessor());

- 支持条件:Map类型

- 处理处理:如果返回值为Map类型,设置到mavContainer.addAllAttributes((Map) returnValue);;,否则报错

(3)自定义

      handlers.addAll(getCustomReturnValueHandlers());

      

(5)如果在RequestMappingHandlerAdapter中存在用户自己设置的ModelAndViewResolvers

      ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));

       - 支持条件:true

       - 处理方式:遍历解析器获取ModelAndView mav = mavResolver.resolveModelAndView(method, handlerType, returnValue, model, webRequest);

                  设置到当前上下文的mavContainer

     不存在,添加ModelAttributeMethodProcessor(true));

- 支持条件:这些类型除外:非Void下的基本类型/Enum/CharSequence/Number/Date/Temporal/URI./URL/Locale/Class

- 处理方式:作为上下文属性mavContainer.addAttribute(name, returnValue);,

name取值规则:Mono<com.myapp.Product>  ->  productMono

                         Flux<com.myapp.MyProduct>  ->   myProductFlux

                         Observable<com.myapp.MyProduct> -> myProductObservable

RequestResponseBodyMethodProcessor解析@ResponseBody举例

对应的解析器为RequestResponseBodyMethodProcessor

  

  1. 主流程

* 外层方法实现

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {

    //略


    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return (AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null ||
                returnType.getMethodAnnotation(ResponseBody.class) != null);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
                                  ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException {
        mavContainer.setRequestHandled(true);
        writeWithMessageConverters(returnValue, returnType, webRequest);
    }

}

* writeWithMessageConverters

//转换写原生的webRequest为ServletServerHttpRequest (转换原因见上搜索)

//和封装下ServletServerHttpResponse outputMessage

protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType, NativeWebRequest webRequest)
      throws IOException, HttpMediaTypeNotAcceptableException {

   ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
   ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
   writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

//封装下ServletServerHttpResponse outputMessage的原因

ServletResponseHttpHeaders headers,可以设置自己的响应头,如ContentTypeCharSet

写响应时,当原生servletResponse的ContentType/CharacterEncoding为空时,可以根据headers里的值来设置

private void writeHeaders() {
   if (!this.headersWritten) {
      for (Map.Entry<String, List<String>> entry : this.headers.entrySet()) {
         String headerName = entry.getKey();
         for (String headerValue : entry.getValue()) {
            this.servletResponse.addHeader(headerName, headerValue);
         }
      }
      if (this.servletResponse.getContentType() == null && this.headers.getContentType() != null) {
         this.servletResponse.setContentType(this.headers.getContentType().toString());
      }
      if (this.servletResponse.getCharacterEncoding() == null && this.headers.getContentType() != null &&
            this.headers.getContentType().getCharSet() != null) {
         this.servletResponse.setCharacterEncoding(this.headers.getContentType().getCharSet().name());
      }
      this.headersWritten = true;
   }
}

* 核心方法writeWithMessageConverters

  - 找出请求方期望接收的MIME类型requestedMediaTypes

    使用传递进来的内容协商ContentNegotiationManager进行解析request,会遍历注册进来的ContentNegotiationStrategy,

    返回第一个不为ALL的,遍历次序如下:

    ①根据扩展名来判断(默认),比如:mvc/test.xml  将返回xml格式数据

    ②根据参数来判断 mvc/test?format=xml        将返回xml数据

    ③根据Http请求的header中的Accept属性的值来判读(默认true),比如:Accept: application/xml  将返回xml格式数据

④服务段默认返回格式,通过在WebMvcConfigurationSupport 子类中configureContentNegotiation方法对configurer.setDefaultContentTypes的设置

  - 找出当前处理器方法能返回的MIME类型producibleMediaTypes

①控制器方法@RequestMapping注解produces属性指定的的MediaType集合,存在就直接返回

②如果没有指定,则收集所有支持MediaType为null的messageConverters,在取他们的MediaType作为返回值,使用converter.canWrite(targetType, valueClass, null)

  - 对requestedMediaTypes 和producibleMediaTypes 进行一一适配,如果适配不到且处理器方法有非null返回值,则报错

匹配规则,即Accept为json;q=;x=、 product也为json,此时取参数多的一个作为结果  

  - 选择最佳的类型

按照参数q、精确匹配度、参数大小进行排序,找出第一个精确指定(没有通配符的)的类型作为最终需要转换的类型

如果最终结果为AL或者application,则默认为application/octet-stream

- 遍历所有的messageConverters,找到第一个支持此类型的Converters进行转换,并写入响应流

@SuppressWarnings("unchecked")
protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType,
                                              ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
        throws IOException, HttpMediaTypeNotAcceptableException {

    Class<?> returnValueClass = getReturnValueType(returnValue, returnType);
    HttpServletRequest servletRequest = inputMessage.getServletRequest();

//使用传递进来的内容协商ContentNegotiationManager进行解析request,会遍历注册进来的ContentNegotiationStrategy,

//List<MediaType> mediaTypes = strategy.resolveMediaTypes(request);当结果不为ALL时就返回

//处理次序如下:

// 如上的协商策略配置,按照策略按序进行解析,存在即返回MIME类型,返回给客户端

  ①根据扩展名来判断(默认),比如:mvc/test.xml  将返回xml格式数据

  ②根据参数来判断 mvc/test?format=xml        将返回xml数据

   ③根据Http请求的header中的Accept属性的值来判读(默认true),比如:Accept: application/xml  将返回xml格式数据

   ④服务段默认返回格式,通过在WebMvcConfigurationSupport 子类中configureContentNegotiation方法对configurer.setDefaultContentTypes的设置
    List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
    //控制器方法@RequestMapping注解produces属性指定的的MediaType集合,如果没有指定,则收集所有支持MediaTypenullmessageConverters,在他们的MediaType作为返回值

// 使用converter.canWrite(targetType, valueClass, null)
    List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass);

    Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
    //以请求需要的类型,一个一个去控制器方法指定的类型配置,如果匹配,说明此处理器方法支持响应请求需要的类型
    for (MediaType requestedType : requestedMediaTypes) {
        for (MediaType producibleType : producibleMediaTypes) {
            //对于匹配的类型,即Acceptjsonq=;x= product也为json,此时参数多的一个作为结果
            if (requestedType.isCompatibleWith(producibleType)) {
                compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
            }
        }
    }
    if (compatibleMediaTypes.isEmpty()) {
        if (returnValue != null) {
            throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
        }
        return;
    }

    List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
    //按照参数q、精确匹配度、参数大小进行排序,找出第一个精确指定没有通配符的的类型作为最终需要转换的类型
    MediaType.sortBySpecificityAndQuality(mediaTypes);
    MediaType selectedMediaType = null;
    for (MediaType mediaType : mediaTypes) {
        if (mediaType.isConcrete()) {
            selectedMediaType = mediaType;
            break;
        }
        else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
            selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
            break;
        }
    }

    //遍历所有的messageConverters,找到第一个支持此类型的Converters进行转换,并写入响应流
    if (selectedMediaType != null) {
        selectedMediaType = selectedMediaType.removeQualityValue();
        for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
            if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
                returnValue = this.adviceChain.invoke(returnValue, returnType, selectedMediaType,
                        (Class<HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage);
                if (returnValue != null) {
                    ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
                }
                return;
            }
        }
    }

    if (returnValue != null) {
        throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
    }
}

获取最终收集的ModelAndView

@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
                                     ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {

   //根据container.getSessionStatus().isComplete()状态是否把@SeesionAttribute的属性从当前request
    //BindingResult结果放到Model
    modelFactory.updateModel(webRequest, mavContainer);
    //处理器是否结果,是返回null
    if (mavContainer.isRequestHandled()) {
        return null;
    }
    //把上下文收到的mavContainer的说要信息封装到一个新的ModelAndView返回
    ModelMap model = mavContainer.getModel();
    ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
    if (!mavContainer.isViewReference()) {
        mav.setView((View) mavContainer.getView());
    }
    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;
}

执行拦截器链的后置方法

使用HandlerExecutionChain的applyPreHandle方法

* 获取当前HandlerExecutionChain处理器执行链的配置的拦截器集合

* 逆序遍历每一个拦截器的applyPostHandle

@Nullable
public HandlerInterceptor[] getInterceptors() {
   if (this.interceptors == null && this.interceptorList != null) {
      this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]);
   }
   return this.interceptors;
}



void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
   if (getInterceptors() == null) {
      return;
   }
   for (int i = getInterceptors().length - 1; i >= 0; i--) {
      HandlerInterceptor interceptor = getInterceptors()[i];
      interceptor.postHandle(request, response, this.handler, mv);
   }
}

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐