最近做springmvc+mybatis+maven项目集成的时候遇到一个问题,项目搭起来以后,http请求怎么都进不到controller中,耗费
了一天多时间弄这个问题,最后发现还是自己对spring的配置文件和各种注解不熟。其实这个问题就是由于注解没配好的缘故
首先,从配置文件讲起
web.xml
<!-- 加载Spring配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring-context*.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 加载spring mvc --> <servlet> <servlet-name>spring3mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring-mvc*.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring3mvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
在上面的web.xml中,我们看到基于ContextLoaderListener和DispatcherServlet都可以配置spring相关的XML,两类XML的前缀分别以spring和springmvc开头,说明,基于ContextLoaderListener加载的XML配置,原则上是与spring容器相关的(也可以说是父容器);而基于DispatcherServlet加载的XML配置,原则上是与springmvc容器相关的(相当于子容器)。
父容器加载的配置文件默认地址为:/WEB-INF/applicationContext.xml,它默认以applicationContext命名,说明它是spring的全局的配置,如果你项目中此文件名和地址都没有改,那么在web.xml中可以不用配置,spring容器会自动到默认地址下去加载。
子容器的配置文件命名默认为[servlet-name]-servlet.xml方式,也就是说servlet-name中如果没有指定init-param属性,系统自动寻找的配置文件为[servlet-name]-servlet.xml,默认路径也是WEB-INF下。
所以个人建议,基于mvc相关的spring配置由DispatcherServlet加载,而其余的JavaBean都交给ContextLoaderListener加载。
值得说明的是这两种方式加载spring的ApplicationContext上下文对象不是合并存储的。mvc
context可以引用applicationContext的bean,而applicationContext无法引用到mvc的bean,spring查找bean,会先在当前context中查找,如果没有满足的,再到父容器查找。而且两个context中可以存在相同的bean定义的,只不过优先查找当前context。并且各context上下文中的声明式标签相互不起作用。也就是说,如果你在applicationContext.xml中声明的<mvc:annotation-driven
/> ,在mvc的context中是不起作用的。
说了这么多,其实我项目中的错误原因也就找到了,我的问题在于,我将<mvc:annotation-driven
/>声明在了application上下文的配置中,从而导致mvc的context 中声明的<context:component-scan base-package="com.hq51.business.controller" /> 不起作用,项目也就无法识别和加载controller了,所以会出现需要controller处理的http请求,最后都是莫名其妙的404错误。