1.问题描述
tomcat中部署有两个项目,一个ROOT.war,一个oauth.war。启动tomcat后访问oauth项目报404,但是ROOT项目可以正常访问。
2.查找原因
查看日志,找到问题所在:
九月 29, 2016 6:07:51 下午 org.apache.catalina.core.StandardContext listenerStart
严重: 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' = [/opt/apache-tomcat-7.0.67/webapps/ROOT/] instead of [/opt/apache-tomcat-7.0.67/webapps/oauth/] - Choose unique values for the 'webAppRootKey' context-param in your web.xml files!
3.解释原理
如果web.xml中有如下配置:
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>webapp.root</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
</listener>
Spring通过org.springframework.web.util.WebAppRootListener 这个监听器将运行路径放到系统变量里。
System.setProperty(key, root); //key="webapp.root" , value=该项目的物理路径,如:"/usr/local/tomcat6/webapps/appname"
在web.xml中如果不显式的配置参数webAppRootKey,默认值为webapp.root,在项目中可以通过以下代码,来动态获项目的运行路径。
System.getProperty("webapp.root")
而部署在同一个容器中的项目,要配置不同的webAppRootKey,否则在启动容器时,就会发生冲突,报2中的错误。
另外,如果在web.xml中配置 org.springframework.web.util.Log4jConfigListener这个监听器,它也包含了WebAppRootListener的功能。所以当在同一容器中部署多个项目时,要显式的声明不同的webAppRootKey,如下:
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>webapp.root</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>oauth.root</param-value>
</context-param>
这样可以在log4j.properties中配置log文件的存储路径:
log4j.appender.file.File=${oauth.root}/WEB-INF/logs/oauth.log