我们来了解下ModelAndViewContainer组件---------------【springmvc源码】

接着上一篇的springmvc最简单配置的解析(4)-----------【springmvc源码】,我们继续分析。

在上一篇中的render方法,其实它是最后处理请求的阶段,也就是把请求转换为视图的阶段。它主要应用到ModelAndViewContainer这个类。

 

ModelAndViewContainer,你可以认为是上下文容器,它主要是承担着整个请求过程中数据的传递工作,但是它在处理保存Model和View之外,还有一些其他功能。请看下面代码:

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();

    ...
}

通过上面,我们可以知道ModelAndViewContain有两个Model,分别为defaultModel和redirectModel;

至于在什么情况下使用哪个,

  1. defaultModel是默认使用的Model
  2. redirectModel是用于传递redirect时的Model
  3. 处理器中使用了Model或ModelMap时,ArgumentResolve会传入defaultModel。defaultModel的话,因为它是BindingAwareModel Map类型,而且继承了ModelMap又实现了Model接口,所以在处理器中使用Model或ModelMap时,其实都是使用同一个对象。-----------Map参数传入的也是这个对象。
  4. 处理器中RedirectAttributes类型的参数ArgumentResolve会传入redirectModel。redirectModel实际是RedirectAttributesModel Map类型。

 

 


 

下面是ModelAndView的大概属性和方法,

 

 

从几张图中,我们能了解到ModleMap这个类,去看看呗,

 

我们在看下它的内部,

/**
 * 可以看出ModelMap实际上就是一个LinkedHashMap,且“值”为超类Object类型
 * 能够放置所有的Java对象
 */
public class ModelMap extends LinkedHashMap<String, Object> {
    public ModelMap() {
    }

    // 调用这个构造函数之前会先调用其父类构造函数,得到一个Map对象
    public ModelMap(String attributeName, Object attributeValue) {
        addAttribute(attributeName, attributeValue);
    }
    
    // 就是将attributeValue对象放置到Map末尾,同时指定键值为attributeName
    public ModelMap addAttribute(String attributeName, Object attributeValue) {
        put(attributeName, attributeValue);
        return this;
    }
    
    // attributes是一个Map集合;所谓merge无非是将attributes这个集合放置到现有集合的末尾
    public ModelMap mergeAttributes(Map<String, ?> attributes) {
        if (attributes != null) {
            for (Map.Entry<String, ?> entry : attributes.entrySet()) {
                String key = entry.getKey();
                if (!containsKey(key)) {
                    put(key, entry.getValue());
                }
            }
        }
        return this;
    }
    
    //省略一些方法的定义...
}

 

通过这样,我们可以了解到

ModelAndViewContainer定义了两个ModelMap对象:defaultModel和redirectModel,实际上也就是两个Map<String, Object>
 1  * 其中defaultModel已经完成了初始化。默认使用defaultModel。
 2  * 也可以通过其中的方法来设置使用redirectModel,这个是方便移植和使用其它框架而设定的。

虽然上面已经写到了,但是这里重新写一遍,是不是理解更深了点。

 

 

 

 

但是大家有注意到吗,其实在springmvc最简单配置的解析(3)-------------【springmvc源码】中的invokeHandlerMethod方法是有使用到ModelAndViewContain,因为该方法使用了类似责任链模式,所以就跳过了。那么ModelAndViewContain,它在那里是起到什么作用呢。。。

 

 

 

到这里,我们来了解invokeHandlerMethod这个比较重要的方法。。。

首先我们得知道invokeHandlerMethod方法,它的主要作用是具体执行请求处理。

/**
 * Invoke the RequestMapping handler method preparing a ModelAndView if view resolution is required.
 */
private ModelAndView invokeHandleMethod(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   //step 1、ModelAndView的前世:是一个ModelAndViewContainer实例
   ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    
   /*
   * RequestContextUtils.getInputFlashMap(request)可以获取到request中的attribute,
   * 并且将所有的request中的attribute放置在mavContainer中,此时使用的是defaultModel
   */
    mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
    modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
   /* 
    * 在RequestMappingHandlerAdapter中ignoreDefaultModelOnRedirect默认为false
    */
    mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
    
    //省略许多代码...
    
    if (asyncManager.hasConcurrentResult()) {
            //...
            mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
            
            //...
        }

    //step 2、调用handler方法,
    requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
    
    //省略许多代码...

    //step 3、从mavContainer中获取到ModelAndView实例,返回
    return getModelAndView(mavContainer, modelFactory, webRequest);
}

或许和之前的有些不一样,但是流程类似。

但是,到了这里大家就明白了吗?MainAndViewResolve。。。

 

 

参考资料:

7、SpringMVC源码分析(2):分析HandlerAdapter.handle方法,了解handler方法的调用细节以及@ModelAttribute注解

SpringMVC源码分析(3):分析ModelAndView的形成过程

看透springmvc源码分析与实践   第13章  HandlerAdapter

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值