今天把一个基于spring的web项目部署到linux环境下的tomcat容器中,启动完发现无法访问,出现404的情况,而其他几个web项目均可正常访问。
404:The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
首先怀疑是各种xml配置有问题,但在线下独立运行也是可以正常请求的,那spring的配置出错的可能基本就排除了。
然后猜测是因为项目中多加了servlet-api.jar,然后把这个jar从Libraries中移除再部署到线上,结果还是不行。
tomcat启动日志提示如下:
SEVERE: Context [/****] startup failed due to previous errors
给出这样的提示丝毫看不出什么端倪呀。
在搜索了一通后决定先看看日志。
在tomcat7下的logs目录发现了这样一个文件:localhost.2019-02-20.log
执行cat localhost.2019-02-20.log命令打开日志文件发现了错误信息。
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.util.Log4jConfigListener
java.lang.IllegalStateException: Web app root system property already set to different value: 'webapp.root' = [/usr/tomcat7/apache-tomcat-7.0.92/webapps/sfbm/] instead of [/usr/tomcat7/apache-tomcat-7.0.92/webapps/sfbtx/] - Choose unique values for the 'webAppRootKey' context-param in your web.xml files!
at org.springframework.web.util.WebUtils.setWebAppRootSystemProperty(WebUtils.java:161)
at org.springframework.web.util.Log4jWebConfigurer.initLogging(Log4jWebConfigurer.java:119)
at org.springframework.web.util.Log4jConfigListener.contextInitialized(Log4jConfigListener.java:49)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5157)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5680)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1018)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:994)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1296)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:2039)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
问题的根源就是webAppRootKey冲突了。Spring通过 org.springframework.web.util.WebAppRootListener 这个监听器来注入项目路径,因此部署在同一个web容器中的项目,要配置不同的param-value(比如”项目名.root”),不然会造成冲突。但是如果在web.xml中已经配置了org.springframework.web.util.Log4jConfigListener这个监听器,则不需要配置WebAppRootListener了。因为Log4jConfigListener已经包含了WebAppRootListener的功能。WebAppRootListener要在ApplicationContext的ContextLoaderListener之前,否则ApplicationContext的bean注入根目录值时会发生无法注入异常。既然已经发现了问题,那么再去解决就很简单了。
我这里已经配置listener,将<param-value>随便改一下就可以了。
<listener>
<listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
</listener>