Administrator
发布于 2022-10-15 / 45 阅读
0
0

SpringMVC源码--九大组件与数据入参

SpringMVC的九大组件

  /** 文件上传解析器*/
    private MultipartResolver multipartResolver;
    /** 区域信息解析器;和国际化有关 */
    private LocaleResolver localeResolver;
    /** 主题解析器;强大的主题效果更换 */
    private ThemeResolver themeResolver;
    /** Handler映射信息;HandlerMapping */
    private List<HandlerMapping> handlerMappings;
    /** Handler的适配器 */
    private List<HandlerAdapter> handlerAdapters;
    /** SpringMVC强大的异常解析功能;异常解析器 */
    private List<HandlerExceptionResolver> handlerExceptionResolvers;
    /**  */
    private RequestToViewNameTranslator viewNameTranslator;
    /** FlashMap+Manager:SpringMVC中运行重定向携带数据的功能 */
    private FlashMapManager flashMapManager;
    /** 视图解析器; */
    private List<ViewResolver> viewResolvers;

补充:SpringMVC在工作的时候,关键位置都是由这些组件完成的;
共同点:九大组件全部都是接口;接口就是规范;提供了非常强大的扩展性;
可以理解是SpringMVC在启动完成后存储各种解析器、适配器的地方

 

九大组件的初始化

	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

 

组价的初始化细节:以initHandlerMappings举例,上一篇源码的后面也有一样的

private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
    
--
detectAllHandlerMappings默认是ture,当然也可以在配置文件中修改
/**
*可以在web.xml中修改DispatcherServlet某些属性的默认配置;
*<init-param>
*          <param-name>detectAllHandlerMappings</param-name>
*            <param-value>false</param-value>
*        </init-param>
/
--

    if (this.detectAllHandlerMappings) {
    --
    在ApplicationContext找到所有HandlerMapping,包含所有的子类
    --
        // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
        Map<String, HandlerMapping> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
                --
                //如果你的配置文件里什么都没有,此时就会为空
                --
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // We keep HandlerMappings in sorted order.
            --
            将所有的HandlerMapping按优先级排序
            --
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    --
    //从context中拿名为handlerMapping,HandlerMapping.class的bean组件,
    //并进行加入到handlerMappings,如果还是没有,下面也会有默认的实现策略
    --
    else {
        try {
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerMapping later.
        }
    }

    // Ensure we have at least one HandlerMapping, by registering
    // a default HandlerMapping if no other mappings are found.
    
    --
    //默认的实现策略
    //默认的策略配置在DispatcherServlet.properties中已经是写好了的,
    //所有的组件基本都是没有就按默认的策略实现。除了MultipartResolver
    --
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
}

总结:如果你的xml文件里什么都没有,也会使用默认的策略进行组件的注册

 

目标方法的执行(利用反射)

eg:

    @RequestMapping(value = "/getBook")
    public Book getBook(@RequestParam("name") String name,
                        Map map,
                        HttpServletRequest request,
                        @ModelAttribute("book") Book book) {
        System.out.println("getBook-----");
        return book;
    }

    @ModelAttribute
    public void initParams(Map map){
        map.put("book", new Book("西游记","吴承恩",99,100,100));

    }
    

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
---->return handleInternal(request, response, (HandlerMethod) handler);
---->mav = invokeHandlerMethod(request, response, handlerMethod);

 

handleInternal

protected ModelAndView handleInternal(HttpServletRequest request,
          HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
          
--
定义了一个ModelAndView,后续用以返回
--
      ModelAndView mav;
      checkRequest(request);

--
有需要就在锁内执行
--
      // Execute invokeHandlerMethod in synchronized block if required.
      if (this.synchronizeOnSession) {
          HttpSession session = request.getSession(false);
          if (session != null) {
              Object mutex = WebUtils.getSessionMutex(session);
              synchronized (mutex) {
                  mav = invokeHandlerMethod(request, response, handlerMethod);
              }
          }
          else {
              // No HttpSession available -> no mutex necessary
              mav = invokeHandlerMethod(request, response, handlerMethod);
          }
      }
      else {
          // No synchronization on session demanded at all...
          --
          个人测试,没有锁也没有配置synchronizeOnSession,按默认走这里
          --
          mav = invokeHandlerMethod(request, response, handlerMethod);
      }

      if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
          if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
              applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
          }
          else {
              prepareResponse(response);
          }
      }

      return mav;
  }

 

invokeHandlerMethod

  @Nullable
  protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
          HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
--
包装原生的request, response
--
      ServletWebRequest webRequest = new ServletWebRequest(request, response);
      try {
      --
      获取数据绑定工厂
      --
          WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
          --
          获取模型工厂,并将标注了@ModelAttribute注解的方法保存在工厂中
          --
          ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

          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);
          
          --
	  //new一个ModelAndView容器,在内部还new BindingAwareModelMap()。
          --
          ModelAndViewContainer mavContainer = new ModelAndViewContainer();
          mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
          --
          //填充模型,map、model中的数据能在方法运行前就存在,就是因为在此进行了填充
          --
          modelFactory.initModel(webRequest, mavContainer, invocableMethod);
          
          
          mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

          AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
          asyncWebRequest.setTimeout(this.asyncRequestTimeout);


          --
          //中间一大段异步的代码,删掉,节约空间
          --
          
              invocableMethod = invocableMethod.wrapConcurrentResult(result);
          }

          --
          //执行目标方法getBook
          --
          
          invocableMethod.invokeAndHandle(webRequest, mavContainer);
          if (asyncManager.isConcurrentHandlingStarted()) {
              return null;
          }

          return getModelAndView(mavContainer, modelFactory, webRequest);
      }
      finally {
          webRequest.requestCompleted();
      }
  }

 

initModel
--
按以下顺序填充模型: 检索列出为@SessionAttributes的“已知”会话属性。 
调用@ModelAttribute方法 找到@ModelAttribute方法参数也作为@SessionAttributes列出,
并确保它们在必要时引发异常的模型中存在。 
参数: 
请求——当前请求 
容器——带有要初始化的模型的容器 
handlerMethod——用于初始化模型的方法 
抛出: 异常-可能由@ModelAttribute方法引起
--
  public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod)
          throws Exception {

      Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);

      container.mergeAttributes(sessionAttributes);
      --
      //执行标注了@ModelAttribute注解的方法·
      --
      invokeModelAttributeMethods(request, container);
      
      --
      //根据处理的方法的参数,查找是否是属于@SessionAttribute中的value的值

      for (String name : findSessionAttributeArguments(handlerMethod)) {
          if (!container.containsAttribute(name)) {
          --
          //从后端会话检索指定的属性。 调用此方法时通常期望属性已经存在,
          //如果该方法返回null则抛出异常。
          //container中有的只是当前请求的,sessionAttributes中有整个会话的、
          //所以说不建议使用sessionAttributes注解,因为使用了就想当于保证了
          //有某一个值,没有就会报错
          //一定要写的话,也可以,但不要标注value的值
          --
              Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
              if (value == null) {
                  throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
              }
              container.addAttribute(name, value);
          }
      }
  }

 

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

	--
    //获取模型工厂的时候如果扫描到了标注@ModelAttribute注解的方法,
    //modelMethods这个ArrayList里就会有值
    --
      while (!this.modelMethods.isEmpty()) {
          InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();
          --
          //查找@ModelAttribute标注的name的值,有就进行绑定
          --
          ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class);
          Assert.state(ann != null, "No ModelAttribute annotation");
          if (container.containsAttribute(ann.name())) {
              if (!ann.binding()) {
                  container.setBindingDisabled(ann.name());
              }
              continue;
          }
          --
          //利用反射执行@ModelAttribute标注的方法,并将可能有的数据保存进defaultModel中
          //即保存进入参中的map、model中
          --

          Object returnValue = modelMethod.invokeForRequest(request, container);
          --
          //返回值类型如果是void,则不处理
          --
          if (!modelMethod.isVoid()){
-----
-----
  }

 

invokeAndHandle

  public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
          Object... providedArgs) throws Exception {
          --
          //执行请求方法,获取返回的结果
          --

      Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
      
      setResponseStatus(webRequest);

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

      mavContainer.setRequestHandled(false);
      Assert.state(this.returnValueHandlers != null, "No return value handlers");
      try {
      --
      //根据你的返回值,返回值类型,选择合适的返回值解析器进行解析以及返回数值绑定
      --
          this.returnValueHandlers.handleReturnValue(
                  returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
      }
      catch (Exception ex) {
          if (logger.isTraceEnabled()) {
              logger.trace(formatErrorForReturnValue(returnValue), ex);
          }
          throw ex;
      }
  }

 

invokeForRequest执行请求方法
  @Nullable
  public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
          Object... providedArgs) throws Exception {
          --
          //解析参数值
          --

      Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
      if (logger.isTraceEnabled()) {
          logger.trace("Arguments: " + Arrays.toString(args));
      }
      --
      //反射执行目标方法
      --
      return doInvoke(args);
  }

 

getMethodArgumentValues获取方法传递的参数
  protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
          Object... providedArgs) throws Exception {

      if (ObjectUtils.isEmpty(getMethodParameters())) {
          return EMPTY_ARGS;
      }
      --
      //获取方法传递的参数,包括参数携带的注解
      --
      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);
          args[i] = findProvidedArgument(parameter, providedArgs);
          if (args[i] != null) {
              continue;
          }
          --
          //给定的方法参数是否被任何注册的HandlerMethodArgumentResolver所支持。
          //支持则放入缓存中
          --
          if (!this.resolvers.supportsParameter(parameter)) {
              throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
          }
          try {
          --
          //解析参数
          //如果在在请求参数中传入的字段有和defaultModel(即之前@ModelAttribute加入的值)的字段一样
          //会在内部调用底层的doBind方法进行数据绑定
          //eg:例子中在请求参数中加入了name属性,book中又包含有name字段,此时会调用底层的方法进行绑定覆盖
          //如果在defaultModel没有这样的值,那么调用createAttribute创建一个实例
          --
              args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
          }
          catch (Exception ex) {
              // Leave stack trace for later, exception may actually be resolved and handled..
              if (logger.isDebugEnabled()) {
                  String error = ex.getMessage();
                  if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
                      logger.debug(formatArgumentError(parameter, error));
                  }
              }
              throw ex;
          }
      }
      return args;
  }

 
getMethodParameters获取方法的参数值
image-1665995871375

 

supportsParameter找到一个已注册的HandlerMethodArgumentResolver,它支持给定的方法参数。
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
      HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
      if (result == null) {
          for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
          --
          //具体的实现判断看supportsParameter
          --
              if (methodArgumentResolver.supportsParameter(parameter)) {
                  result = methodArgumentResolver;
                  this.argumentResolverCache.put(parameter, result);
                  break;
              }
          }
      }
      return result;
  }

Spring5.0的基本流程总结

1.如果有方法有标注@ModelAttribute注解,在请求执行前,
提前运行此方法,并将执行中要保存在defaultModel中的数据加入进去。

2.如果有ModelAttribute注解标注的参数,会在initModel方法执行的时候调用
container.mergeAttributes(sessionAttributes);合并到defaultModel中。

     	2.1如果此方法有返回值,那么返回值也会保存在defaultModel中
        
3.执行目标方法,确定目标方法的值

		 3.1无论参数是否有注解,统一使用this.resolvers.supportsParameter(parameter)判定,
         但如果参数的的首字母小写的值与@SessionAttributes中某个value值一样,
         那么会在container中找,找不到就抛异常
         
		  3.2如果有注解且标注了name值,那么尝试用标注的name值从defaultModel获取;
          如果没有注解,按参数的首字母小写作为name从defaultModel获取。
          
		3.3 如果是自定义类型参数,能从defaultModel中获取则获取并调用doBind进行数据绑定,
        如果获取不到,则利用反射创建一个对象。

this.resolvers.supportsParameter(parameter)判定使用的类型适配

image-1666010344169
 

4.0版本

invokeHandlerMethod

public String updateBook(@RequestParam(value="author")String author,Map<String, Object> model,
                      HttpServletRequest request, @ModelAttribute("haha")Book book
            )

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());执行目标方法的细节;
     ||
     \/
return invokeHandlerMethod(request, response, handler);
     ||
     \/
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
          throws Exception {
                         //拿到方法的解析器
      ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
        //方法解析器根据当前请求地址找到真正的目标方法
      Method handlerMethod = methodResolver.resolveHandlerMethod(request);
        //创建一个方法执行器;
      ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
        //包装原生的request, response,
      ServletWebRequest webRequest = new ServletWebRequest(request, response);
        //创建了一个,隐含模型
      ExtendedModelMap implicitModel = new BindingAwareModelMap();

       //真正执行目标方法;目标方法利用反射执行期间确定参数值,
       //提前执行modelattribute等所有的操作都在这个方法中;
      Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
      ModelAndView mav =
              methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
      methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
      return mav;
  }
  

 

方法执行的细节invokeHandlerMethod

方法执行的细节invokeHandlerMethod
public final Object invokeHandlerMethod(Method handlerMethod, Object handler,
          NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
      Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
      try {
          boolean debug = logger.isDebugEnabled();
          for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
              Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
              if (attrValue != null) {
                  implicitModel.addAttribute(attrName, attrValue);
              }
          }

        //找到所有@ModelAttribute注解标注的方法;
          for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
              Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
              //先确定modelattribute方法执行时要使用的每一个参数的值;
             Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
              if (debug) {
                  logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
              }
              String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
              if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
                  continue;
              }
              ReflectionUtils.makeAccessible(attributeMethodToInvoke);

             //提前运行ModelAttribute,
              Object attrValue = attributeMethodToInvoke.invoke(handler, args);
              if ("".equals(attrName)) {
                  Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
                  attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
              }
              //把提前运行的ModelAttribute方法的返回值也放在隐含模型中
              if (!implicitModel.containsAttribute(attrName)) {
                  implicitModel.addAttribute(attrName, attrValue);
              }
          }

             //再次解析目标方法参数是哪些值
          Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
          if (debug) {
              logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
          }
          ReflectionUtils.makeAccessible(handlerMethodToInvoke);

          //执行目标方法
          return handlerMethodToInvoke.invoke(handler, args);
      }
      catch (IllegalStateException ex) {
          // Internal assertion failed (e.g. invalid signature):
          // throw exception with full handler method context...
          throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
      }
      catch (InvocationTargetException ex) {
          // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
          ReflectionUtils.rethrowException(ex.getTargetException());
          return null;
      }
  }

 

确定方法运行时使用的每一个参数的值


private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
        NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
    Class<?>[] paramTypes = handlerMethod.getParameterTypes();
      //创建了一个和参数个数一样多的数组,会用来保存每一个参数的值
    Object[] args = new Object[paramTypes.length];


    for (int i = 0; i < args.length; i++) {
        MethodParameter methodParam = new MethodParameter(handlerMethod, i);
        methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
        GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
        String paramName = null;
        String headerName = null;
        boolean requestBodyFound = false;
        String cookieName = null;
        String pathVarName = null;
        String attrName = null;
        boolean required = false;
        String defaultValue = null;
        boolean validate = false;
        Object[] validationHints = null;
        int annotationsFound = 0;
        Annotation[] paramAnns = methodParam.getParameterAnnotations();
                                  //找到目标方法这个参数的所有注解,如果有注解就解析并保存注解的信息;
        for (Annotation paramAnn : paramAnns) {
            if (RequestParam.class.isInstance(paramAnn)) {
                RequestParam requestParam = (RequestParam) paramAnn;
                paramName = requestParam.value();
                required = requestParam.required();
                defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
                annotationsFound++;
            }
            else if (RequestHeader.class.isInstance(paramAnn)) {
                RequestHeader requestHeader = (RequestHeader) paramAnn;
                headerName = requestHeader.value();
                required = requestHeader.required();
                defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
                annotationsFound++;
            }
            else if (RequestBody.class.isInstance(paramAnn)) {
                requestBodyFound = true;
                annotationsFound++;
            }
            else if (CookieValue.class.isInstance(paramAnn)) {
                CookieValue cookieValue = (CookieValue) paramAnn;
                cookieName = cookieValue.value();
                required = cookieValue.required();
                defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
                annotationsFound++;
            }
            else if (PathVariable.class.isInstance(paramAnn)) {
                PathVariable pathVar = (PathVariable) paramAnn;
                pathVarName = pathVar.value();
                annotationsFound++;
            }
            else if (ModelAttribute.class.isInstance(paramAnn)) {
                ModelAttribute attr = (ModelAttribute) paramAnn;
                attrName = attr.value();
                annotationsFound++;
            }
            else if (Value.class.isInstance(paramAnn)) {
                defaultValue = ((Value) paramAnn).value();
            }
            else if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
                validate = true;
                Object value = AnnotationUtils.getValue(paramAnn);
                validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value});
            }
        }
        if (annotationsFound > 1) {
            throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +
                    "do not specify more than one such annotation on the same parameter: " + handlerMethod);
        }

                               //没有找到注解的情况;
        if (annotationsFound == 0) {
            //解析普通参数
            Object argValue = resolveCommonArgument(methodParam, webRequest);--
                          会进入resolveStandardArgument(解析标准参数)
            if (argValue != WebArgumentResolver.UNRESOLVED) {
                args[i] = argValue;
            }
            else if (defaultValue != null) {
                args[i] = resolveDefaultValue(defaultValue);
            }
            else {
                Class<?> paramType = methodParam.getParameterType();
                if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {
                    if (!paramType.isAssignableFrom(implicitModel.getClass())) {
                        throw new IllegalStateException("Argument [" + paramType.getSimpleName() + "] is of type " +
                                "Model or Map but is not assignable from the actual model. You may need to switch " +
                                "newer MVC infrastructure classes to use this argument.");
                    }
                    args[i] = implicitModel;
                }
                else if (SessionStatus.class.isAssignableFrom(paramType)) {
                    args[i] = this.sessionStatus;
                }
                else if (HttpEntity.class.isAssignableFrom(paramType)) {
                    args[i] = resolveHttpEntityRequest(methodParam, webRequest);
                }
                else if (Errors.class.isAssignableFrom(paramType)) {
                    throw new IllegalStateException("Errors/BindingResult argument declared " +
                            "without preceding model attribute. Check your handler method signature!");
                }
                else if (BeanUtils.isSimpleProperty(paramType)) {
                    paramName = "";
                }
                else {
                    attrName = "";
                }
            }
        }


           //确定值的环节
        if (paramName != null) {
            args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);
        }
        else if (headerName != null) {
            args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);
        }
        else if (requestBodyFound) {
            args[i] = resolveRequestBody(methodParam, webRequest, handler);
        }
        else if (cookieName != null) {
            args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);
        }
        else if (pathVarName != null) {
            args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
        }

           //确定自定义类型参数的值;还要将请求中的每一个参数赋值给这个对象
        else if (attrName != null) {
            WebDataBinder binder =
                    resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
            boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
            if (binder.getTarget() != null) {
                doBind(binder, webRequest, validate, validationHints, !assignBindingResult);
            }
            args[i] = binder.getTarget();
            if (assignBindingResult) {
                args[i + 1] = binder.getBindingResult();
                i++;
            }
            implicitModel.putAll(binder.getBindingResult().getModel());
        }
    }
    return args;
}

如果没有注解:

 1)、先看是否普通参数(resolveCommonArgument);----就是确定当前的参数是否是原生API;
@Override
    protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest) throws Exception {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);

        if (ServletRequest.class.isAssignableFrom(parameterType) ||
                MultipartRequest.class.isAssignableFrom(parameterType)) {
            Object nativeRequest = webRequest.getNativeRequest(parameterType);
            if (nativeRequest == null) {
                throw new IllegalStateException(
                        "Current request is not of type [" + parameterType.getName() + "]: " + request);
            }
            return nativeRequest;
        }
        else if (ServletResponse.class.isAssignableFrom(parameterType)) {
            this.responseArgumentUsed = true;
            Object nativeResponse = webRequest.getNativeResponse(parameterType);
            if (nativeResponse == null) {
                throw new IllegalStateException(
                        "Current response is not of type [" + parameterType.getName() + "]: " + response);
            }
            return nativeResponse;
        }
        else if (HttpSession.class.isAssignableFrom(parameterType)) {
            return request.getSession();
        }
        else if (Principal.class.isAssignableFrom(parameterType)) {
            return request.getUserPrincipal();
        }
        else if (Locale.class.equals(parameterType)) {
            return RequestContextUtils.getLocale(request);
        }
        else if (InputStream.class.isAssignableFrom(parameterType)) {
            return request.getInputStream();
        }
        else if (Reader.class.isAssignableFrom(parameterType)) {
            return request.getReader();
        }
        else if (OutputStream.class.isAssignableFrom(parameterType)) {
            this.responseArgumentUsed = true;
            return response.getOutputStream();
        }
        else if (Writer.class.isAssignableFrom(parameterType)) {
            this.responseArgumentUsed = true;
            return response.getWriter();
        }
        return super.resolveStandardArgument(parameterType, webRequest);
    }

2)、判断是否是Model或者是Map旗下的,如果是将之前创建的隐含模型直接赋值给这个参数;

方法上标注的ModelAttribute注解如果有value值   
@ModelAttribute("abc")
hahaMyModelAttribute()
        标了 :  attrName="abc"
        没标:attrName="";attrName就会变为返回值类型首字母小写,比如void ,或者book;

【@ModelAttribute标在方法上的另外一个作用;
可以把方法运行后的返回值按照方法上@ModelAttribute("abc")指定的key放到隐含模型中;
如果没有指定这个key;就用返回值类型的首字母小写】
{haha=Book [id=100, bookName=西游记, author=吴承恩, stock=98, sales=10, price=98.98], void=null}

如何确定方法的每一个参数的值;

标了注解:
          保存时哪个注解的详细信息;
          如果参数有ModelAttribute注解;
               拿到ModelAttribute注解的值让attrName保存
                    attrName="haha"


没标注解:
          1)、先看是否普通参数(是否原生API)
               再看是否Model或者Map,如果是就传入隐含模型;
          2)、自定义类型的参数没有ModelAttribute 注解
                    1)、先看是否原生API
                    2)、再看是否Model或者Map
                    3)、再看是否是其他类型的比如SessionStatus、HttpEntity、Errors
           4)、再看是否简单类型的属性;比如是否Integer,String,基本类型
                    如果是paramName=“”
           5)、attrName="";
如果是自定义类型对象,最终会产生两个效果;
     1)、如果这个参数标注了ModelAttribute注解就给attrName赋值为这个注解的value值
     2)、如果这个参数没有标注ModelAttribute注解就给attrName赋值"";

确定自定义类型参数的值;

SpringMVC确定POJO值的三步;
1、如果隐含模型中有这个key(标了ModelAttribute注解就是注解指定的value,没标就是参数类型的首字母小写)指定的值;
          如果有将这个值赋值给bindObject;
2、如果是SessionAttributes标注的属性,就从session中拿;
3、如果都不是就利用反射创建对象;
private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam,
            ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception {

        // Bind request parameter onto object...  
        String name = attrName;
     
        if ("".equals(name)) {
               //如果attrName是空串;就将参数类型的首字母小写作为值  Book book2121;name=book
            name = Conventions.getVariableNameForParameter(methodParam);
        }
        Class<?> paramType = methodParam.getParameterType();
        Object bindObject;确定目标对象的值
        if (implicitModel.containsKey(name)) {
            bindObject = implicitModel.get(name);
        }
        else if (this.methodResolver.isSessionAttribute(name, paramType)) {
            bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);
            if (bindObject == null) {
                raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session");
            }
        }
        else {
            bindObject = BeanUtils.instantiateClass(paramType);
        }
        WebDataBinder binder = createBinder(webRequest, bindObject, name);
        initBinder(handler, name, binder, webRequest);
        return binder;
    }

 

Spring4.0中的基本流程

两件事:
1)、运行流程简单版;
2)、确定方法每个参数的值;
          1)、标注解:保存注解的信息;最终得到这个注解应该对应解析的值;
          2)、没标注解:
                    1)、看是否是原生API;
                    2)、看是否是Model或者是Map,xxxx
                    3)、都不是,看是否是简单类型;paramName;
                    4)、给attrName赋值;attrName(参数标了@ModelAttribute("")就是指定的,没标就是"")
                              确定自定义类型参数:
                                   1)、attrName使用参数的类型首字母小写;或者使用之前@ModelAttribute("")的值
                                   2)、先看隐含模型中有每个这个attrName作为key对应的值;如果有就从隐含模型中获取并赋值
                                   3)、看是否是@SessionAttributes(value="haha");标注的属性,如果是从session中拿;
                                                            如果拿不到就会抛异常;
                                   4)、不是@SessionAttributes标注的,利用反射创建一个对象;
                   5)、拿到之前创建好的对象,使用数据绑定器(WebDataBinder)将请求中的每个数据绑定到这个对象中;

Spring 4版本和Spring 5版本部分的流程差别

有差异的流程 Spring4.0 Spring5.0
确定pojo 如果隐含模型中有这个key(标了ModelAttribute注解就是注解指定的value,没标就是参数类型的首字母小写)指定的值;如果有将这个值赋值给bindObject;如果是SessionAttributes标注的属性,就从session中拿;如果都不是就利用反射创建对象 在任何方法执行的时候都会调用initModel方法,将SessionAttributes中的值合并到container中,那么后续就不会再有从session的操作,直接从模型中取,没有就直接创建对象
确定入参的参数类型 有一大长串的代码进行类型的判定 在扫描参数的时候,将入参的所有信息都保存,然后使用this.resolvers.supportsParameter(parameter)增强for循环进行判定
SessionAttributes获取值问题 同右 调用任何一个方法,如果方法参数带有ModelAttribute注解且vlaue值和SessionAttributes中有一样的,那么就会扫描一遍mavcontainer中是否有标注value一样名字的属性,找不到直接抛异常
标注ModelAttribute注解方法的返回值为 viod是否保存在defaultModel 保存 ,其他返回值也保存 , 如String 等 不保存 ,只保存其他返回值,如String 等

评论