问题说明

今天在部署项目时,遇到一个错误:
严重: 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: '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

谢谢!

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐