1. 概述web
對於Web開發者,MVC模型是你們再熟悉不過的了,SpringMVC中,知足條件的請求進入到負責請求分發的DispatcherServlet,DispatcherServlet根據請求url到控制器的映射(HandlerMapping中保存),HandlerMapping最終返回HandlerExecutionChain,其中包含了具體的處理對象handler(也即咱們編程時寫的controller)以及一系列的攔截器interceptors,此時DispatcherServlet會根據返回的HandlerExecutionChain中的handler找到支持這一處理器類型的適配器(handlerAdapter),在處理器適配器中最終會去調用控制器的請求響應方法並返回結果視圖(ModelAndView),獲得結果視圖後,經過render方法完成結果的顯示。spring
HanderMapping的繼承體系:編程
HandlerAdapter的繼承體系:mvc
一樣的視圖解析器ViewResolver針對不一樣的輸出格式也有一系列的實現類,具體可本身看。app
2. 實現分析jsp
以我本身的一個web項目中spring mvc的配置爲例:函數
- <context:component-scan base-package="cn.ds.log" />
-
- <bean id="defaultHandlerMapping"
- class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
-
- <bean
- class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
- </bean>
-
- <bean
- class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
- </bean>
-
- <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter">
- </bean>
-
- <bean id="viewResolver"
- class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <property name="prefix">
- <value>/WEB-INF/jsp/</value>
- </property>
- <property name="suffix">
- <value>.jsp</value>
- </property>
- </bean>
這裏由於是採用全註解的方式,因此先經過context:component-scan配置讓spring自定掃描的包路徑,接着配置handlerMapping、handlerAdapter及ViewResolver,幾乎包含了SpringMVC的配置中須要涉及的全部元素。後面須要涉及具體的HanderMapping等的實現時,將以這裏配置中的實現爲例進行分析,其它的你們「同理可解」。⊙﹏⊙b汗源碼分析
2.1 Spring MVC初始化流程this
DispatcherServlet的繼承體系如:url
看到它們繼承自HttpServlet,你就知道初始化過程應該是從init方法開始了,整個初始化的流程爲:
很簡單是麼?我也以爲是,至少從上面的時序圖看來是這樣,不過前提是你已經很瞭解Spring IOC的實現原理了。上面的時序圖中,在5的initStragegies()中除了調用6,7的函數外,還有幾個相似的初始化函數,由於這裏主要是爲了理解整個的流程,因此我都省略了。上面流程可能須要分析的地方就在於3,4步,咱們看看initWebApplicationContext函數的實現:
- protected WebApplicationContext initWebApplicationContext() {
- WebApplicationContext rootContext =
- WebApplicationContextUtils.getWebApplicationContext(getServletContext());
- WebApplicationContext wac = null;
-
- if (this.webApplicationContext != null) {
- // A context instance was injected at construction time -> use it
- wac = this.webApplicationContext;
- if (wac instanceof ConfigurableWebApplicationContext) {
- ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
- if (!cwac.isActive()) {
- ……
- configureAndRefreshWebApplicationContext(cwac);
- }
- }
- }
- if (wac == null) {
- wac = findWebApplicationContext();
- }
- if (wac == null) {
- // No context instance is defined for this servlet -> create a local one
- wac = createWebApplicationContext(rootContext);
- }
-
- if (!this.refreshEventReceived) {
- // Either the context is not a ConfigurableApplicationContext with refresh
- // support or the context injected at construction time had already been
- // refreshed -> trigger initial onRefresh manually here.
- onRefresh(wac);
- }
-
- if (this.publishContext) {
- ……
- }
-
- return wac;
- }
看起來貌似有點複雜,其實理解了IOC容器的實現原理(能夠看下「spring ioc源碼分析」一文,⊙﹏⊙多年前弄的,此次暑假實習時又以讀書報告的形式寫了,感受當年腫麼能夠寫得這麼亂……也是一種成長,不打算修改)就很簡單,函數一開始會去獲取WebApplicationContext對象,這個對象在ContextLoaderListener初始化IOC容器時就已經把它set到ServletContext的屬性中,並且它也正是ConfigurableWebApplicationContext的實例,第一個if語句其實就是若是此時SpringIOC容器沒有初始化的話就在這裏啓動IOC容器的初始化過程,由於看「省略(1)」中的代碼你就知道,它會在這裏調用refresh函數,「世人」都知道這就是IOC容器啓動的入口,這裏會解析配置文件springmvc-servlet.xml。
這裏最終要執行onRefresh(),而這個就是SpringMVC初始化的入口。
(注:其實這裏也能夠配置log4j,經過其打印的info信息來看IOC與MVC的初始化順序)