将获取参数合并到mavContainer中金沙js娱乐场官方网站:,将获取参数合并到mavContainer中

HandlerMethod及子类主要用于封装方法调用相关信息,参数准备和返回值处理的职责.,HandlerMethod及子类主要用于封装方法调用相关信息,参数准备和返回值处理的职责.,  2. 处理器执行后将modle中相应参数设置到SessionAttributes中,将获取参数合并到mavContainer中,  2. 处理器执行后将modle中相应参数设置到SessionAttributes中,将获取参数合并到mavContainer中,所以这时需要一个适配类,SimpleControllerHandlerAdapter 适配 Controller 接口的 HandlerAdapter

金沙js娱乐场官方网站 3

SpringMVC源码分析,springmvc源码

HandlerMethod及子类首要用以封装方法调用相关消息,子类还提供调用,参数准备和重返值管理的义务.

金沙js娱乐场官方网站 1

分析下相继类的天职吧(顺便做分析目录):

HandlerMethod 封装方法定义相关的音信,如类,方法,参数等.

  使用处境:HandlerMapping时会使用

InvocableHandlerMethod 增加参数计划,方法调用成效

  使用境况:实行使用@ModelAttribute注明会采用

ServletInvocableHandlerMethod 加多再次回到值管理职分,ResponseStatus处理

  使用情况:推行http相关方法会使用,比如调用管理实施

 

1. HandlerMethod

 HandlerMethod其实能够总结明了为涵养方法新闻的pojo.

进而这里重要正是看下定义的习性:

 1 package org.springframework.web.method;
 2 public class HandlerMethod {
 3     /** 什么鬼,给子类提供logger,到现在为止源码中不多见 */
 4     protected final Log logger = LogFactory.getLog(HandlerMethod.class);
 5     // 方法所在的类,如果是String类型,可以去容器中获取
 6     private final Object bean;
 7     // 方法
 8     private final Method method;
 9     // 类管理的容器
10     private final BeanFactory beanFactory;
11     // 方法的参数
12     private final MethodParameter[] parameters;
13     // 如果方法是bridged方法,则对应原始方法
14     private final Method bridgedMethod;
15     // ...
16 }

绝大非常多应有是看看注释就可以精通了,大家解释下下边:

  那边全部的听得多了就能说的清楚都以final类型的,不可修改,所以若是出现修改须要new.

  尽管bean是string,是在createWithResolvedBean找容器获取实例的.

  MethodParameter类封装了参数相关的消息.

  提供获取再次来到值,决断是还是不是void类型,还恐怕有读取声明

 

createWithResolvedBean逻辑其实很简短:

确认下若是bean是String类型的,那么从容器BeanFactory中获取,并选择private
HandlerMethod(HandlerMethod handlerMethod, Object handler) new多少个新的.

1 // HandlerMethod
2     public HandlerMethod createWithResolvedBean() {
3         Object handler = this.bean;
4         if (this.bean instanceof String) {
5             String beanName = (String) this.bean;
6             handler = this.beanFactory.getBean(beanName);
7         }
8         return new HandlerMethod(this, handler);
9     }

 

MethodParameter,能够依据method方法和parameterIndex(参数下标)独一明显,其余质量都足以依赖他们两获取.

由于反射中绝非参数名的音信,而那边要求,所以Spring增添了一个参数名查找器ParameterNameDiscover.

那边重返值的花色是积累在parameters属性中的,下标用-1区分.

MethodParameter在HandlerMethod有七个里头类的子类.

 1 package org.springframework.core;
 2 public class MethodParameter {
 3     // 参数所在方法
 4     private final Method method;
 5     // 参数的构造方法
 6     private final Constructor constructor;
 7     // 参数下标
 8     private final int parameterIndex;
 9     // 参数类型
10     private Class<?> parameterType;
11     // Type类型的参数类型
12     private Type genericParameterType;
13     // 参数使用的注解
14     private Annotation[] parameterAnnotations;
15     // 参数名查找器
16     private ParameterNameDiscoverer parameterNameDiscoverer;
17     // 参数名
18     private String parameterName;
19     // 参数嵌套级别,如Map<String>中map为1,string为2
20     private int nestingLevel = 1;
21     // 每层的下标
22     /** Map from Integer level to Integer type index */
23     Map<Integer, Integer> typeIndexesPerLevel;
24     // 什么鬼?就一个构造方法用了,其他都没有使用
25     Map<TypeVariable, Type> typeVariableMap;
26     // ... 
27 }

 

 

2. InvocableHandlerMethod

习于旧贯性的,看到Invocable,会想到Spring会不会定义五个接口来定义可调用概念,然则未有.

那边增多了2个职务:参数绸缪和方式推行.

参数希图委托HandlerMethodArgumentResolver实行实际的分析.剖判的时候须求用到WebDataBinder,所以顺便带上.对参数剖判器有意思味能够运动这里

 

2.1 先来看看参数筹算干活有的吧.

招来某些参数值的逻辑:

  a, 先委托参数名查找器获取参数名

  b,从表面提供的参数清单中查找值(竟然是依照项目判定的)

  c,若无直接提供,使用参数深入分析器创设

  d,假诺仍然未有博得,直接报错

 1 package org.springframework.web.method.support;
 2 
 3 public class InvocableHandlerMethod extends HandlerMethod {
 4     // 参数解析器
 5     private HandlerMethodArgumentResolverComposite argumentResolvers = new HandlerMethodArgumentResolverComposite();
 6     // 参数解析器需要用到
 7     private WebDataBinderFactory dataBinderFactory;
 8     // 参数名查找器
 9     private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
10 
11     private Object[] getMethodArgumentValues(
12             NativeWebRequest request, ModelAndViewContainer mavContainer,
13             Object... providedArgs) throws Exception {
14 
15         MethodParameter[] parameters = getMethodParameters();
16         Object[] args = new Object[parameters.length];
17         for (int i = 0; i < parameters.length; i++) {
18             MethodParameter parameter = parameters[i];
19             parameter.initParameterNameDiscovery(parameterNameDiscoverer);
20             // 查找参数名
21             GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
22             // 从提供的参数值providedArgs中找值
23             args[i] = resolveProvidedArgument(parameter, providedArgs);
24             if (args[i] != null) {
25                 continue;
26             }
27             // 使用参数解析器解析
28             if (argumentResolvers.supportsParameter(parameter)) {
29                 try {
30                     args[i] = argumentResolvers.resolveArgument(parameter, mavContainer, request, dataBinderFactory);
31                     continue;
32                 } catch (Exception ex) {
33                     throw ex;
34                 }
35             }
36             // 参数获取不到是需要报错的
37             if (args[i] == null) {
38                 String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
39                 throw new IllegalStateException(msg);
40             }
41         }
42         return args;
43     }
44 
45     private Object resolveProvidedArgument(MethodParameter parameter, Object... providedArgs) {
46         if (providedArgs == null) {
47             return null;
48         }
49         for (Object providedArg : providedArgs) {
50             // 竟然是根据类型判断的
51             if (parameter.getParameterType().isInstance(providedArg)) {
52                 return providedArg;
53             }
54         }
55         return null;
56     }
57 
58     // ...
59 
60 }

 2.2 方法实践

这边的逻辑其实很简短:

  委托获取形式试行需求的参数

  强制将艺术成为可用

  管理方法试行进程中的格外

 

 1 package org.springframework.web.method.support;
 2 
 3 public class InvocableHandlerMethod extends HandlerMethod {
 4     // ... 
 5     public final Object invokeForRequest(NativeWebRequest request,
 6                                          ModelAndViewContainer mavContainer,
 7                                          Object... providedArgs) throws Exception {
 8         Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
 9         Object returnValue = invoke(args);
10         return returnValue;
11     }
12 
13     private Object invoke(Object... args) throws Exception {
14         ReflectionUtils.makeAccessible(this.getBridgedMethod());
15         try {
16             return getBridgedMethod().invoke(getBean(), args);
17         }
18         catch (IllegalArgumentException e) {
19             String msg = getInvocationErrorMessage(e.getMessage(), args);
20             throw new IllegalArgumentException(msg, e);
21         }
22         catch (InvocationTargetException e) {
23             // Unwrap for HandlerExceptionResolvers ...
24             Throwable targetException = e.getTargetException();
25             if (targetException instanceof RuntimeException) {
26                 throw (RuntimeException) targetException;
27             }
28             else if (targetException instanceof Error) {
29                 throw (Error) targetException;
30             }
31             else if (targetException instanceof Exception) {
32                 throw (Exception) targetException;
33             }
34             else {
35                 String msg = getInvocationErrorMessage("Failed to invoke controller method", args);
36                 throw new IllegalStateException(msg, targetException);
37             }
38         }
39     }
40 
41 }

 

 

3. ServletInvocableHandlerMethod

  委托HandlerMethodReturnValueHandler加多重临值管理功效

  增添@ResponseStatus申明援助.

 

那边使用的@ResponseStatus注明多个属性:value状态码,reason
写入response的表明文字

 

3.1 设置response status时的逻辑:

  responseStatus没安装就回去

  responseReason存在则步入error

  把responseStatus设置到request,RedirectView须求利用 

 1 // ServletInvocableHandlerMethod
 2     private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
 3         if (this.responseStatus == null) {
 4             return;
 5         }
 6 
 7         if (StringUtils.hasText(this.responseReason)) {
 8             webRequest.getResponse().sendError(this.responseStatus.value(), this.responseReason);
 9         }
10         else {
11             webRequest.getResponse().setStatus(this.responseStatus.value());
12         }
13 
14         // to be picked up by the RedirectView
15         webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, this.responseStatus);
16     }

3.2 invokeAndHandle

  委托父类施行乞请

  添加ResponseStatus支持

  然后判定哪些才是实行完成,满意一下任性二个:

    request的notModified为真,使用@ResponseStatus注解,mavContainer的requestHandled为真

  委托HandlerMethodReturnValueHandler封装重返值

 1 // ServletInvocableHandlerMethod
 2     public final void invokeAndHandle(ServletWebRequest webRequest,
 3             ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
 4 
 5         Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
 6 
 7         setResponseStatus(webRequest);
 8 
 9         if (returnValue == null) {
10             if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
11                 mavContainer.setRequestHandled(true);
12                 return;
13             }
14         }
15         else if (StringUtils.hasText(this.responseReason)) {
16             mavContainer.setRequestHandled(true);
17             return;
18         }
19 
20         mavContainer.setRequestHandled(false);
21 
22         try {
23             this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
24         }
25         catch (Exception ex) {
26             if (logger.isTraceEnabled()) {
27                 logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
28             }
29             throw ex;
30         }
31     }

 

HandlerMethod及子类主要用以封装方法调用相关消息,子类还提供调用,参数打算和再次来到值处理的义务.
剖析下相继…

HandlerMethod及子类首要用来封装方法调用相关新闻,子类还提供调用,参数计划和重回值管理的职分.

SpringMVC源码深入分析- HandlerAdapter,springmvchandler

ModelFactory主即使四个职分:

  1. 初始化model

  2. Computer实施后将modle中相应参数设置到SessionAttributes中

 

大家来拜望现实的拍卖逻辑(直接充当深入分析目录):

  1. 初始化model

  1.1 分析类上选用的sessionAttributres,将得到参数合併到mavContainer中

  1.2 试行声明了@ModelAttribute的主意,并将结果共同到Model

    参数名的变化准则:@ModelAttribute中定义的value >
方法的回来类型决定(直接往model.addAttribute的不外乎)

  1.3
将注解@ModelAttribute方法参数(在@SessionAttributes定义范围内)同步到model中

     将艺术中运用@ModelAttribute的参数跟@SessionAttribute核对,假使都定义了,需求将其参数值同步至mavContainer

  1. 处理器施行后将modle中相应参数设置到SessionAttributes中

  2.1
假如SessionStatus被调用了setComplete则清除sesssionAttributesHandler中缓存的数据

  2.2 如若没清除,将model中的数据同步至sessionAttributesHandler中

  2.3
假如handler还没管理完(是还是不是需求渲染页面),绑定BindingResult到model(若是要求的话)

  上面包车型大巴代码表达在一般费用时,SessionStatus.setComplete写在情势哪个地点都行,因为她是在点子执行后才在那边调用,跟艺术中的顺序毫不相关.

 

 1. 初始化model

做了多少个业务,详细见源码中的注释吧:

 1 package org.springframework.web.method.annotation;
 2 public final class ModelFactory {
 3     public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod)
 4             throws Exception {
 5     // 获取使用@SessionAttributes注解并已经解析的参数,合并到mavContainer
 6         Map<String, ?> attributesInSession = this.sessionAttributesHandler.retrieveAttributes(request);
 7         mavContainer.mergeAttributes(attributesInSession);
 8     // 执行使用@ModelAttribute注解的方法,并将结果设置到mavContainer
 9         invokeModelAttributeMethods(request, mavContainer);
10     // 将同时使用@ModelAttribute和@SessionAttributes注解的参数设置到mavContainer
11         for (String name : findSessionAttributeArguments(handlerMethod)) {
12             if (!mavContainer.containsAttribute(name)) {
13                 Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
14                 if (value == null) {
15                     throw new HttpSessionRequiredException("Expected session attribute '" + name + "'");
16                 }
17                 mavContainer.addAttribute(name, value);
18             }
19         }
20     }
21     // ...
22 }

 

1.1 分析类上采用的sessionAttributres,将获取参数合併到mavContainer中

这一部分,此前的<SpringMVC源码深入分析 – HandlerAdapter –
@SessionAttributes注脚管理>已经陈述得相当细,那边就不张开.

 

1.2 试行申明了@ModelAttribute的不二秘诀,并将结果一块到Model

  迭代全体应用@ModelAttribute证明的法子

  获取@ModelAttribute中的value属性值作为 model
attribute,要是mavContainer中早就存在则脱离

  委托InvocableHandlerMethod的invokeForRequest生成属性值.

    a,获取当前情势的调用参数

    b,直接推行invoke,并回到结果

  假若艺术不是void的,则须求将值同步到mavContainer

    a,若是格局是void,则表明用户一向将参数通过model.addAttribute设置好值了

    b,参数名的浮动法规:@ModelAttribute中定义的value >
方法的回来类型决定

    依照办法的回来类型决定参数名时,差不离的条条框框如下:

      String ->
string(那边就表达本身在此之前没搞精通使用@ModelAttribute评释实例的结尾七个情景)

      List<Double> -> doubleList

    c,假使mavContainer中还并未那么些参数值,则一同踏入

 1 package org.springframework.web.method.annotation;
 2 public final class ModelFactory {
 3     private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer mavContainer)
 4             throws Exception {
 5         // 迭代使用@ModelAttribute注解的方法
 6         for (InvocableHandlerMethod attrMethod : this.attributeMethods) {
 7             // 使用@ModelAttribute的value值作为 attribute name
 8             String modelName = attrMethod.getMethodAnnotation(ModelAttribute.class).value();
 9             if (mavContainer.containsAttribute(modelName)) {
10                 continue;
11             }
12             // 委托InvocableHandlerMethod调用方法,生成值
13             Object returnValue = attrMethod.invokeForRequest(request, mavContainer);
14             // 如果方法返回值,需要将这个值同步到mavContainer中
15             if (!attrMethod.isVoid()){
16                 // 生成参数名:注解的value或者返回值类型
17                 String returnValueName = getNameForReturnValue(returnValue, attrMethod.getReturnType());
18                 if (!mavContainer.containsAttribute(returnValueName)) {
19                     mavContainer.addAttribute(returnValueName, returnValue);
20                 }
21             }
22         }
23     }
24     // ...
25 }

 

看看InvocableHandlerMethod的invokeForRequest(NativeWebRequest
request,ModelAndViewContainer mavContainer,Object… providedArgs)

  那边境海关系到多少个封装类:InvocableHandlerMethod和MethodParameter.

  InvocableHandlerMethod封装一个可推行的艺术,在HandlerMethod基础上增多方法参数分析的职务.

  MethodParameter封装方法定义相关的概念

切切实实的管理逻辑照旧看代码中的注释吧.

 1 package org.springframework.web.method.support;
 2 public class InvocableHandlerMethod extends HandlerMethod {
 3     public final Object invokeForRequest(NativeWebRequest request,
 4                                          ModelAndViewContainer mavContainer,
 5                                          Object... providedArgs) throws Exception {
 6         // 生成方法调用时的参数
 7         Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
 8         // 霸气的调用
 9         Object returnValue = invoke(args);
10 
11         return returnValue;
12     }
13     private Object[] getMethodArgumentValues(
14             NativeWebRequest request, ModelAndViewContainer mavContainer,
15             Object... providedArgs) throws Exception {
16         // 获取参数,这边没有值
17         MethodParameter[] parameters = getMethodParameters();
18         Object[] args = new Object[parameters.length];
19         for (int i = 0; i < parameters.length; i++) {
20             MethodParameter parameter = parameters[i];
21             // 参数名称查找器,反射中拿不到参数名,所以使用spring的parameterNameDiscover
22             parameter.initParameterNameDiscovery(parameterNameDiscoverer);
23             // 获取参数的目标类型,methodParam.setParameterType(result);设置.这边具体的逻辑后面再细化
24             GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
25             // 尝试通过类型判断,获取参数的值
26             args[i] = resolveProvidedArgument(parameter, providedArgs);
27             if (args[i] != null) {
28                 continue;
29             }
30             // 使用HandlerMethodArgumentResolver,判断是否支持处理
31             if (argumentResolvers.supportsParameter(parameter)) {
32                 try {
33                     // 这边直接处理,实际执行时,是通过责任链设计模式处理
34                     args[i] = argumentResolvers.resolveArgument(parameter, mavContainer, request, dataBinderFactory);
35                     continue;
36                 } catch (Exception ex) {
37                     throw ex;
38                 }
39             }
40 
41             if (args[i] == null) {
42                 String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
43                 throw new IllegalStateException(msg);
44             }
45         }
46         return args;
47     }
48     private Object invoke(Object... args) throws Exception {
49         // 解决权限的问题
50         ReflectionUtils.makeAccessible(this.getBridgedMethod());
51         try {
52             return getBridgedMethod().invoke(getBean(), args);
53         }
54         catch (IllegalArgumentException | InvocationTargetExceptione) {
55             // 省略异常处理机制
56         }
57     }
58     // ...
59 }

咱俩再来看看参数名称的变越来越准绳吧:

  假若@ModelAttribute中定义了value,就以value命名

  假诺评释中从不定义value,则依照重返值类型定义名称

  如:String会被定义为string,List<Double>会被定义为doubleList(集合都是那般定义的,富含array数组)

 1 package org.springframework.web.method.annotation;
 2 public final class ModelFactory {
 3 
 4     public static String getNameForReturnValue(Object returnValue, MethodParameter returnType) {
 5         ModelAttribute annot = returnType.getMethodAnnotation(ModelAttribute.class);
 6         if (annot != null && StringUtils.hasText(annot.value())) { // 注解中定义了value
 7             return annot.value();
 8         }
 9         else { // 根据类型生成
10             Method method = returnType.getMethod();
11             Class<?> resolvedType = GenericTypeResolver.resolveReturnType(method, returnType.getDeclaringClass());
12             return Conventions.getVariableNameForReturnType(method, resolvedType, returnValue);
13         }
14     }
15     // ...
16 }

接下去是怎么样依据再次来到值类型生成参数名称的逻辑,挺风趣,珍视拓展:

那边又依照办法的signature中定义的参数类型是不是细化再衍生三个支行:

  假诺格局签字中只定义Object类型,则供给依照value生成;不然依照签订契约生成

 1 package org.springframework.core;
 2 public abstract class Conventions {
 3     public static String getVariableNameForReturnType(Method method, Class resolvedType, Object value) {
 4         // 如果signature定义为object,则根据value来判断
 5         if (Object.class.equals(resolvedType)) {
 6             if (value == null) {
 7                 throw new IllegalArgumentException("Cannot generate variable name for an Object return type with null value");
 8             }
 9             // 这边的处理逻辑跟下面的很类似,不展开.差别是一个根据value,一个根据resolvedType判断
10             return getVariableName(value);
11         }
12 
13         Class valueClass;
14         // 是否是数组或集合
15         boolean pluralize = false;
16 
17         if (resolvedType.isArray()) { // 数组,读取内部元素的类型
18             valueClass = resolvedType.getComponentType();
19             pluralize = true;
20         }
21         else if (Collection.class.isAssignableFrom(resolvedType)) { // 集合
22             // 集合内的元素类型
23             valueClass = GenericCollectionTypeResolver.getCollectionReturnType(method);
24             if (valueClass == null) {
25                 if (!(value instanceof Collection)) {// 跟value再校验一遍类型
26                     throw new IllegalArgumentException(
27                             "Cannot generate variable name for non-typed Collection return type and a non-Collection value");
28                 }
29                 Collection collection = (Collection) value;
30                 if (collection.isEmpty()) {
31                     throw new IllegalArgumentException(
32                             "Cannot generate variable name for non-typed Collection return type and an empty Collection value");
33                 }
34                 // 获取集合中的第一个value
35                 Object valueToCheck = peekAhead(collection);
36                 // 获取value的类系
37                 valueClass = getClassForValue(valueToCheck);
38             }
39             pluralize = true;
40         }
41         else {
42             valueClass = resolvedType;
43         }
44 
45         String name = ClassUtils.getShortNameAsProperty(valueClass);
46         return (pluralize ? pluralize(name) : name);
47     }
48     // 获取集合中的第一个value
49     private static Object peekAhead(Collection collection) {
50         Iterator it = collection.iterator();
51         if (!it.hasNext()) {
52             throw new IllegalStateException(
53                     "Unable to peek ahead in non-empty collection - no element found");
54         }
55         Object value = it.next();
56         if (value == null) {
57             throw new IllegalStateException(
58                     "Unable to peek ahead in non-empty collection - only null element found");
59         }
60         return value;
61     }
62     private static Class getClassForValue(Object value) {
63         Class valueClass = value.getClass();
64         // 代理时根据接口获取,遍历时以第一个符合条件的为准
65         if (Proxy.isProxyClass(valueClass)) {
66             Class[] ifcs = valueClass.getInterfaces();
67             for (Class ifc : ifcs) {
68                 if (!ignoredInterfaces.contains(ifc)) {
69                     return ifc;
70                 }
71             }
72         }
73         else if (valueClass.getName().lastIndexOf('$') != -1 && valueClass.getDeclaringClass() == null) {
74             // '$' in the class name but no inner class -
75             // assuming it's a special subclass (e.g. by OpenJPA)
76             valueClass = valueClass.getSuperclass();
77         }
78         return valueClass;
79     }
80     // 数组或结合统一添加后缀List
81     private static String pluralize(String name) {
82         //private static final String PLURAL_SUFFIX = "List";
83         return name + PLURAL_SUFFIX;
84     }
85 
86 }

 

1.3
将声明@ModelAttribute方法参数(在@SessionAttributes定义范围内)同步到model中

遍历HandlerMethod的装有参数,搜索利用了@ModelAttribute评释的参数

  获取参数的名号:注明value值 > 参数类型

  核查那一个参数名称是还是不是在@SessionAttributes评释内

  若是mavContainer中还尚未该参数,继续管理

  获取缓存在sessionAttributesHandler中的参数值

  倘若值为空,抛HttpSessionRequiredException

  不然同步到mavContainer中

 1 package org.springframework.web.method.annotation;
 2 public final class ModelFactory {
 3     // ...
 4     public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod)
 5             throws Exception {
 6         // ...
 7         for (String name : findSessionAttributeArguments(handlerMethod)) {
 8             if (!mavContainer.containsAttribute(name)) {
 9                 Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
10                 if (value == null) {
11                     throw new HttpSessionRequiredException("Expected session attribute '" + name + "'");
12                 }
13                 mavContainer.addAttribute(name, value);
14             }
15         }
16     }
17     private List<String> findSessionAttributeArguments(HandlerMethod handlerMethod) {
18         List<String> result = new ArrayList<String>();
19         // 这边找的是HandlerMethod的参数
20         for (MethodParameter param : handlerMethod.getMethodParameters()) {
21             if (param.hasParameterAnnotation(ModelAttribute.class)) {
22                 String name = getNameForParameter(param);
23                 if (this.sessionAttributesHandler.isHandlerSessionAttribute(name, param.getParameterType())) {
24                     result.add(name);
25                 }
26             }
27         }
28         return result;
29     }
30     public static String getNameForParameter(MethodParameter parameter) {
31         ModelAttribute annot = parameter.getParameterAnnotation(ModelAttribute.class);
32         String attrName = (annot != null) ? annot.value() : null;
33         // 如果value为空,获取参数类型解析属性名称
34         return StringUtils.hasText(attrName) ? attrName :  Conventions.getVariableNameForParameter(parameter);
35     }
36 }

 

2. 管理器施行后将modle中相应参数设置到SessionAttributes中

  2.1
假使SessionStatus被调用了setComplete则清除sesssionAttributesHandler中缓存的数目

  2.2 要是没消除,将model中的数据同步至sessionAttributesHandler中

  2.3
假如handler还没管理完(是不是必要渲染页面),绑定BindingResult到model(要是必要的话)

 

还索要补给表达的是:

决断绑定BindingResult到model时的尺度(满意任意):

  a,不是别的参数绑定结果的Bindingresult

  b,@SessionAttributes证明定义范围内

  c, 不是null,数组,集结,map,简单数据类型

剩余的看代码注释就行了

 1 package org.springframework.web.method.annotation;
 2 public final class ModelFactory {
 3     // ...
 4     public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {
 5         if (mavContainer.getSessionStatus().isComplete()){ // 清除
 6             this.sessionAttributesHandler.cleanupAttributes(request);
 7         }
 8         else { // 不清除,那么就需要同步
 9             this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel());
10         }
11 
12         if (!mavContainer.isRequestHandled()) {
13             updateBindingResult(request, mavContainer.getModel());
14         }
15     }
16 
17     private void updateBindingResult(NativeWebRequest request, ModelMap model) throws Exception {
18         List<String> keyNames = new ArrayList<String>(model.keySet());
19         for (String name : keyNames) {
20             Object value = model.get(name);
21             // 核对是否需要绑定BindingResult到model
22             if (isBindingCandidate(name, value)) {
23                 String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + name;
24 
25                 if (!model.containsAttribute(bindingResultKey)) { // 不是其他参数绑定的结果
26                     WebDataBinder dataBinder = binderFactory.createBinder(request, value, name);
27                     model.put(bindingResultKey, dataBinder.getBindingResult());
28                 }
29             }
30         }
31     }
32 
33     private boolean isBindingCandidate(String attributeName, Object value) {
34         // 不是其他参数绑定的结果
35         if (attributeName.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
36             return false;
37         }
38         // 是否在@SessionAttributes注解定义中
39         Class<?> attrType = (value != null) ? value.getClass() : null;
40         if (this.sessionAttributesHandler.isHandlerSessionAttribute(attributeName, attrType)) {
41             return true;
42         }
43         // 不是null,数组,集合,map,简单数据类型,则调用
44         return (value != null && !value.getClass().isArray() && !(value instanceof Collection) &&
45                 !(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass()));
46     }
47 }

 

HandlerAdapter,springmvchandler ModelFactory首若是七个任务: 1.
伊始化model 2.
处理器实践后将modle中相应参数设置到SessionAttributes中…

ModelFactory首要是四个职分:

1. HandlerAdapter 概述

在 SpringMVC 中Handler能够是各个类型的类, 而DispatcherServlet断定须求对
handler 进行激活, 所以那时须要叁个适配类,
将各样handler适配成能够实践的类, 那时 HandlerAdapter就出现了;
主要代码如下

// Handler 处理适配器, 适配不同的 Handler
public interface HandlerAdapter {

    /** HandlerAdapter 是否支持这个 handler <-- 通常是检查这个 handler 是否是某一类
     *  如
     *    SimpleServletHandlerAdapter      -->  javax.servlet.Servlet
     *    SimpleControllerHandlerAdapter   -->  org.springframework.web.servlet.mvc.Controller
     *    HttpRequestHandlerAdapter        -->  org.springframework.web.HttpRequestHandler
     *    RequestMappingHandlerAdapter     -->  handler instanceof HandlerMethod
     * PS: 整个 DispatcherServlet 的入口是 HandlerAdapter.handle, 但其中真正执行的可能是  Servlet, Controller, HttpRequestHandler, HandlerMethod; 这时就需要 HandlerAdapter 来进行适配操作
     */
    boolean supports(Object handler);

    // 处理 HttpServletRequest 的入口方法
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    // Http 请求中的lastModifiedTime, 默认 -1
    long getLastModified(HttpServletRequest request, Object handler);
}

而 Handler艾达pter具备如下子类:

金沙js娱乐场官方网站 2

HandlerAdapter.png

1. SimpleServletHandlerAdapter:    适配实现 Servlet 接口的 Handler, 默认调用其 service 方法
2. SimpleControllerHandlerAdapter: 适配实现 Controller 接口的 Handler, 默认调用其 handleRequest 方法
3. HttpRequestHandlerAdapter:      适配实现 HttpRequestHandler 接口的 Handler, 默认调用其 handleRequest 方法
4. RequestMappingHandlerAdapter:   适配被@RequestMapping注释的方式, 一般都是解析一个一个参数, 并且通过反射进行激活

PS: 上面几个子类中唯有 RequestMappingHandlerAdapter有复杂的逻辑,
也是利用最频仍的 HandlerAdapter

金沙js娱乐场官方网站 3

  1. 初始化model

2. HandlerAdapter 的子类 SimpleServletHandlerAdapter

SimpleServletHandlerAdapter 适配 Servlet 调用的HandlerAdapter, 代码如下:

public boolean supports(Object handler) {
    return (handler instanceof Servlet); // 只要是个 Servlet, 就支持
}

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
    // 直接调用 Servlet 的 service 接口返回
    ((Servlet) handler).service(request, response);
    return null;
}

解析下各种类的职分吧(顺便做剖析目录):

  2. 管理器推行后将modle中相应参数设置到SessionAttributes中

3. HandlerAdapter 的子类 SimpleControllerHandlerAdapter

SimpleControllerHandlerAdapter 适配 Controller 接口的 HandlerAdapter,
代码如下:

public boolean supports(Object handler) {
    // 判断将要调用的 handler 是不是 Controller
    return (handler instanceof Controller);
}

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
    // 调用 Controller 接口类的接口方法 handleRequest() 方法直接响应给前端
    return ((Controller) handler).handleRequest(request, response);
}

HandlerMethod 封装方法定义相关的音信,如类,方法,参数等.

 

4. HandlerAdapter 的子类 HttpRequestHandlerAdapter

HttpRequestHandlerAdapter 适配 HttpRequestHandler 的 HandlerAdapter,
代码如下:

public boolean supports(Object handler) {
    // 判断将要调用的 handler 是不是 HttpRequestHandler
    return (handler instanceof HttpRequestHandler);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 调用 HttpRequestHandler 接口类的接口方法 handleRequest() 方法直接响应给前端
    ((HttpRequestHandler) handler).handleRequest(request, response);
    return null;
}

  使用情形:HandlerMapping时会使用

大家来拜望现实的拍卖逻辑(直接充当深入分析目录):

5. RequestMappingHandlerAdapter 概述

RequestMappingHandlerAdapter
将被@RequestMapping注释修饰的不二秘籍封装成ServletInvocableHandlerMethod,
并举办激活, 其重大有如下组件:

// 参数解析器 HandlerMethodArgumentResolver, 比如 RequestResponseBodyMethodProcessor
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
// 组合模式的参数解析器
private HandlerMethodArgumentResolverComposite argumentResolvers;
// initBinderArgumentResolvers 的 参数解析器
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
// 返回值处理器 比如 RequestResponseBodyMethodProcessor
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
// 组合模式的 返回值解析器
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
// ModelAndView 解析器
private List<ModelAndViewResolver> modelAndViewResolvers;
// 内容解析器 <-- 一般通过 HttpServletRequest 获取 MediaType
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
// HttpMessageConverter 转换器 --> 比如 form 表单的 FormHttpMessageConverter, Json 对应的 MappingJackson2HttpMessageConverter
private List<HttpMessageConverter<?>> messageConverters;
// request|response 对应的 Advice <-- 其实就像 AOP 中的 Advice的概念
private List<Object> requestResponseBodyAdvice = new ArrayList<Object>();

// 是否给予 Session 同步请求
private boolean synchronizeOnSession = false;
// Session 中存储|获取器
private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
// 方法解析器, 默认使用 ASM | 反射来获取 <- 反射针对 Java 8
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
// BeanFactory
private ConfigurableBeanFactory beanFactory;

下边各样组件都有其对应的效果: 在那之中第一有 HandlerMethod
的参数剖判器HandlerMethodArgumentResolver, 再次来到值管理器
HandlerMethodReturnValueHandler, 乞请内容的格式解析器
ContentNegotiationManager,
知道了诉求内容的格式,那时必要将字符串转为对应措施参数的参数转变器
HttpMessageConverter, Controller巩固器
requestResponseBodyAdvice(那其实就疑似Aop中的Advice), 再者大家能够透过
@RequestParam 获取钦赐名称的参数内容, 所以还亟需一个参数名称获取器
ParameterNameDiscoverer(有基于ASM, 有基于反射机制); 首先我们来看一下
RequestMappingHandlerAdapter 的起先化, 对应的初叶化入口在
InitializingBean.afterPropertiesSet 中张开:

public void afterPropertiesSet() {
    // Do this first, it may add ResponseBody advice beans
    // 初始化 被 @ControllerAdvice 修饰的类 <-- 这是一个 Controller 增强器, 主要是通过 @ModelAttribute, @InitBinder 注解
    initControllerAdviceCache(); 
    // 初始化 HandlerMethodArgumentResolver, 最后封装成 HandlerMethodArgumentResolverComposite <-- 组合模式
    if (this.argumentResolvers == null) {
        List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
        this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);  // Spring 里面 composite 模式 的提现
    }
    // 初始化 参数绑定方法的参数解决器  <-- 这个平时用得比较少
    if (this.initBinderArgumentResolvers == null) { 
        List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
        this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    // 初始化 HandlerMethodReturnValueHandler 比如 -> RequestResponseBodyMethodProcessor
    if (this.returnValueHandlers == null) { 
        List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
        this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
    }
}

其上首要照旧做了:

1. 初始化 被 @ControllerAdvice 修饰的类 <-- 这是一个 Controller 增强器, 主要是通过 @ModelAttribute, @InitBinder 注解
    1.1 收集 ApplicationContext 中所有被 @ControllerAdvice 注解修饰的 Bean, 并封装成 ControllerAdviceBean
    1.2 获取 Bean 上被 @ModelAttribute @RequestMapping 修饰的方法
    1.3 将被 @ModelAttribute @RequestMapping 修饰的方法 放入 modelAttributeAdviceCache
    1.4 获取 Bean 上被 @InitBinder 注解的方法, 并放入 initBinderAdviceCache 中
    1.5 若是 RequestBodyAdvice 子类, 则加入 requestResponseBodyAdviceBeans
    1.6 若是 RequestBodyAdvice 子类, 则加入 requestResponseBodyAdviceBeans
2. 初始化 HandlerMethodArgumentResolver(这里主要分成 基于注解的参数解决器, 基于参数类型的解决器), 最后封装成 HandlerMethodArgumentResolverComposite <-- 组合模式
3. 初始化 参数绑定方法的参数解决器(这里主要分成 基于注解的参数解决器, 基于参数类型的解决器), 最后封装成 HandlerMethodArgumentResolverComposite <-- 组合模式  <-- 这个平时用得比较少
4. 初始化 HandlerMethodReturnValueHandler(这里主要分成 基于注解的参数解决器, 单|多个目的的解决器) 比如 -> RequestResponseBodyMethodProcessor, 最后封装成 HandlerMethodReturnValueHandlerComposite <-- 组合模式

地点的参数剖析器其实在 SpringMVC 中扮演着特别首要的剧中人物, 也是 SpringMVC
扩大点的一个反映机制, 首要利用了之类的剖析器:

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { // 获取默认的 HandlerMethodArgumentResolver
    List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
    // 基于注解的参数解析 <-- 解析的数据来源主要是 HttpServletRequest | ModelAndViewContainer
    // Annotation-based argument resolution
    // 解析被注解 @RequestParam, @RequestPart 修饰的参数, 数据的获取通过 HttpServletRequest.getParameterValues
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
    // 解析被注解 @RequestParam 修饰, 且类型是 Map 的参数, 数据的获取通过 HttpServletRequest.getParameterMap
    resolvers.add(new RequestParamMapMethodArgumentResolver());
    // 解析被注解 @PathVariable 修饰, 数据的获取通过 uriTemplateVars, 而 uriTemplateVars 却是通过 RequestMappingInfoHandlerMapping.handleMatch 生成, 其实就是 uri 中映射出的 key <-> value
    resolvers.add(new PathVariableMethodArgumentResolver());
    // 解析被注解 @PathVariable 修饰 且数据类型是 Map, 数据的获取通过 uriTemplateVars, 而 uriTemplateVars 却是通过 RequestMappingInfoHandlerMapping.handleMatch 生成, 其实就是 uri 中映射出的 key <-> value
    resolvers.add(new PathVariableMapMethodArgumentResolver());
    // 解析被注解 @MatrixVariable 修饰, 数据的获取通过 URI提取了;后存储的 uri template 变量值
    resolvers.add(new MatrixVariableMethodArgumentResolver());
    // 解析被注解 @MatrixVariable 修饰 且数据类型是 Map, 数据的获取通过 URI提取了;后存储的 uri template 变量值
    resolvers.add(new MatrixVariableMapMethodArgumentResolver());
    // 解析被注解 @ModelAttribute 修饰, 且类型是 Map 的参数, 数据的获取通过 ModelAndViewContainer 获取, 通过 DataBinder 进行绑定
    resolvers.add(new ServletModelAttributeMethodProcessor(false));
    // 解析被注解 @RequestBody 修饰的参数, 以及被@ResponseBody修饰的返回值, 数据的获取通过 HttpServletRequest 获取, 根据 MediaType通过HttpMessageConverter转换成对应的格式, 在处理返回值时 也是通过 MediaType 选择合适HttpMessageConverter, 进行转换格式, 并输出
    resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    // 解析被注解 @RequestPart 修饰, 数据的获取通过 HttpServletRequest.getParts()
    resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
    // 解析被注解 @RequestHeader 修饰, 数据的获取通过 HttpServletRequest.getHeaderValues()
    resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
    // 解析被注解 @RequestHeader 修饰且参数类型是 Map, 数据的获取通过 HttpServletRequest.getHeaderValues()
    resolvers.add(new RequestHeaderMapMethodArgumentResolver());
    // 解析被注解 @CookieValue 修饰, 数据的获取通过 HttpServletRequest.getCookies()
    resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
    // 解析被注解 @Value 修饰, 数据在这里没有解析
    resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
    // 解析被注解 @SessionAttribute 修饰, 数据的获取通过 HttpServletRequest.getAttribute(name, RequestAttributes.SCOPE_SESSION)
    resolvers.add(new SessionAttributeMethodArgumentResolver());
    // 解析被注解 @RequestAttribute 修饰, 数据的获取通过 HttpServletRequest.getAttribute(name, RequestAttributes.SCOPE_REQUEST)
    resolvers.add(new RequestAttributeMethodArgumentResolver());

    // Type-based argument resolution
    // 解析固定类型参数(比如: ServletRequest, HttpSession, InputStream 等), 参数的数据获取还是通过 HttpServletRequest
    resolvers.add(new ServletRequestMethodArgumentResolver());
    // 解析固定类型参数(比如: ServletResponse, OutputStream等), 参数的数据获取还是通过 HttpServletResponse
    resolvers.add(new ServletResponseMethodArgumentResolver());
    // 解析固定类型参数(比如: HttpEntity, RequestEntity 等), 参数的数据获取还是通过 HttpServletRequest
    resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    // 解析固定类型参数(比如: RedirectAttributes), 参数的数据获取还是通过 HttpServletResponse
    resolvers.add(new RedirectAttributesMethodArgumentResolver());
    // 解析固定类型参数(比如: Model等), 参数的数据获取通过 ModelAndViewContainer
    resolvers.add(new ModelMethodProcessor());
    // 解析固定类型参数(比如: Model等), 参数的数据获取通过 ModelAndViewContainer
    resolvers.add(new MapMethodProcessor());
    // 解析固定类型参数(比如: Errors), 参数的数据获取通过 ModelAndViewContainer
    resolvers.add(new ErrorsMethodArgumentResolver());
    // 解析固定类型参数(比如: SessionStatus), 参数的数据获取通过 ModelAndViewContainer
    resolvers.add(new SessionStatusMethodArgumentResolver());
    // 解析固定类型参数(比如: UriComponentsBuilder), 参数的数据获取通过 HttpServletRequest
    resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
    // Custom arguments
    if (getCustomArgumentResolvers() != null) {
        resolvers.addAll(getCustomArgumentResolvers());
    }
    // Catch-all
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    resolvers.add(new ServletModelAttributeMethodProcessor(true));
    return resolvers;
}

地点的分析器首要分为基于评释, 基于参数类型, 与自定义的参数剖析器(PS:
轮廓上的数码来源是 HttpServletRequest的 header|body 中的属性,
ModelAndViewContainer)! 然后哪怕管理重临值的Computer:

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

    // Single-purpose return value types
    // 支持 ModelAndView 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 ModelAndViewContainer
    handlers.add(new ModelAndViewMethodReturnValueHandler());
    // 支持 Map 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 ModelAndViewContainer
    handlers.add(new ModelMethodProcessor());
    // 支持 View 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 ModelAndViewContainer
    handlers.add(new ViewMethodReturnValueHandler());
    // 支持 ResponseEntity 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 HttpServletResponse 的数据流中 OutputStream
    handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));
    // 支持 ResponseEntity | StreamingResponseBody 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 HttpServletResponse 的数据流中 OutputStream
    handlers.add(new StreamingResponseBodyReturnValueHandler());
    // 支持 HttpEntity | !RequestEntity 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 HttpServletResponse 的数据流中 OutputStream
    handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));
    // 支持 HttpHeaders 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 HttpServletResponse 的数据头部
    handlers.add(new HttpHeadersReturnValueHandler());
    // 支持 Callable 类型的 HandlerMethodReturnValueHandler
    handlers.add(new CallableMethodReturnValueHandler());
    handlers.add(new DeferredResultMethodReturnValueHandler());
    // 支持 WebAsyncTask 类型的 HandlerMethodReturnValueHandler
    handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

    // Annotation-based return value types
    // 将数据加入 ModelAndViewContainer 的 HandlerMethodReturnValueHandler
    handlers.add(new ModelAttributeMethodProcessor(false));
    // 返回值被 ResponseBody 修饰的返回值, 并且根据 MediaType 通过 HttpMessageConverter 转化后进行写入数据流中
    handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));

    // Multi-purpose return value types
    // 支持返回值为 CharSequence 类型, 设置 ModelAndViewContainer.setViewName
    handlers.add(new ViewNameMethodReturnValueHandler());
    // 支持返回值为 Map, 并将结果设置到 ModelAndViewContainer
    handlers.add(new MapMethodProcessor());
    // Custom return value types
    if (getCustomReturnValueHandlers() != null) {
        handlers.addAll(getCustomReturnValueHandlers());
    }
    // Catch-all
    if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
        handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
    }
    else {
        handlers.add(new ModelAttributeMethodProcessor(true));
    }
    return handlers;
}

在有了那个工具类后,
大家就能够完成AbstractHandlerMethodAdapter中定义的虚幻方法handleInternal,
在 handleInternal 中重视开始展览了出现的主宰(并发的粒度是 HttpSession),
而正真的法子激活交给了 ServletInvocableHandlerMethod, 对
ServletInvocableHandlerMethod 的初步化在 invokeHandlerMethod 中:

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    // 构建 ServletWebRequest <-- 主要由 HttpServletRequest, HttpServletResponse
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        // 构建 DataBinder 工厂
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        // binderFactory 中存储着被 @InitBinder, @ModelAttribute 修饰的方法 <- 最终包裹成 InvocableHandlerMethod
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        // 构建一个 ServletInvocableHandlerMethod
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        // 设置方法参数解析器 HandlerMethodArgumentValueResolver
        invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        // 返回值处理器 HandlerMethodReturnValueHandler
        invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        // 设置 WebDataBinderFactory
        invocableMethod.setDataBinderFactory(binderFactory);
        // 设置 参数名解析器
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        // 获取 HttpServletRequest 中存储的 FlashMap
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        // 这里是激活 @ModelAttribute, @InitBinder 方法, 并将返回值放入 ModelAndViewContainer
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
        // 将 HttpServletRequest 转换成方法的参数, 激活方法, 最后 通过 HandlerMethodReturnValueHandler 来处理返回值
        invocableMethod.invokeAndHandle(webRequest, mavContainer);      
        // 生成 ModelAndView
        return getModelAndView(mavContainer, modelFactory, webRequest); 
    }
    finally {
        webRequest.requestCompleted(); // 标志请求已经结束, 进行一些生命周期回调函数的激活
    }
}

代码到那边HandlerMethod依旧不曾激活, 还会有极其重要的做事急需去做 ->
参数的剖判与绑定 + 反射激活方法 + 再次来到值处理; 参数深入分析 + 绑定的操作在
InvocableHandlerMethod中, 具体流程如下:

private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {
    // 这里的 getMethodParameters 其实是在构造 MethodParameters 时创建的
    MethodParameter[] parameters = getMethodParameters();           
    Object[] args = new Object[parameters.length];
    // 从这里开始对参数进行一个一个解析 <- 主要是通过 HandlerMethodArgumentResolver
    for (int i = 0; i < parameters.length; i++) {                   
        MethodParameter parameter = parameters[i];
        // 设置参数名解析器 ParameterNameDiscoverer (默认通过 ASM)
        parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
        // 这一步是尝试 判断 参数 providedArgs 里面的类型是否满足 parameter 
        args[i] = resolveProvidedArgument(parameter, providedArgs);             
        if (args[i] != null) continue;
        // 判断是否 argumentResolvers 里面含有对应的 解释器
        if (this.argumentResolvers.supportsParameter(parameter)) {              
            try { // 通过 argumentResolvers 解析 HandlerMethod 里面 对应的参数内容
                args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
                continue;
            }
            catch (Exception ex) {throw ex;}
        }
    }
    return args;
}

再得到参数后实际就足以激活对应的主意,
而再次回到值的做法相对上边的参数分析要简单一点, 都以先得到相应的再次来到值管理,
然后拓展管理!

InvocableHandlerMethod 增加参数计划,方法调用成效

  1. 初始化model
6. HandlerAdapter 中的卓绝设计
1. 模版模式: 比如在 AbstractHandlerMethodAdapter中的 handleInternal, 而正真的实现在RequestMappingHandlerAdapter
2. 策略模式: 根据不同的策略实现接口 HandlerAdapter, 以支持不同的"controller"
3. InitializingBean: 这是 BeanFactory 中Bean生命周期的扩展接口, 表示 Bean 的初始化方法, RequestMappingHandlerAdapter 就是通过这个接口实现工具类的初始化
4. MethodIntrospector: 这是一个对方法进行反省操作的工具类, 通过传入 classType 与 methodFilter 来过滤需要的 Method

  使用意况:实行使用@ModelAttribute表明会选用

  1.1 分析类上运用的sessionAttributres,将获取参数合併到mavContainer中

7. 总结

HandlerAdapter 是 SpringMVC中扩充机制的至极好的三个反映, 通过
HandlerAdapter, DispatcherServlet
就足以支撑别的格式的Handler(这里的能够帮助指在不改造 DispatcherServlet
的处境下), 第二是Handler艾达pter
基于差异Handler完成分歧完成类(能够把它精通为政策形式),
最后也是最根本的就是参数的剖析与再次回到值的深入分析(那些在底下举办描述)!

ServletInvocableHandlerMethod 增添再次来到值管理职责,ResponseStatus处理

  1.2 试行注解了@ModelAttribute的主意,并将结果共同到Model

8. 仿效资料

SpringMVC源码解析连串
Spring
MVC源码剖判
Spring源码情操陶冶
Spring
揭秘
Spring
本领内部原因
Spring
源码深度剖判
看透 Spring MVC
源代码剖判与实行

  使用情况:实践http相关方法会使用,比方调用管理实行

    参数名的转移法规:@ModelAttribute中定义的value >
方法的回到类型决定(直接往model.addAttribute的除了)

 

  1.3
将表明@ModelAttribute方法参数(在@SessionAttributes定义范围内)同步到model中

1. HandlerMethod

    将艺术中利用@ModelAttribute的参数跟@SessionAttribute核查,即使都定义了,供给将其参数值同步至mavContainer

HandlerMethod其实能够省略明了为保全方法音信的pojo.

  1. Computer执行后将modle中相应参数设置到SessionAttributes中

之所以那边首要便是看下定义的属性:

  2.1
假如SessionStatus被调用了setComplete则清除sesssionAttributesHandler中缓存的数额

金沙js娱乐场官方网站 4

  2.2 如果没排除,将model中的数据同步至sessionAttributesHandler中

 1 package org.springframework.web.method;
 2 public class HandlerMethod {
 3     /** 什么鬼,给子类提供logger,到现在为止源码中不多见 */
 4     protected final Log logger = LogFactory.getLog(HandlerMethod.class);
 5     // 方法所在的类,如果是String类型,可以去容器中获取
 6     private final Object bean;
 7     // 方法
 8     private final Method method;
 9     // 类管理的容器
10     private final BeanFactory beanFactory;
11     // 方法的参数
12     private final MethodParameter[] parameters;
13     // 如果方法是bridged方法,则对应原始方法
14     private final Method bridgedMethod;
15     // ...
16 }

  2.3
纵然handler还没管理完(是不是需求渲染页面),绑定BindingResult到model(假使要求的话)

金沙js娱乐场官方网站 5

  下边包车型大巴代码表达在平凡开支时,SessionStatus.setComplete写在格局哪个地点都行,因为她是在点子施行后才在那边调用,跟措施中的顺序非亲非故.

大部应当是看看注释就会领略了,大家解释下上边:

 

  那边全体的熟练都以final类型的,不可修改,所以一旦出现修改需求new.

1. 初始化model

  借使bean是string,是在createWithResolvedBean找容器获取实例的.

做了三个业务,详细见源码中的注释吧: