转载

SpringMVC源码解析系列4-HandleAdapter

SpringMVC源码解析系列4-HandleAdapter

HandleAdapter接口定义

定义: 根据HandlerMethod信息,对http请求进行参数解析,并完成调用

先看一下HandlerAdapter的接口定义

public interface HandlerAdapter {
   //判断是否支持该handler类型的解析
   boolean supports(Object handler);
   //参数解析 并调用handler完成过程调用 
   ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
   //用于处理http请求头中的last-modified
   long getLastModified(HttpServletRequest request, Object handler);

}
SpringMVC源码解析系列4-HandleAdapter

RequestMappingHandlerAdapter

以RequestMappingHandlerAdapter为例来讲,先看下继承关系

SpringMVC源码解析系列4-HandleAdapter

初始化过程

同RequestMappingHandlerMapping都有 ApplicationContextAware , ServletContextAware , InitializingBean 三个生命周期方法

这里我们就直接看InitializingBean了

#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
public void afterPropertiesSet() {
 // 1.装载@ControllerAdvice注解的类
 initControllerAdviceCache();
// 2.装载ArgumentResolver(默认+自定义)
 if (this.argumentResolvers == null) {
    List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
    //包装成一个Composite对象
    this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
 }
 // 2.装载InitBinderArgumentResolvers(默认+自定义)
 if (this.initBinderArgumentResolvers == null) {
    List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
    //包装成一个Composite对象
    this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
 }
 // 3.装载ReturnValueHandlers(默认+自定义)
 if (this.returnValueHandlers == null) {
    List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
    //包装成一个Composite对象
    this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
 }
}

过程概括:

  1. 装载带有ControllerAdvices注解的对象

    private void initControllerAdviceCache() {
      //从容器中获取所有带有ControllerAdvices注解的类名 并包装成ControllerAdviceBean
      List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
      OrderComparator.sort(beans);
      List<Object> responseBodyAdviceBeans = new ArrayList<Object>();
      for (ControllerAdviceBean bean : beans) {
        //筛选出带有@ModelAttribute且不带@RequestMapping注解的方法
        Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
        if (!attrMethods.isEmpty()) {
          //保存到modelAttributeAdviceCache中
          this.modelAttributeAdviceCache.put(bean, attrMethods);
        }
        //筛选出带InitBinder注解的方法 添加到initBinderAdviceCache中
        Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
        if (!binderMethods.isEmpty()) {
          this.initBinderAdviceCache.put(bean, binderMethods);
        }
        //筛选实现RequestBodyAdvice接口 添加到requestResponseBodyAdviceBeans中
        if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
          requestResponseBodyAdviceBeans.add(bean);
          if (logger.isInfoEnabled()) {
            logger.info("Detected RequestBodyAdvice bean in " + bean);
          }
        }
        //筛选实现ResponseBodyAdvice接口 添加到requestResponseBodyAdviceBeans中
        if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
          requestResponseBodyAdviceBeans.add(bean);
          if (logger.isInfoEnabled()) {
            logger.info("Detected ResponseBodyAdvice bean in " + bean);
          }
        }
      }
      //保存到全局变量
      if (!responseBodyAdviceBeans.isEmpty()) {
        this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans);
      }
    }
    • 筛选出带有@ModelAttribute且不带@RequestMapping注解的方法
    • 筛选出带InitBinder注解的方法 添加到initBinderAdviceCache中
    • 筛选实现RequestBodyAdvice接口 添加到responseBodyAdvice中
    • 筛选实现ResponseBodyAdvice接口 添加到responseBodyAdvice中
  2. 装载ArgumentResolvers(默认+自定义)

  3. 装载InitBinderArgumentResolvers(默认+自定义)

  4. 装载ReturnValueHandlers(默认+自定义)

自定义拓展方式放后面说

以下为HandlerAdapter默认解析器

SpringMVC源码解析系列4-HandleAdapter

HandlerMethodReturnValueHandler,HandlerMethodArgumentResolver

//参数解析器
public interface HandlerMethodArgumentResolver {
  //判断是否支持该参数的解析(根据类型,注解等)
   boolean supportsParameter(MethodParameter parameter);
  //对参数进行解析 得到解析结果
   Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
         NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}
//返回值解析器
public interface HandlerMethodReturnValueHandler {
  //判断是否支持该返回值的解析(根据类型,注解等)
	boolean supportsReturnType(MethodParameter returnType);
  //对返回值进行解析
	void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}

DispatcherServlet调用HandlerAdapter过程

//1.调用support()方法判断是否支持HandlerMethod的解析
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 如果是Get或Head请求 调用getLastModified()获取上次更新时间 
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
   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;
   }
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
   return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

过程总结:

  1. 调用support()方法判断是否支持改handler的解析

    #org.springframework.web.servlet.DispatcherServlet
    //在doDispatch()方法中调用了getHandlerAdapter(Object)方法来得到一个HandlerAdapter
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        //调用HandlerAdapter.support()方法 判断是否支持该handler对象的解析
       for (HandlerAdapter ha : this.handlerAdapters) {
            ...
          if (ha.supports(handler)) {
             return ha;
          }
       }
      ...
    }
    #org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter
    //根据handler对象判断是否支持handler解析
    @Override
    public final boolean supports(Object handler) {
    	return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }
    #org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
    @Override
    protected boolean supportsInternal(HandlerMethod handlerMethod) {
    	return true;
    }

  2. 如果是Get或Head请求 调用getLastModified()获取上次更新时间

    如果小于浏览器缓存更新时间 则直接返回 浏览器使用本地缓存

    #org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
    @Override
    protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
       return -1;
    }

  3. 调用handler()方法完成过程调用(参数解析 返回值解析)

    #org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter
    @Override
    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
          throws Exception {
       return handleInternal(request, response, (HandlerMethod) handler);
    }
    
    #org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
    @Override
    protected ModelAndView handleInternal(HttpServletRequest request,
    		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    	//对http协议缓存方面的请求头的处理(expire,cache-control)
    	if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
    		checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
    	}else {
    		checkAndPrepare(request, response, true);
    	}
    	//是否使用session锁
    	if (this.synchronizeOnSession) {
    		HttpSession session = request.getSession(false);
    		if (session != null) {
              	//得到互斥量
    			Object mutex = WebUtils.getSessionMutex(session);
    			synchronized (mutex) {//执行过程调用
    				return invokeHandleMethod(request, response, handlerMethod);
    			}
    		}
    	}
    	//执行过程调用(参数解析 过程调用)
    	return invokeHandleMethod(request, response, handlerMethod);
    }

参数解析,过程调用流程分析

//根据HandlerMethod解析参数 并完成过程调用得到一个ModelAndView
private ModelAndView invokeHandleMethod(HttpServletRequest request,
                 HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  ServletWebRequest webRequest = new ServletWebRequest(request, response);
  try {
    //对@InitBinder的处理 主要是聚合了@InitBinder的所有处理方法
    WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
    //@ModelAttribute的处理
    ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
	//对HandlerMethod的装饰,主要是增加了参数解析和返回值转化的功能
    ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
    //提供对参数解析的支持
    invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
    //提供对返回值解析的支持
    invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
    //提供对@InitBinder处理的支持
    invocableMethod.setDataBinderFactory(binderFactory);
    //TODO 尚不明功能
    invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
	
    //可以看做handler()过程的上下文
    ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
    modelFactory.initModel(webRequest, mavContainer, invocableMethod);
    mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
==========================异步处理分割线=============	
	//AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务
    AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
    asyncWebRequest.setTimeout(this.asyncRequestTimeout);
	//异步处理Manager
    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();
      ...
      //替换invocableMethod(原先异步处理的方法返回值是Callable现在直接返回结果)
      invocableMethod = invocableMethod.wrapConcurrentResult(result);
    }
	//对invocableMethod进行参数解析,过程调用,返回值转化
    //并将结果存到mavContainer中
    invocableMethod.invokeAndHandle(webRequest, mavContainer);
    //如果异步处理正在执行(已经开始,尚未结束) 立刻返回
    //同时DispatcherServlet也直接返回 等待AsyncContext.dispatch()调用再次进入doDispatch()方法
    if (asyncManager.isConcurrentHandlingStarted()) {
      return null;
    }
	//从mavContainer捞出结果
    return getModelAndView(mavContainer, modelFactory, webRequest);
  }
  finally {
    webRequest.requestCompleted();
  }
}

以上是invokeHandleMethod()的完整过程

但在调用过程中实际从 异步处理分割线 开始分为 2种情况 :

  1. 同步调用: 过程比较简单,直接进行参数解析和返回值转化就好了

    invocableMethod.invokeAndHandle(webRequest, mavContainer);
    return getModelAndView(mavContainer, modelFactory, webRequest);
  2. 异步调用:

    再分为两种情况:

    1. 异步处理中(已开始,尚未完成)

      //AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务
      AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
      asyncWebRequest.setTimeout(this.asyncRequestTimeout);
      //异步处理Manager
      WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      //设置异步执行线程池
      asyncManager.setTaskExecutor(this.taskExecutor);
      //提供对异步处理的支持
      asyncManager.setAsyncWebRequest(asyncWebRequest);
      //异步调用拦截器
      asyncManager.registerCallableInterceptors(this.callableInterceptors);
      asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
      //对invocableMethod进行参数解析,过程调用(调用AsyncWebRequest.startAsync()执行异步过程),返回值转化
      //并将结果存到mavContainer中
      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      //如果异步处理正在执行(已经开始,尚未结束) 立刻返回
      //同时DispatcherServlet也直接返回 
      return null;
      
      #org.springframework.web.servlet.DispatcherServlet
      protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ...
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        if (asyncManager.isConcurrentHandlingStarted()) {
          return;
        }
        ...
      }
      //等待AsyncWebRequest.dispatch()被调用 然后再次进入doDispatch()方法
    2. 异步执行完成,再次进入doDispatch()流程

      //AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务
      AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
      asyncWebRequest.setTimeout(this.asyncRequestTimeout);
      //异步处理Manager
      WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      //设置异步执行线程池
      asyncManager.setTaskExecutor(this.taskExecutor);
      //提供对异步处理的支持
      asyncManager.setAsyncWebRequest(asyncWebRequest);
      //异步调用拦截器
      asyncManager.registerCallableInterceptors(this.callableInterceptors);
      asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
      //异步处理完成 获取异步执行结果
      Object result = asyncManager.getConcurrentResult();
      mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
      asyncManager.clearConcurrentResult();
      //替换invocableMethod(原先异步处理的方法返回值是Callable现在直接返回结果)
      invocableMethod = invocableMethod.wrapConcurrentResult(result);
      //对invocableMethod进行参数解析,过程调用,返回值转化
      //并将结果存到mavContainer中
      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      //从mavContainer捞出结果
      return getModelAndView(mavContainer, modelFactory, webRequest);

ServletInvocableHandlerMethod

先看一下ServletInvocableHandlerMethod是个什么东东

SpringMVC源码解析系列4-HandleAdapter

HandlerMethod:保存了处理过程方法

InvocableHandlerMethod: 对HandlerMethod的装饰,增加了参数解析的功能

ServletInvocableHandlerMethod:对HandlerMethod的装饰,增加了返回值转化的功能

同步流程

  1. invocableMethod.invokeAndHandle(webRequest, mavContainer);

    #org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod
    public void invokeAndHandle(ServletWebRequest webRequest,
                        ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
      // 1.1 参数解析 并完成过程调用
      Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
      setResponseStatus(webRequest);
      ...
        try {
          //1.2 使用returnValueHandlers对返回结果进行处理 讲结果塞到mavContainer中 过程类似参数解析
          this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
    }
    #org.springframework.web.method.support.InvocableHandlerMethod
    public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
                                           Object... providedArgs) throws Exception {
      //1.1.1 参数解析并得到绑定的结果
      Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
      ...
        //1.1.2 反射完成过程调用 
        Object returnValue = doInvoke(args);
      ...
        return returnValue;
    }
    private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
                                             Object... providedArgs) throws Exception {
      //参数信息
      MethodParameter[] parameters = getMethodParameters();
      Object[] args = new Object[parameters.length];
      for (int i = 0; i < parameters.length; i++) {
        //调用HandlerMethodArgumentResolver#supportsParameter判断是否支持该参数的解析
        if (this.argumentResolvers.supportsParameter(parameter)) {
          try {
            //调用HandlerMethodArgumentResolver#resolveArgument进行解析
            args[i] = this.argumentResolvers.resolveArgument(
              parameter, mavContainer, request, this.dataBinderFactory);
            continue;
          }
          ...
        }
        ...
      }
      return args;
    }

  2. 包装ModelAndView getModelAndView(mavContainer, modelFactory, webRequest);

    //从mavContainer取出结果 包装成ModelAndView
    private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
                                         ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
      modelFactory.updateModel(webRequest, mavContainer);
      if (mavContainer.isRequestHandled()) {
        return null;
      }
      ModelMap model = mavContainer.getModel();
      ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
      if (!mavContainer.isViewReference()) {
        mav.setView((View) mavContainer.getView());
      }
      //如果是redirect请求
      if (model instanceof RedirectAttributes) {
        Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
      }
      return mav;
    }

到此 HandlerAdapter.handler的调用过程算分析完了

@InitBinder的处理

WebDataBinder:数据(对象属性)绑定器,用于对对象的属性进行转化(Formatter)和校验(Validator)

InitBinder: @InitBinder注解用于在参数解析前初始化WebDataBinder.简单来说就是可以对WebDataBinder增加Validator和属性转化器Formatter

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InitBinder {
	//在哪些属性上发生作用
	String[] value() default {};
}

示例

@InitBinder
protected void initBinder(WebDataBinder binder) {
 //添加自定义Data类型Formatter
  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  dateFormat.setLenient(false);
  binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}

@InitBinder方法分为 两种 :

  • 全局@InitBinder:定义在注解有@ControllerAdvices的类中,装载发生在HandlerAdapter初始化调用initControllerAdviceCache()过程中(见上文初始化过程分析)

  • 局部@InitBinder:定义在注解有@Controller的类中,装载发生在HandlerAdapter.handler()调用getDataBinderFactory()过程中

    private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
      //获取处理方法所在的类
      Class<?> handlerType = handlerMethod.getBeanType();
      //从保存的全局缓存中找属于该类的局部@InitBinder方法
      Set<Method> methods = this.initBinderCache.get(handlerType);
      if (methods == null) {//如果没找到 说明该类不是一个@ControllerAdvices注解的类(只有@Controller没有@ControllerAdvices)
        //得到该类中所有@InitBinder注解的方法
        methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
        //将局部@InitBinder方法缓存到initBinderCache中
        this.initBinderCache.put(handlerType, methods);
      }
      List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
      //将全局@InitBinder方法包装成InvocableHandlerMethod,添加到initBinderMethods
      for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
        if (entry.getKey().isApplicableToBeanType(handlerType)) {
          Object bean = entry.getKey().resolveBean();
          for (Method method : entry.getValue()) {
            initBinderMethods.add(createInitBinderMethod(bean, method));
          }
        }
      }
      //将局部@InitBinder方法包装成InvocableHandlerMethod,添加到initBinderMethods
      for (Method method : methods) {
        Object bean = handlerMethod.getBean();
        initBinderMethods.add(createInitBinderMethod(bean, method));
      }
      //使用initBinderMethods对象(局部+全局),包装成WebDataBinderFactory对象
      return createDataBinderFactory(initBinderMethods);
    }
    protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)
      throws Exception {
      return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
    }

看完了了@InitBinder的装载过程,来看下@InitBinder方法是怎样被处理的

处理过程

this.argumentResolvers.resolveArgument(
          parameter, mavContainer, request, this.dataBinderFactory);

可以看到在使用argumentResolvers.resolveArgument()进行参数解析时将dataBinderFactory作为参数传递了过去

分别来看 RequestParamMapMethodArgumentResolver , RequestResponseBodyMethodProcessor , ModelAttributeMethodProcessor 三个参数解析器是如何处理@InitBinder方法的

  • RequestParamMapMethodArgumentResolver

    @Override
    	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
          // 完全没使用binderFactory
          ...
    	}
    }

    因为说过@InitBinder是用来初始化WebDataBinder的,而RequestParamMapMethodArgumentResolver是处理表单属性的(不是对象),所以完全没用

  • RequestResponseBodyMethodProcessor

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
    NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
      parameter = parameter.nestedIfOptional();
     //使用binderFactory创建对象解析器
      WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
      if (arg != null) {
        //使用对象解析进行参数校验
        validateIfApplicable(binder, parameter);
        //如果参数校验异常,且目标方法参数列表中没有BindingResult类型参数,则直接抛出参数解析异常
        if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) 	{
        throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
        }
      }
      //将参数解析结果存到mavContainer上下文中
      mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
      return adaptArgumentIfNecessary(arg, parameter);
    }

    因为RequestResponseBodyMethodProcessor将属性绑定委托给了json解析器,所以这里WebDataBinder 只负责参数校验

  • ModelAttributeMethodProcessor

    @Override
    public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer 		mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    
      String name = ModelFactory.getNameForParameter(parameter);
      Object attribute = (mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) :
                          createAttribute(name, parameter, binderFactory, webRequest));
    	...
      WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
      if (binder.getTarget() != null) {
        //使用binder进行属性绑定
        if (!mavContainer.isBindingDisabled(name)) {
          bindRequestParameters(binder, webRequest);
        }
        //使用binder进行属性校验
        validateIfApplicable(binder, parameter);
        if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
          throw new BindException(binder.getBindingResult());
        }
      }
    
      // Add resolved attribute and BindingResult at the end of the model
      Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
      mavContainer.removeAttributes(bindingResultModel);
      mavContainer.addAllAttributes(bindingResultModel);
    
      return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
    }
    protected Object createAttribute(String attributeName, MethodParameter methodParam,
    			WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception {
      return BeanUtils.instantiateClass(methodParam.getParameterType());
    }
    protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
      ((WebRequestDataBinder) binder).bind(request);
    }

    使用WebDataBinder进行了属性绑定和属性校验

原文  https://juejin.im/post/5ab3c8d6f265da238f12771b
正文到此结束
Loading...