HandlerAdapter在处理请求时上下文数据的传递工作是由ModelAndViewContainer负责的.

源码注释是这样描述的:

Records model and view related decisions made by HandlerMethodArgumentResolvers and HandlerMethodReturnValueHandlers during the course of invocation of a controller method.

翻译下: 记录HandlerMethodArgumentResolver 和 HandlerMethodReturnValueHandler 在处理handler时 使用的模型model和视图view相关信息.

ModelAndViewContainer主要职责:

  1. 维护模型model,包括defaultModle和redirectModel

  2. 维护视图view

  3. 维护是否redirect信息,及根据这个判断HandlerAdapter使用的是defaultModel或redirectModel(判断规则详见下文)

  4. 维护@SessionAttributes注解信息状态

  5. 维护handler是否处理标记

目录:

1. ModelAndViewContainer属性

2. 科普ModelMap继承体系

3. ModelAndView提供的api,复杂的还是model相关的属性设置,其他主要是简单的getter,setter

ModelAndViewContainer属性

先来看看ModelAndViewContainer的属性,这样就比较清晰:

 package org.springframework.web.method.support;
public class ModelAndViewContainer {
// 视图,实际使用时可能是String类型的逻辑视图
private Object view;
// 标记handler是否已经完成请求处理
private boolean requestHandled = false;
// 默认模型,下文我们可以简单科普下ModelMap继承体系
private final ModelMap defaultModel = new BindingAwareModelMap();
// redirect时使用的模型,实际使用的是RedirectAttributesModelMap
private ModelMap redirectModel;
// 标记处理器返回redirect视图
private boolean redirectModelScenario = false;
// redirect时,是否忽略defaultModel
private boolean ignoreDefaultModelOnRedirect = false;
// @SessionAttributes注解使用状态标记,就是是否处理完毕
private final SessionStatus sessionStatus = new SimpleSessionStatus();
}

顺便学个英语单词,Scenario 方案

科普ModelMap继承体系

继续往下分析之前,我们先来简单科普下ModelMap的继承体系:

各个类的职责与使用场景:

  ModelMap是LinkedHashMap的子类,主要是封装attribute概念,实际处理还是委托给map

  ExtendedModelMap添加链调用chained calls,并实现Model接口

  BindingAwareModelMap,BindingResult相关属性被设置时,自动清除BindingResult.defaultModel使用的该类.

  RedirectAttributesModelMap 通过DataBinder做参数类型转换,redirect时使用的flash attributes

各有侧重地看下源码吧

  2.1 ModelMap,是继承LinkedHashMap,添加mergeAttributes

 package org.springframework.ui;
public class ModelMap extends LinkedHashMap<String, Object> {
public ModelMap mergeAttributes(Map<String, ?> attributes) {
if (attributes != null) {
for (String key : attributes.keySet()) {
if (!containsKey(key)) {
put(key, attributes.get(key));
}
}
}
return this;
}
// ...
}

  2.2 ExtendedModelMap添加链调用chained calls

 package org.springframework.ui;
public class ExtendedModelMap extends ModelMap implements Model {
@Override
public ExtendedModelMap addAttribute(String attributeName, Object attributeValue) {
super.addAttribute(attributeName, attributeValue);
return this;// 看这里
}
// ...
}

  2.3 BindingAwareModelMap,BindingResult相关属性被设置时,自动清除BindingResult.defaultModel使用的该类.

  看的就是removeBindingResultIfNecessary.这边put和putAll都会调用removeBindingResultIfNecessary

 package org.springframework.validation.support;
public class BindingAwareModelMap extends ExtendedModelMap { @Override
public Object put(String key, Object value) {
removeBindingResultIfNecessary(key, value);
return super.put(key, value);
}
// ...
private void removeBindingResultIfNecessary(Object key, Object value) {
if (key instanceof String) {
String attributeName = (String) key;
if (!attributeName.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attributeName;
BindingResult bindingResult = (BindingResult) get(bindingResultKey);
if (bindingResult != null && bindingResult.getTarget() != value) {
remove(bindingResultKey);
}
}
}
} }

  2.4 RedirectAttributesModelMap 通过DataBinder做参数类型转换,redirect时使用的flash attributes

  这样主要就是添加了dataBinder和flashAttributes属性相关的api

 package org.springframework.web.servlet.mvc.support;
public class RedirectAttributesModelMap extends ModelMap implements RedirectAttributes { 4 private final DataBinder dataBinder;

6 private final ModelMap flashAttributes = new ModelMap();

private String formatValue(Object value) {
if (value == null) {
return null;
}
12 return (dataBinder != null) ? dataBinder.convertIfNecessary(value, String.class) : value.toString();
}
// ...
}

ModelAndView提供的api

主要是两类api,view相关和model相关.

  3.1 view相关其实就一个api,是否类应用(通过是否是string类型判断):

 package org.springframework.web.method.support;
public class ModelAndViewContainer {
// ...
/**
* Whether the view is a view reference specified via a name to be
* resolved by the DispatcherServlet via a ViewResolver.
*/
public boolean isViewReference() {
return (this.view instanceof String);
}
}

  3.2 model相关的api就比较多了,主要是设置模型值.

  在设置模型值的时候,这边涉及到一个问题,就是container里有两个model,往哪个里设置?

  container索性抽象一个getModel()的api进行判断.

  我们来说说判断的逻辑吧:

    使用defaultModel的场景:

    a,不是redirect  

    b,redirect场景下,redirectModel为null,同时ignoreDefaultModelOnRedirect为false

    剩下的就是使用redirectModel的场景了,不细说

  model相关属性操作的类都是跟addAttribute类似的逻辑,使用getModel获取model后直接委托.所以篇幅缘故下面的源码以addAttribute为例,其他都只是展现api 的signature

 package org.springframework.web.method.support;
public class ModelAndViewContainer {
// ...
/**
* Return the model to use: the "default" or the "redirect" model.
* <p>The default model is used if {@code "redirectModelScenario=false"} or
* if the redirect model is {@code null} (i.e. it wasn't declared as a
* method argument) and {@code ignoreDefaultModelOnRedirect=false}.
*/
public ModelMap getModel() {
if (useDefaultModel()) {
return this.defaultModel;
}
else {
return (this.redirectModel != null) ? this.redirectModel : new ModelMap();
}
}
/**
* Whether to use the default model or the redirect model.
* 不是redirect || redirect时redirectModel为空同时不忽略defaultModel
*/
private boolean useDefaultModel() {
return !this.redirectModelScenario || ((this.redirectModel == null) && !this.ignoreDefaultModelOnRedirect);
}
public ModelAndViewContainer addAttribute(String name, Object value) {
getModel().addAttribute(name, value);
return this;
}
public ModelAndViewContainer addAttribute(Object value){};
public ModelAndViewContainer addAllAttributes(Map<String, ?> attributes){};
public ModelAndViewContainer removeAttributes(Map<String, ?> attributes){};
public boolean containsAttribute(String name){};
}

SpringMVC源码解析 - HandlerAdater - ModelAndViewContainer上下文容器的更多相关文章

  1. SpringMVC源码解析- HandlerAdapter - ModelFactory(转)

    ModelFactory主要是两个职责: 1. 初始化model 2. 处理器执行后将modle中相应参数设置到SessionAttributes中 我们来看看具体的处理逻辑(直接充当分析目录): 1 ...

  2. SpringMVC源码解析- HandlerAdapter - ModelFactory

    ModelFactory主要是两个职责: 1. 初始化model 2. 处理器执行后将modle中相应参数设置到SessionAttributes中 我们来看看具体的处理逻辑(直接充当分析目录): 1 ...

  3. springMVC源码解析--ViewResolver视图解析器执行(三)

    之前两篇博客springMVC源码分析--ViewResolver视图解析器(一)和springMVC源码解析--ViewResolverComposite视图解析器集合(二)中我们已经简单介绍了一些 ...

  4. springMVC源码解析--HandlerMethodArgumentResolverComposite参数解析器集合(二)

    上一篇博客springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)中我们已经介绍了参数解析相关的东西,并且也提到了HandlerMethodArgume ...

  5. SpringMVC源码解析- HandlerAdapter初始化

    HandlerAdapter初始化时,主要是进行注解解析器初始化注册;返回值处理类初始化;全局注解@ControllerAdvice内容读取并缓存. 目录: 注解解析器初始化注册:@ModelAttr ...

  6. SpringMVC源码解析

    一:springmvc运行过程: 1. dispatcherServlet 通过 HandlerMapping 找到controller2. controller经过后台逻辑处理得到结果集modela ...

  7. 深入了解SpringMVC源码解析

    Spring MVC源码解析 Spring MVC的使用原理其实是通过配置一个Servlet来接管所有的请求,所有的请求由这个Servlet来进行分发处理. 我们可以从web.xml里面看出这一点 & ...

  8. springMVC源码解析--ViewResolverComposite视图解析器集合(二)

    上一篇博客springMVC源码分析--ViewResolver视图解析器(一)中我们介绍了一些springMVC提供的很多视图解析器ViewResolver,在开发的一套springMVC系统中是可 ...

  9. springmvc源码解析MvcNamespaceHandler之<mvc:view-resolvers>

    说在前面 本次主要介绍springmvc配置解析. springmvc配置解析 本次介绍MvcNamespaceHandler. 进入到这个方法org.springframework.web.serv ...

随机推荐

  1. excel 条件格式 心的

    例1: 图1 图2 $G$16 ≠G16  用G16就可以用格式刷拖动,$G$16用格式刷刷到其它单元格保持不变,判断单元格函数 ISBLANK(G16)=TRUE

  2. PHP 设计模式 原型模式(Prototype)之深/浅拷贝

      看PHP 设计模式 原型模式(Prototype)时,衍生出一个扩展问题之 原型拷贝的浅拷贝和深拷贝问题(不管写Java还是写PHP还是写JS时都多多少少遇到过对象拷贝问题)   比如写前端页面时 ...

  3. USACO 2016 January Contest, Gold解题报告

    1.Angry Cows http://www.usaco.org/index.php?page=viewproblem2&cpid=597 dp题+vector数组运用 将从左向右与从右向左 ...

  4. week1-绪论

    一 .作业题目 仿照三元组或复数的抽象数据类型写出有理数抽象数据类型的描述 (有理数是其分子.分母均为整数且分母不为零的分数). 有理数基本运算: 构造有理数T,元素e1,e2分别被赋以分子.分母值 ...

  5. Regenerate Script 重置脚本

    1.Regenerate Script 重置回录制后的第一次脚本,当修改设定后点击这个按钮,新的设置也会录制到 如:开始没有录到下载的文件,添加下载文件的个时候,再次点击重置,就录制到了 如:如开始是 ...

  6. postman-3http请求

    http消息是服务器和客户端之间交换数据的方式. 有2种类型的消息: 请求:由客户端发送用来触发服务器的动作. 响应:来自服务器的应答. https://developer.mozilla.org/z ...

  7. 折腾一天,获取下列多选框的所有选中值,原生js可直接通过obj.val()来获取,可jq不行,要通过循环取值来获取;

    折腾一天,获取下列多选框的所有选中值,原生js可直接通过obj.val()来获取,可jq不行,要通过循环取值来获取;

  8. ExtJS组件扩展

    1.extends 2.initComponent 3.constracot: 4.onRender:重新写这个方法 ========================================= ...

  9. logger5步走

    https://www.cnblogs.com/GGGGGGZX/p/9114378.html'''打印日志11/26/2017 10:44:21 PM bug 24 并写入文件example.log ...

  10. Android开发入门——ImageView的设置

    在熟悉了android后,总是对系统自带的ic_launcher这个小机器人不太喜欢,想换成自己喜欢的图片,接下来就介绍两种方法来实现把imageView的ic_launcher换成自己喜欢的图片. ...