VVL1295

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Spring MVC过程分析(除视图解析过程)

  写在最前,本文的源码分析基于4.2.3版本的Spring,采用的是RequestMappingHandlerMapping

  1,DispatcherServlet的doDispactch方法,调用DispatcherServlet的getHandler方法;

  2,DispatcherServlet的getHandler方法,遍历注册的HandlerMapping,寻找到适合的HandlerMapping,此处是RequestMappingHandlerMapping,调用RequestMappingHandlerMapping的getHandler方法;

  3,DefaultAnnotationRequestMapping的getHandler方法(AbstractHandlerMapping的),调用DefaultAnnotationRequestMapping的getHandlerInternal方法,该方法返回一个HandlerExecutionChain对象,内含handler和interceptor;

  4,DefaultAnnotationRequestMapping的getHandlerInternal方法(AbstractUrlHandlerMapping的),调用getUrlPathHelper().getLookupPathForRequest(request),根据URL找到对应的handler,返回handler;

  5,DefaultAnnotationRequestMapping的getHandler方法(AbstractHandlerMapping的),调用DefaultAnnotationRequestMapping的getHandlerExecutionChain(handler, request);

  6,DefaultAnnotationRequestMapping的getHandlerExecutionChain(handler, request)(AbstractHandlerMapping的),把适合的interceptor添加进HandlerExecution对象里,返回HandlerExecutionChain对象;

  7,然后,继续执行doDispatch方法,调用getHandler方法,此处返回的是AnnotationMethodHandlerAdapter对象;

  8,继续执行doDispatch方法,调用handlerAdapter的handle方法;

  9,handlerAdapter的handle方法(AnnotationMethodHandlerAdapter的),调用AnnotationMethodHandlerAdapter的invokeHandlerMethod方法;

  10,AnnotationMethodHandlerAdapter的invokeHandlerMethod方法,创建ServletHandlerMethodInvoker类型的对象methodInvoker用于调用HandlerMethod,创建ExtendedModelMap类型的对象implicittModel用于存储视图中的数据,调用methodInvoker的invokeHandlerMethod方法(HandlerMethodInvoker的);

  11,methodInvoker的invokeHandlerMethod方法(HandlerMethodInvoker的),把sessionAttributeStore里的属性添加到implicitModel中,然后遍历所有被@ModelAttribute修饰的方法,循环体内,调用resolveHandlerArguments方法(用于处理@ModelAttribute 注解修饰的方法的各种参数,和处理功能处理方法的参数的方式一样),如果方法里有参数的类型是Map或ModelMap或Model,则把implicitModel作为参数传入方法,然后继续执行循环体,获得@ModelAttribute的属性值,如果implicitModel已经含有与该属性值同名的属性,那么将不执行该方法,反之,执行该方法,若@ModelAttribute没有value属性值,那么放进implicitModel的属性的属性名为把返回值类型的类型名的首字母改为小写的类型名字符串(即Tax改为tax),然后处理功能处理方法部分,调用resolveHandlerArguments方法,处理各种类型的参数,其中需要说明的是被@ModelAttribute修饰的参数和bindingResult,resolveModelAttribute时,如果@ModelAttribute的参数值是SessionAttribute,但其不存在impliciteModel中,则抛出异常,如果implicitModel存在于参数值存在的属性,则把属性赋值给bindObject,对于bindingResult,若@ModelAttribute的参数值不为null,则处理绑定,把binder.getBindingResult().getModel()放进implicitModel里,该Model是一个Map对象,里面有两个entry,一个是objectName+target,一个是BindingResult的Prefix拼接objectName+target,处理完功能处理方法的参数,就调用方法,返回一个Object对象;

  12,继续执行AnnotationMethodHandlerAdapter的invokeHandlerMethod方法,调用methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest)方法,其中result是功能处理方法的返回值;

  13,methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest)方法,处理功能处理方法的不同情况,包括返回一个mv,返回一个字符串,返回值为void,返回值被@ResponseBody修饰等,如果想客户端返回一个网页,则返回一个mv,否则,返回null;

  14,继续执行AnnotationMethodHandlerAdapter的invokeHandlerMethod方法,调用methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest)方法;

  15,methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest)方法,方法体内,如果sessionStatus.isComplete()方法返回true,则删掉所有的sessionAttribute,且会把mavModel(implicitModel)的全部sessionAttribute属性设为陈旧的,并放进implicitModel里,如果sessionStatus.isComplete()方法返回false且若属性不是陈旧的,则把mavModel(implicitModel)的属性放进sessionAttribute里,继续,把bindingResultKey和bindingResult放进mavModel(implicitModel)里,过程中进行了绑定,其实就是为了更新SessionAttribute,因为implicitModel中的SessionAttribute可能被更新,所以最后要进行更新,而关于bindingResult,就是针对@ModelAttribute没有参数值(即该参数值为null)的情况而做的补充处理,即无论如何都要进行绑定和把BingResult的model放进去implicitModel;

  16,继续执行methodInvoker的invokeHandlerMethod方法(HandlerMethodInvoker的),返回mav,整个过程完成,接下来就是试图解析;

 

  总的来说,过程是这样的:

    如果 @SessionAttributes 修饰 Controller,那么先把 session 中与 @SessionAttributes value参数的参数值同名的 attribute 放进 Model 中,然后执行 @ModelAttribute 修饰的方法,如果 Model 中有与 @ModelAttribute 的参数 value 的参数值同名的 attribute,那就不执行该方法,否则执行;执行完 @ModelAttribute 修饰的方法,开始执行处理方法,对于 @ModelAttribute 修饰的参数,如果 Model 中有同名的,就直接获取 Model 中的参数,否则通过反射创建一个,然后执行方法体,@ModelAttribute 会把入参暴露成模型数据;注意,参数名不要重名,那就不用考虑优先级,更好地避免隐蔽的错误,提高可读性。

    注意点:即便不加 @RequestParam 注解,SpringMVC也会试图对入参进行数据绑定;@ModelAttribute 会使入参暴露到模型数据,不然就只能 addObject 进行添加模型数据;

posted on 2016-10-29 14:21  bobo2018  阅读(180)  评论(0)    收藏  举报