SpringMVC源码分析

Spring MVC中DispatchServlet运行流程

  1. doDispatch()详细细节

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
    ModelAndView mv = null;
    Exception dispatchException = null;

    try {
    //1、 检查是否文件上传请求
    processedRequest = checkMultipart(request);
    multipartRequestParsed = processedRequest != request;

    /****** Determine handler for the current request.*/
    //2、根据当前的请求地址找到那个类能来处理
    mappedHandler = getHandler(processedRequest);
    if (mappedHandler == null || mappedHandler.getHandler() == null) {
    //3、如果没有找到处理器可以处理当前请求,抛出异常
    noHandlerFound(processedRequest, response);
    return;
    }

    // Determine handler adapter for the current request.
    //4、拿到可以执行这个处理器类的所有方法的适配器(反射工具)
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

    // Process last-modified header, if supported by the handler.
    String method = request.getMethod();
    boolean isGet = "GET".equals(method);
    if (isGet || "HEAD".equals(method)) {
    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    if (logger.isDebugEnabled()) {
    String requestUri = urlPathHelper.getRequestUri(request);
    logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
    }
    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    return;
    }
    }

    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
    }

    try {



    /************
    ***注意:控制器执行*******
    *************
    */
    //5、适配器来回显目标方法:将目标方法执行完成后的返回值作为视图名,设置保存到ModelAndView
    //目标方法无论怎么写,最终适配器执行完后,都会封装为ModelAndView
    // Actually invoke the handler.
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());





    }
    finally {
    if (asyncManager.isConcurrentHandlingStarted()) {
    return;
    }
    }

    applyDefaultViewName(request, mv);//如果没有视图名,取默认
    mappedHandler.applyPostHandle(processedRequest, response, mv);
    }
    catch (Exception ex) {
    dispatchException = ex;
    }
    /************
    ***注意:转发目标页面执行*******
    *************
    */
    //6、根据方法最终执行完成后封装的ModelAndView,转发到对应页面,而且ModelAndView中的数据可以从请求域中获取
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
    triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Error err) {
    triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
    }
    finally {
    if (asyncManager.isConcurrentHandlingStarted()) {
    // Instead of postHandle and afterCompletion
    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    return;
    }
    // Clean up any resources used by a multipart request.
    if (multipartRequestParsed) {
    cleanupMultipart(processedRequest);
    }
    }
    }

    1. 所有请求过来DispatchServlet收到请求

    2. 调用doDispatch() 方法进行处理

      1. getHandler(): 根据当前请求地址找到能处理这个请求的的目标的类(处理器)

        ​ 根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类

      2. getHandlerAdapter():根据当前处理器获取到能执行这个处理器方法的适配器

        根据当前处理器类,找到当前类的HandlerAdapter

      3. 使用当前获取到的适配器(RequestMappingHandlerAdapter)执行目标方法

      4. 目标方法执行后会返回一个ModelAndView对象

      5. 根据ModelAndView的信息转发到具体的页面,并可以在请求域中取出ModelAndView中的模型数据


  1. getHandler()细节:怎么根据当前请求就能找到哪个类能处理

    getHandler() 会返回目标处理器类的执行链

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //HandlerMappings处理器映射:他里面保存了每一个处理器能处理那些方法的映射信息
    for (HandlerMapping hm : this.handlerMappings) {
    if (logger.isTraceEnabled()) {
    logger.trace(
    "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
    }
    HandlerExecutionChain handler = hm.getHandler(request);
    if (handler != null) {
    return handler;
    }
    }
    return null;
    }

    handlerMap: ioc容器自动创建Controller对象的时候扫描每个处理器都能处理什么请求,保存在HandlerMapping的handlerMap属性中:下一次请求过来就来查看那个handlerMapping中有相应的请求映射信息

  2. getHandlerAdapter() 细节(如何找到目标处理器类的适配器?)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    for (HandlerAdapter ha : this.handlerAdapters) {
    if (logger.isTraceEnabled()) {
    logger.trace("Testing handler adapter [" + ha + "]");
    }
    if (ha.supports(handler)) {
    return ha;
    }
    }
    throw new ServletException("No adapter for handler [" + handler +
    "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

  1. 研究HandlerMappings和HandlerAdapters如何获取值,

    可以在web.xml中修改DispatchServlet某些属性的默认配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;

    if (this.detectAllHandlerMappings) {
    // 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<HandlerMapping>(matchingBeans.values());
    // We keep HandlerMappings in sorted order.
    OrderComparator.sort(this.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.
    if (this.handlerMappings == null) {
    this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
    if (logger.isDebugEnabled()) {
    logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
    }
    }
    }

    组件的初始化:

    ​ 有些组件是通过类型找,有些是通过id

    ​ 去容器中找这个组件,如果没有找到就用默认配置

  2. 如何调用目标方法?

    1. DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse) line: 945
    2. AnnotationMethodHandlerAdapter.handle(HttpServletRequest, HttpServletResponse, Object) line: 406
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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);
    //包装原生的response和request
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    //创建隐含模型
    ExtendedModelMap implicitModel = new BindingAwareModelMap();
    //真正执行目标方法
    //目标方法执行期间利用反射执行期间确定参数值
    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;
    }
    1. AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker(HandlerMethodInvoker).invokeHandlerMethod

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      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()) {
      //先确定modelattribute方法执行是要使用的每一个参数的值
      Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
      //args
      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);
      Object attrValue = attributeMethodToInvoke.invoke(handler, args);
      if ("".equals(attrName)) {
      Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
      attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
      }
      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;
      }
      }
      1. 确定方法运行时使用的每一个参数值
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      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);-->解析标准参数
      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
      2. 如果是Map或者Map子类,将之前创建的隐含模型赋值过去


      方法上标注的ModelAttribute注解如果有value值

      @ModelAttribute(value=”as”)

      attrName=value标注值

      标了:attrName=”abc”

      没标:attrName=””;attrName就会变为返回值类型首字母小写

      @ModelAttribute标在方法的另一个作用;可以把方法运行后的返回值按照@ModelAttribute(“abc”)放到隐含模型中,如果没有key就用返回值类型void

      {person=Person [name=as, pwd=12, gender=qw, email=asas], void=null}

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      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);
      }
      }
      for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
      Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
      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);
      }
      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;
      }
      }
  1. 如何确定方法的每一个参数的值

    标了注解:

     保存时哪个注解的信息确定值

     拿到ModelAttribute注解的值让attrName保存

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    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);
    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. 先看是否为普通参数(是否为原生API)

      再看是否Model或者Map,如果是传入隐含模型

    2. 自定义类型的参数没有注解没有ModelAttribute注解

      1. 先看原生API
      2. 在看是否是Map或ModelMap
      3. 在看看是不是其他类型,比如SessionStatus、HttpEntity、Errors
      4. 是否为简单属性,是否Integer、String基本类型
        1. 如果paramName=“”
      5. AttrName=””

    如果是自定义类型对象,最终会产生两个效果

    1. 如果这个参数标注了ModelAttribute注解就给attrName赋值,为这个注解Value值
    2. 如果没有,就为“”
  2. 确定自定义类型的值(POJO)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    private void doBind(WebDataBinder binder, NativeWebRequest webRequest, boolean validate,
    Object[] validationHints, boolean failOnErrors) throws Exception {

    doBind(binder, webRequest);
    if (validate) {
    binder.validate(validationHints);
    }
    if (failOnErrors && binder.getBindingResult().hasErrors()) {
    throw new BindException(binder.getBindingResult());
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    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)) {
    name = Conventions.getVariableNameForParameter(methodParam);
    }
    Class<?> paramType = methodParam.getParameterType();
    //如果隐含模型有这个key(标了ModelAttribute注解就是注解标定的值,没标就是参数类型首字母小写)指定的值
    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;
    }
    1. 如果隐含模型有这个key(标了ModelAttribute注解就是注解标定的值,没标就是参数类型首字母小写)指定的值

      如果有将这个值赋值给bindObject

    2. 如果是SessionAttributes标注的属性,就从Session中拿

    3. 如果都不是,就用反射创建一个


  1. 确定方法每个参数的值

    1. 标注解:保存注解信息;最终得到这个注解应该对应解析的值

    2. 没标注解

      1. 先看是否是否为原生API

      2. 是否为Model或Map

      3. 看是否为简单类型

      4. 给attrName赋值,参数标了ModelAttribute就是指定的,没标就位空串

        确定自定义类型参数

        1. attrName使用参数类型首字母小写;或者使用之前@ModelAttribute的值

        2. 先看隐含模型中是否有这个attrName对应的值;如果有就从隐含模型中获取并赋值

        3. 看是否SessionAttrinute标注的属性,如果是从Session中拿

          拿不到抛异常

        4. 不是SessionAttributes标注的值,利用反射创建一个

      5. 拿到之前创建好的对象,使用数据绑定器(WebDataBinder)将请求的么个数据绑定到这个对象中


SpringMVC九大组件

在DispatchServlet中有几个引用类型属性。关键位置都是由这些组件完成的

共同点: 九大组件都是接口:接口就是规范,提供了强大的扩展性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/** MultipartResolver used by this servlet */
//文件上传解析器
private MultipartResolver multipartResolver;

/** LocaleResolver used by this servlet */
//区域信息析器与国际化有关
private LocaleResolver localeResolver;

/** ThemeResolver used by this servlet */
//主题解析器:主题效果更换
private ThemeResolver themeResolver;

/** List of HandlerMappings used by this servlet */
//Handler映射信息:HandlerMapping
private List<HandlerMapping> handlerMappings;

/** List of HandlerAdapters used by this servlet */
//Handler适配器
private List<HandlerAdapter> handlerAdapters;

/** List of HandlerExceptionResolvers used by this servlet */
//SpringMVC强大的异常解析功能
private List<HandlerExceptionResolver> handlerExceptionResolvers;

/** RequestToViewNameTranslator used by this servlet */
//
private RequestToViewNameTranslator viewNameTranslator;

/** FlashMapManager used by this servlet */
//SpringMVC中运行重定向携带数据的功能
private FlashMapManager flashMapManager;

/** List of ViewResolvers used by this servlet */
//视图解析器
private List<ViewResolver> viewResolvers;

DispatchServlet中onRefresh方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×