SpringMVC源碼解析,springmvc源碼

來源:互聯網
上載者:User

SpringMVC源碼解析,springmvc源碼

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的屬性,這樣就比較清晰:

 1 package org.springframework.web.method.support; 2 public class ModelAndViewContainer { 3     // 視圖,實際使用時可能是String類型的邏輯視圖 4     private Object view; 5     // 標記handler是否已經完成請求處理 6     private boolean requestHandled = false; 7     // 預設模型,下文我們可以簡單科普下ModelMap繼承體系 8     private final ModelMap defaultModel = new BindingAwareModelMap(); 9     // redirect時使用的模型,實際使用的是RedirectAttributesModelMap10     private ModelMap redirectModel;11     // 標記處理器返回redirect視圖12     private boolean redirectModelScenario = false;13     // redirect時,是否忽略defaultModel14     private boolean ignoreDefaultModelOnRedirect = false;15     // @SessionAttributes註解使用狀態標記,就是是否處理完畢16     private final SessionStatus sessionStatus = new SimpleSessionStatus();17 }

 順便學個英語單詞,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 

 1 package org.springframework.ui; 2 public class ModelMap extends LinkedHashMap<String, Object> { 3     public ModelMap mergeAttributes(Map<String, ?> attributes) { 4         if (attributes != null) { 5             for (String key : attributes.keySet()) { 6                 if (!containsKey(key)) { 7                     put(key, attributes.get(key)); 8                 } 9             }10         }11         return this;12     }13     // ...14 }

  2.2 ExtendedModelMap添加鏈調用chained calls

1 package org.springframework.ui;2 public class ExtendedModelMap extends ModelMap implements Model {3     @Override4     public ExtendedModelMap addAttribute(String attributeName, Object attributeValue) {5         super.addAttribute(attributeName, attributeValue);6         return this;// 看這裡7     }8     // ...9 }

  2.3 BindingAwareModelMap,BindingResult相關屬性被設定時,自動清除BindingResult.defaultModel使用的該類.

  看的就是removeBindingResultIfNecessary.這邊put和putAll都會調用removeBindingResultIfNecessary

 1 package org.springframework.validation.support; 2 public class BindingAwareModelMap extends ExtendedModelMap { 3  4     @Override 5     public Object put(String key, Object value) { 6         removeBindingResultIfNecessary(key, value); 7         return super.put(key, value); 8     } 9     // ...10     private void removeBindingResultIfNecessary(Object key, Object value) {11         if (key instanceof String) {12             String attributeName = (String) key;13             if (!attributeName.startsWith(BindingResult.MODEL_KEY_PREFIX)) {14                 String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attributeName;15                 BindingResult bindingResult = (BindingResult) get(bindingResultKey);16                 if (bindingResult != null && bindingResult.getTarget() != value) {17                     remove(bindingResultKey);18                 }19             }20         }21     }22 23 }

  2.4 RedirectAttributesModelMap 通過DataBinder做參數類型轉換,redirect時使用的flash attributes

  這樣主要就是添加了dataBinder和flashAttributes屬性相關的api

 1 package org.springframework.web.servlet.mvc.support; 2 public class RedirectAttributesModelMap extends ModelMap implements RedirectAttributes { 3  4     private final DataBinder dataBinder; 5  6     private final ModelMap flashAttributes = new ModelMap(); 7  8     private String formatValue(Object value) { 9         if (value == null) {10             return null;11         }12         return (dataBinder != null) ? dataBinder.convertIfNecessary(value, String.class) : value.toString();13     }14     // ...15 }

 

ModelAndView提供的api

主要是兩類api,view相關和model相關.

  3.1 view相關其實就一個api,是否類應用(通過是否是string類型判斷):

 1 package org.springframework.web.method.support; 2 public class ModelAndViewContainer { 3     // ... 4     /** 5      * Whether the view is a view reference specified via a name to be 6      * resolved by the DispatcherServlet via a ViewResolver. 7      */ 8     public boolean isViewReference() { 9         return (this.view instanceof String);10     }11 }

  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

 1 package org.springframework.web.method.support; 2 public class ModelAndViewContainer { 3     // ... 4     /** 5      * Return the model to use: the "default" or the "redirect" model. 6      * <p>The default model is used if {@code "redirectModelScenario=false"} or 7      * if the redirect model is {@code null} (i.e. it wasn't declared as a 8      * method argument) and {@code ignoreDefaultModelOnRedirect=false}. 9      */10     public ModelMap getModel() {11         if (useDefaultModel()) {12             return this.defaultModel;13         }14         else {15             return (this.redirectModel != null) ? this.redirectModel : new ModelMap();16         }17     }18     /**19      * Whether to use the default model or the redirect model.20      * 不是redirect || redirect時redirectModel為空白同時不忽略defaultModel21      */22     private boolean useDefaultModel() {23         return !this.redirectModelScenario || ((this.redirectModel == null) && !this.ignoreDefaultModelOnRedirect);24     }25     public ModelAndViewContainer addAttribute(String name, Object value) {26         getModel().addAttribute(name, value);27         return this;28     }29     public ModelAndViewContainer addAttribute(Object value){};30     public ModelAndViewContainer addAllAttributes(Map<String, ?> attributes){};31     public ModelAndViewContainer removeAttributes(Map<String, ?> attributes){};32     public boolean containsAttribute(String name){};33 }

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.