1. web.xml文件的简单详解
在web环境中, spring MVC是建立在IOC容器的基础上,要了解spring mvc,首先要了解Spring IOC容器是如何在web环境中被载入并起作用的。
spring IOC是一个独立的模块,并不是直接关联web容器的,在web环境中使用IOC容器,就需要把IOC容器导入,在web环境中建立起来。下面以tomcat作为web容器的例子。在tomcat中,web.xml是应用部署文件,web文件如下。

1 <!DOCTYPE web-app PUBLIC 2 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 3 "http://java.sun.com/dtd/web-app_2_3.dtd" > 4 5 <web-app> 6 <display-name>springmvcTest</display-name> 7 <!-- spring 配置 --> 8 <context-param> 9 <param-name>contextConfigLocation</param-name> 10 <param-value>/WEB-INF/applicationContext.xml</param-value> 11 </context-param> 12 13 <filter> 14 <filter-name>characterEncoding</filter-name> 15 <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 16 <init-param> 17 <param-name>encoding</param-name> 18 <param-value>utf-8</param-value> 19 </init-param> 20 </filter> 21 <filter-mapping> 22 <filter-name>characterEncoding</filter-name> 23 <url-pattern>/*</url-pattern> 24 </filter-mapping> 25 <listener> 26 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 27 </listener> 28 29 <!-- 配置springmvc --> 30 <servlet> 31 <servlet-name>springmvcTest</servlet-name> 32 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 33 <init-param> 34 <param-name>contextConfigLocation</param-name> 35 <param-value>classpath:springmvc.xml</param-value> 36 </init-param> 37 <load-on-startup>1</load-on-startup> 38 </servlet> 39 <servlet-mapping> 40 <servlet-name>springmvcTest</servlet-name> 41 <url-pattern>*.do</url-pattern> 42 </servlet-mapping> 43 44 <servlet-mapping> 45 <servlet-name>springmvcTest</servlet-name> 46 <url-pattern>*.html</url-pattern> 47 </servlet-mapping> 48 49 <!-- <welcome-file-list> 50 <welcome-file>index.do</welcome-file> 51 </welcome-file-list> --> 52 </web-app>
在web文件中,有两个非常重要的类,一个是ContextLoaderListener,一个是DispatcherServlet。DispatcherServlet定义了对应的URL映射,这些URL映射为servlet指定了需要处理的HTTP请求。ContextLoaderListener被定义为一个监听器,这个监听器负责完成IOC容器在web环境中的启动工作。web.xml文件中,还引入了两个文件,一个是/WEB-INF/applicationContext.xml文件,另一个是classpath:springmvc.xml文件,其中applicationContext.xml文件就是sping IOC容器配置的xml文件。
DispatcherServlet和ContextLoaderListener提供了在web容器中对spring的接口,也就是说,这些接口与web容器耦合是通过ServletContext来实现的。这个ServletContext为springIOC容器提供了一个宿主环境,在宿主环境中,spring mvc建立一个ioc容器的体系,这个IOC容器体系是通过ContextLoaderListener的初始化来建立的,在IOC容器建立后,把DispatcherServlet作为spring mvc处理web请求转发建立起来,从而完成响应的HTTP请求的准备。
2. ContextLoaderListener的初始化和spring IOC的建立
IOC容器启动的过程就是建立上下文的过程,该上下文是与ServletContext相伴而生的,同时也是IOC容器在web应用环境的具体表现之一。由ContextLoaderListener启动的上下文为根上下文。在根上下文的基础上,还有一个与web MVC相关的上下文来保存的控制器(DispatcherServlet)需要的MVC对象,作为根上下文的子上下文,构成一个层次化的上下文体系。在web容器启动的过程,首先建立根上下文,然后建立这个上下文体系的,这个上下文体系的建立是由ContextLoader来完成。
也就是说/WEB-INF/applicationContext.xml配置的spring IOC容器是由ContextLoaderListener这个类进行初始化的,这样就完成了根上下文在web容器中的创建。这个根上下文是作为web容器中唯一的实例而存在,如果在初始化过程中,发现已经有根上下文被创建了,就会抛出异常。根上下文被创建了,就会被保存到web容器的ServletContext中,以共需要时使用。
3. DispatcherServlet的初始化和MVC IoC容器的建立
完成了对ContextLoaderListener的初始化以后,也就是创建完根上下文后,Web容器开始初始化DispatcherServlet,DispatcherServlet会建立自己的上下文来持有spring mvc的bean对象,在建立自己持有的IoC容器时,会从ServletContext中得到根上下文作为DispatcherServlet持有上下文的双亲对象。有了这个根上下文,再对自己持有的上下文进行初始化,最后把自己持有的这个上下文保存到ServletContext中,供以后检索使用。
作为servlet,DispatcherServlet的启动与servlet的启动过程是相联系的,在Servlet的初始化过程中,Servlet的init方法会被调用,以进行初始化。接下来就是执行DispatcherServlet持有的IoC容器的初始化过程,在初始化这个过程中,一个新的上下文被建立起来,DispatcherServlet持有的上下文被设置为根上下文的子上下文。可以认为,根上下文是和web应用相对应的上下文,而DispatcherServlet持有的上下文是和servlet对应的上下文。而在web容器中,往往可以容纳多个Servlet存在。对于应用在web容器中的上下文体系,一个根上下文可以作为许多Servlet上下文的双亲上下文。了解了这一点,对在web环境中的Ioc容器中的bean设置和检索会有更多的了解,在向IOC容器getBean时候,IOC容器会首先像其双亲去getBean,也就是说,在根上下文定义的bean是可以被各个servlet持有的上下文得到和共享的。最后,DispatcherServlet给自己持有的上下文命名,并把它设置到web容器的上下文中,这个名称和在web.xml中设置的DispatcherServlet的servlet名称相关,从而保证了这个上下文在web环境上下文体系中的唯一性。
4. 总结
在web环境中建立IOC容器体系,首先是通过ContextLoaderListener来建立spring 容器,然后在建立DispatcherServlet的IoC容器,假如我们在service层引用controller,即/WEB-INF/applicationContext.xml中的bean引用classpath:springmvc.xml中的bean,是会报错的,会报如下错误:No qualifying bean found for dependency.....即没有找到指定的bean。还有就是为什么controller一般放在classpath:springmvc.xml文件中进行配置,DispatcherServlet直接打交道的是controller,首先会从DispatcherServlet持有的IOC容器中寻找相对应的controller,找不到才会到spring IOC容器里寻找。