Spring MVC的使用原理其實是通過配置一個Servlet來接管所有的請求,所有的請求由這個Servlet來進行分發處理。
我們可以從web.xml裡面看出這一點
這個Servlet就是Spring MVC提供的DispatcherServlet,它的繼承圖如下:
DispatcherServlet大緻接收請求的時序圖如下:
下面我們先設定幾個問題然後再去看源碼。
DispatcherServlet初始化的時機?
我們将斷點打在DispatcherServlet中的onRefresh方法上
,然後啟動項目。
從這個堆棧的圖可以看出,最開始是HttpServletBean的init方法執行,然後啟動Spring容器,Spring容器初始化的最後一步finishRefresh裡面進行了事件通知。
FrameworkServlet裡有個内部類ContextRefreshListener,實作了ApplicationListener接口,接收到了上面的事件通知,執行onApplicationEvent方法。
繼續跟蹤onApplicationEvent方法
發現最終是由onRefresh方法來進行具體處理的,并且這個onRefresh方法在FrameworkServlet裡面是個空方法,是由它的子類DispatcherServlet來實作的。
我們來看DispatcherServlet裡的onRefresh方法
這樣就把SpringMVC的九大元件給初始化了。
我們的@RequestMapping注解在方法上,SpringMVC是怎麼根據這個注解就能将對應的請求執行到這個方法上的?
從上面可以看到有個initHandlerMappings方法:
繼續跟蹤getDefaultStrategies方法
可以看出對classNames進行了周遊,這裡有兩個值,
BeanNameUrlHandlerMapping和RequestMappingHandlerMapping,我們一般用的是RequestMappingHandlerMapping。
RequestMappingHandlerMapping的父類AbstractHandlerMethodMapping實作了InitializingBean接口,我們來看看它實作的afterPropertiesSet方法。
前面都是一些配置,後面是調用父類的afterPropertiesSet方法,此方法裡隻有initHandlerMethods一個方法
主要看processCandidateBean方法
繼續跟蹤detectHandlerMethods方法
繼續跟蹤裡面的register方法
可以看出mappingLookup、urlLookup、registry都放入了值。這時我也不知道每個的具體作用。我把斷點打到這3個屬性上。然後前端發起一個get請求。
請求比對的過程?
前端發起請求,斷點停在了AbstractHandlerMethodMapping.MappingRegistry#getMappingsByUrl方法上,以前端發起的請求路徑,從urlLookup上擷取對應的值。
最後看看請求分發的主流程,也是springMVC最核心的代碼
總結:
tomcat的Servlet調起Spring容器啟動,Spring容器啟動完,事件通知到SpringMVC的DispatcherServlet。
這時會掃描所有的bean,将注解了@Controller和@RequestMapping的解析出來。
前端請求發過來,DispatcherServlet接收到(因為它是個servlet,配置在web.xml的),根據上一步處理好的映射關系,找到對應的方法來處理。
如通過/test能找到test方法
找到對應的方法後,反射調用
組裝modelAndView渲染視圖到前端
書山有路勤為徑,學海無涯苦作舟