最近学了Maven,并尝试将以前的项目(springmvc+myabtis)重构成Maven项目,Maven项目推荐各种资源文件都放在src/java/resources目录下,所以我自然把spring的配置文件(包括spring-mvc,spring-mybatis等配置都写在一个文件中)applicationContext.xml文件也放在了resources目录下,重构结束后,启动Tomcat报错:
八月 31, 2015 3:26:24 下午 org.apache.catalina.core.AprLifecycleListener init 信息: Loaded APR based Apache Tomcat Native library 1.1.22. 八月 31, 2015 3:26:24 下午 org.apache.catalina.core.AprLifecycleListener init 信息: APR capabilities: IPv6 [false], sendfile [true], accept filters [false], random [true]. 八月 31, 2015 3:26:25 下午 org.apache.coyote.AbstractProtocol init 信息: Initializing ProtocolHandler ["http-apr-8080"] 八月 31, 2015 3:26:25 下午 org.apache.coyote.AbstractProtocol init 信息: Initializing ProtocolHandler ["ajp-apr-8009"] 八月 31, 2015 3:26:25 下午 org.apache.catalina.startup.Catalina load 信息: Initialization processed in 1784 ms 八月 31, 2015 3:26:25 下午 org.apache.catalina.core.StandardService startInternal 信息: Starting service Catalina 八月 31, 2015 3:26:25 下午 org.apache.catalina.core.StandardEngine startInternal 信息: Starting Servlet Engine: Apache Tomcat/7.0.26 八月 31, 2015 3:26:25 下午 org.apache.catalina.startup.HostConfig deployDirectory 信息: Deploying web application directory E:\java\apache-tomcat-7.0.26\webapps\host-manager 八月 31, 2015 3:26:26 下午 org.apache.catalina.startup.HostConfig deployDirectory 信息: Deploying web application directory E:\java\apache-tomcat-7.0.26\webapps\manager 八月 31, 2015 3:26:26 下午 org.apache.catalina.startup.HostConfig deployDirectory 信息: Deploying web application directory E:\java\apache-tomcat-7.0.26\webapps\ROOT 八月 31, 2015 3:26:26 下午 org.apache.catalina.startup.HostConfig deployDirectory 信息: Deploying web application directory E:\java\apache-tomcat-7.0.26\webapps\zhsz 八月 31, 2015 3:26:26 下午 org.apache.catalina.loader.WebappClassLoader validateJarFile 信息: validateJarFile(E:\java\apache-tomcat-7.0.26\webapps\zhsz\WEB-INF\lib\javaee.jar) - jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class 八月 31, 2015 3:26:32 下午 org.apache.catalina.core.ApplicationContext log 信息: No Spring WebApplicationInitializer types detected on classpath log4j:ERROR Could not find value for key log4j.appender.stdout log4j:ERROR Could not instantiate appender named "stdout". log4j:ERROR Could not find value for key log4j.appender.debug log4j:ERROR Could not instantiate appender named "debug". 八月 31, 2015 3:26:32 下午 org.apache.catalina.core.ApplicationContext log 信息: Initializing Spring root WebApplicationContext 八月 31, 2015 3:26:33 下午 org.apache.catalina.core.StandardContext listenerStart 严重: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from ServletContext resource [/WEB-INF/applicationContext.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml] at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:341) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:131) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:522) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:436) at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:385) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:284) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4779) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5273) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:895) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:871) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:615) at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1095) at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1617) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) at java.util.concurrent.FutureTask.run(FutureTask.java:166) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) at java.lang.Thread.run(Thread.java:722) Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml] at org.springframework.web.context.support.ServletContextResource.getInputStream(ServletContextResource.java:140) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:328) ... 26 more 八月 31, 2015 3:26:33 下午 org.apache.catalina.core.StandardContext startInternal 严重: Error listenerStart 八月 31, 2015 3:26:33 下午 org.apache.catalina.core.StandardContext startInternal 严重: Context [/zhsz] startup failed due to previous errors 八月 31, 2015 3:26:33 下午 org.apache.catalina.core.ApplicationContext log 信息: Closing Spring root WebApplicationContext 八月 31, 2015 3:26:33 下午 org.apache.catalina.core.StandardContext listenerStop 严重: Exception sending context destroyed event to listener instance of class org.springframework.web.context.ContextLoaderListener java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext at org.springframework.context.support.AbstractRefreshableApplicationContext.getBeanFactory(AbstractRefreshableApplicationContext.java:172) at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1066) at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1040) at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:988) at org.springframework.web.context.ContextLoader.closeWebApplicationContext(ContextLoader.java:556) at org.springframework.web.context.ContextLoaderListener.contextDestroyed(ContextLoaderListener.java:142) at org.apache.catalina.core.StandardContext.listenerStop(StandardContext.java:4819) at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5466) at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:160) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:895) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:871) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:615) at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1095) at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1617) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) at java.util.concurrent.FutureTask.run(FutureTask.java:166) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) at java.lang.Thread.run(Thread.java:722) 八月 31, 2015 3:26:33 下午 org.apache.coyote.AbstractProtocol start 信息: Starting ProtocolHandler ["http-apr-8080"] 八月 31, 2015 3:26:33 下午 org.apache.coyote.AbstractProtocol start 信息: Starting ProtocolHandler ["ajp-apr-8009"] 八月 31, 2015 3:26:33 下午 org.apache.catalina.startup.Catalina start 信息: Server startup in 7589 ms
注意一下,其实重点就一句话,即Could not open ServletContext resource [/WEB-INF/applicationContext.xml],异常也很明显,FileNotException,无法打开ServletContext的资源文件。下面再看一下web.xml的配置:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>xxybm</display-name> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>springMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>/app/*</url-pattern> </servlet-mapping> <filter> <filter-name>SecurityFilter</filter-name> <filter-class>net.zhsz.util.LoginCheckFilter</filter-class> </filter> <filter-mapping> <filter-name>SecurityFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> <filter-mapping> <filter-name>SecurityFilter</filter-name> <url-pattern>/app/*</url-pattern> </filter-mapping> <session-config> <session-timeout>30</session-timeout> </session-config> <error-page> <exception-type>java.lang.Exception</exception-type> <location>/500.html</location> </error-page> </web-app>
由于在没用Maven之前,我的spring配置文件——applicationContext.xml是放在WEB-INF根目录下的,在项目运行时都是正常的,重构成Maven项目之后,我的配置文件自然应该放在src下的resources文件夹下了,那么在web.xml中我自然将<init-param>中contextConfigLocation的参数值由WEB-INF/applicationContext.xml修改为classpath:applicationContext.xml了,那么启动tomcat之后依然报错,而且我们从报错信息中可以看出容器依然是在WEB-INF下去找applicationContext.xml,很明显这个文件的位置已经被我们改变了,而且我们也修改了web.xml的配置为何还要从这里去加载呢?原因是我们缺少另一个重要的配置。
遇到问题盲目搜索往往不能迅速得到有效的解决方案,所以我们先从官方去寻找线索,看一看spring的官方文档,在The Web的章节中可以发现这样一段话:
简单翻译一下上图标记的小段落:如果不特意指定参数名为contextConfigLoction的<context-parameter>元素,那么spring的ContextLoderListener监听器就会在/WEB-INF/下去寻找并加载该目录下的名为applicationContext.xml这个文件。So,我们应该在web.xml中添加<context-param>标签并再次指定spring核心文件的位置:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>xxybm</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>springMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>/app/*</url-pattern> </servlet-mapping> <filter> <filter-name>SecurityFilter</filter-name> <filter-class>net.zhsz.util.LoginCheckFilter</filter-class> </filter> <filter-mapping> <filter-name>SecurityFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> <filter-mapping> <filter-name>SecurityFilter</filter-name> <url-pattern>/app/*</url-pattern> </filter-mapping> <session-config> <session-timeout>30</session-timeout> </session-config> <error-page> <exception-type>java.lang.Exception</exception-type> <location>/500.html</location> </error-page> </web-app>