基於 Spring4.X 來學習 SpringtMVC, 在學習過程中,被“告知”在 XML 配置文件中建議設置如下兩項:
一直不明白為什么,但又甘心。於是,花了一點時間來調試源碼,想了解清楚為什么需要這樣做。
Demo代碼地址:
https://github.com/cyhbyw/springMVC_atguigu_TongGang
工程名稱:
springMVC_DebugSourceCode
現在開始調試。
==============>>>>
PS:圖片可能不是很清晰,可以右擊圖片、選擇在新標簽頁中查看
或者,可以右擊圖片,選擇“圖片另存為”保存在本地並編好號(建議直接以01、02、03……來編號)
或者,可以右擊圖片,選擇“復制圖片”,再保存到本地並編好號(建議直接以01、02、03……來編號)
以上三種辦法,任意選擇喜歡的一種,以獲得並查看更清晰的圖片~~
<<<<==============
情況一:有這兩個標簽時
1. 初始化 HandlerMapping 的過程如下,且其中包含 RequestMappingHandlerMapping!如下圖所示。
2. 初始化 HandlerAdapter 的過程如下,且其中包含 RequestMappingHandlerAdapter!如下圖所示。
情況二:沒有這兩個標簽 (提醒:調試時需要注釋掉這兩個標簽的內容)
1. 初始化 HandlerMapping 的過程如下,且其中包含 DefaultAnnotationHandlerMapping。如下圖所示。
從源碼中可以看到,它調用了Line588的 getDefaultStrategies() 方法。而有這兩個標簽時,調用的是Line570的方法。
2. 初始化 HandlerAdapter 的過程如下,且其中包含 AnnotationMethodHandlerAdapter!如下圖所示。
從源碼中可以看到,它調用了Line626的 getDefaultStrategies() 方法。而有這兩個標簽時,調用的是Line608的方法。
可以看到,當有、無這兩個標簽時,SpringtMVC所采用的HandlerMapping、HandlerAdapter是不一樣的。對比如下:
有這兩個標簽時 | 沒有這兩個標簽時 | |
HandlerMapping | BeanNameUrlHandlerMapping SimpleUrlHandlerMapping RequestMappingHandlerMapping |
BeanNameUrlHandlerMapping DefaultAnnotationHandlerMapping |
HandlerAdapter | HttpRequestHandlerAdapter SimpleControllerHandlerAdapter RequestMappingHandlerAdapter |
HttpRequestHandlerAdapter SimpleControllerHandlerAdapter AnnotationMethodHandlerAdapter |
從表中可以看出:
1. 對於HandlerMapping,有標簽時比無標簽時多出一個 SimpleUrlHandlerMapping。更重要的是,將 DefaultAnnotationHandlerMapping 更新為 RequestMappingHandlerMapping!而從源碼中也可以看到,前者已被廢棄並建議使用后者。
2. 對於HandlerAdapter,將 AnnotationMethodHandlerAdapter 更新為 RequestMappingHandlerAdapter!同理,前者已被廢棄並建議使用后者。
不知道會不會是因為上述原因才建議加上這兩個標簽的,但是,總歸來說,使用已過時被廢棄的類總是不好的吧。所以,即使沒有其它更多理由,還是遵循建議,加上這兩個標簽吧。
自己還知道的建議加上這兩個標簽的其它原因如下(還未完全確認):
1. 除了自動注冊上述的 RequestMappingHandlerMapping 與 RequestMappingHandlerAdapter 外,它還會自動注冊 ExceptionHandlerExceptionResolver
2. 支持使用 ConversionService 進行數據格式轉換
3. 支持使用 NumberFormatAnnotation 與 DateTimeFormat 進行數據格式化
4. 支持使用 RequestBody 與 ResponseBody 注解
上面的整個流程都是圍繞着初始化 HandlerMapping & HandlerAdapter (就是給它們賦值)來展開的。既然已經賦值,那總得有取值並使用它們的地方吧。
使用流程如下:
1. 先會到達 DispatcherServlet 的 doDispatcher() 方法(此方法非常重要,是 SpringtMVC 處理Controller方法的核心入口!!);同時,會先后分別調用 getHandler() & getHandlerAdapter() 方法。
2. getHandler() 方法中就會使用剛剛賦值過的 HandlerMapping 對象
3. getHandlerAdapter() 方法中就會使用剛剛賦值過的 HandlerAdapter 對象
下一篇將進行源碼調試並分析 SpringtMVC 是如何實現並做到上述差異的