今天把一個基於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>