問題說明
今天在部署項目時,遇到一個錯誤:
嚴重: Exception sending context initialized event to listener instance of class org.springframework.web.util.Log4jConfigListenerjava.lang.IllegalStateException: Web app root system property already set to different value: 'springmvc.root' = [D:\Projects\PureWater\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\PureWaterWeixin\] instead of [D:\Projects\PureWater\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\PureWater\] - 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:117)at org.springframework.web.util.Log4jConfigListener.contextInitialized(Log4jConfigListener.java:46)at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4812)at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5255)at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:745)
意思是“springmvc.root ”這個key已經指向了項目"PureWater",不能再指向另一個項目“PureWaterWeixin”。
原理分析
爲什麼會報這樣一個錯誤呢?
SpringMVC容器啓動時,WebAppRootListener會將該webapp的項目路徑設置到系統全局變量中,以便在可以使用系統全局變量的地方獲取到webapp的項目路徑,默認該變量名爲webapp.root,比如在log4j配置文件中使用${webapp.root} 。我們可以在web.xml中對該變量名進行自定義(任意名稱)。而且在Tomcat中,因爲其不會爲每個webapp隔離系統全局變量,我們必須在不同webapp中設置不同的變量名,否則就會出現上面的錯誤。
因爲我們有兩個項目都使用瞭如下相同的配置,導致“springmvc.root ”命名衝突。
在項目的web.xml中有一段聲明
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>springmvc.root</param-value>
</context-param>
然後在log4j.properties對聲明的全局變量有使用
### Output to the log file ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = ${springmvc.root}/WEB-INF/logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = debug
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
解決方案
只需要爲每個項目設置不同的名稱即可。比如,針對上面兩個代碼片段配置的名稱springmvc.root,將第一個項目改爲PureWater.root,第二個項目的名稱改爲PureWaterWeixin.root。
參考鏈接
web.xml中webAppRootKey
log4j和web.xml配置webAppRootKey 的問題
Class WebAppRootListener API
API中對webAppRootKey的原理和使用說明的非常清楚
WebApproot in Spring
謝謝!