Blog文章地址:http://www./spring/453.html 1. 概述 對(duì)于Web開(kāi)發(fā)者,,MVC模型是大家再熟悉不過(guò)的了,,SpringMVC中,滿足條件的請(qǐng)求進(jìn)入到負(fù)責(zé)請(qǐng)求分發(fā)的DispatcherServlet,,DispatcherServlet根據(jù)請(qǐng)求url到控制器的映射(HandlerMapping中保存),HandlerMapping最終返回HandlerExecutionChain,,其中包含了具體的處理對(duì)象handler(也即我們編程時(shí)寫(xiě)的controller)以及一系列的攔截器interceptors,,此時(shí)DispatcherServlet會(huì)根據(jù)返回的HandlerExecutionChain中的handler找到支持這一處理器類型的適配器(handlerAdapter),在處理器適配器中最終會(huì)去調(diào)用控制器的請(qǐng)求響應(yīng)方法并返回結(jié)果視圖(ModelAndView),,得到結(jié)果視圖后,,通過(guò)render方法完成結(jié)果的顯示。 HanderMapping的繼承體系:
HandlerAdapter的繼承體系:
同樣的視圖解析器ViewResolver針對(duì)不同的輸出格式也有一系列的實(shí)現(xiàn)類,,具體可自己看,。 2. 實(shí)現(xiàn)分析 以我自己的一個(gè)web項(xiàng)目中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 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>
這里因?yàn)槭遣捎萌⒔獾姆绞剑韵韧ㄟ^(guò)context:component-scan配置讓spring自定掃描的包路徑,,接著配置handlerMapping、handlerAdapter及ViewResolver,,幾乎包含了SpringMVC的配置中需要涉及的所有元素,。后面需要涉及具體的HanderMapping等的實(shí)現(xiàn)時(shí),將以這里配置中的實(shí)現(xiàn)為例進(jìn)行分析,,其它的大家“同理可解”,。⊙﹏⊙b汗
2.1 Spring MVC初始化流程 DispatcherServlet的繼承體系如:
看到它們繼承自HttpServlet,,你就知道初始化過(guò)程應(yīng)該是從init方法開(kāi)始了,,整個(gè)初始化的流程為:
很簡(jiǎn)單是么?我也覺(jué)得是,,至少?gòu)纳厦娴臅r(shí)序圖看來(lái)是這樣,,不過(guò)前提是你已經(jīng)很了解Spring IOC的實(shí)現(xiàn)原理了。上面的時(shí)序圖中,,在5的initStragegies()中除了調(diào)用6,7的函數(shù)外,,還有幾個(gè)類似的初始化函數(shù),因?yàn)檫@里主要是為了理解整個(gè)的流程,,所以我都省略了,。上面流程可能需要分析的地方就在于3,4步,,我們看看initWebApplicationContext函數(shù)的實(shí)現(xiàn): - 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;
- }
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; } 看起來(lái)貌似有點(diǎn)復(fù)雜,其實(shí)理解了IOC容器的實(shí)現(xiàn)原理(可以看下“spring ioc源碼分析”一文,,⊙﹏⊙多年前弄的,,這次暑假實(shí)習(xí)時(shí)又以讀書(shū)報(bào)告的形式寫(xiě)了,感覺(jué)當(dāng)年腫么可以寫(xiě)得這么亂……也是一種成長(zhǎng),,不打算修改)就很簡(jiǎn)單,,函數(shù)一開(kāi)始會(huì)去獲取WebApplicationContext對(duì)象,這個(gè)對(duì)象在ContextLoaderListener初始化IOC容器時(shí)就已經(jīng)把它set到ServletContext的屬性中,,而且它也正是ConfigurableWebApplicationContext的實(shí)例,,第一個(gè)if語(yǔ)句其實(shí)就是如果此時(shí)SpringIOC容器沒(méi)有初始化的話就在這里啟動(dòng)IOC容器的初始化過(guò)程,因?yàn)榭础笆÷裕?)”中的代碼你就知道,,它會(huì)在這里調(diào)用refresh函數(shù),,“世人”都知道這就是IOC容器啟動(dòng)的入口,這里會(huì)解析配置文件springmvc-servlet.xml,。 這里最終要執(zhí)行onRefresh(),,而這個(gè)就是SpringMVC初始化的入口。 (注:其實(shí)這里也可以配置log4j,,通過(guò)其打印的info信息來(lái)看IOC與MVC的初始化順序)
相關(guān)內(nèi)容: 1. Spring MVC源碼分析——請(qǐng)求處理,,http://blog.csdn.net/shi1122/article/details/8041017 2. Spring MVC源碼分析——視圖解析,http://blog.csdn.net/shi1122/article/details/8586463
|