本文将介绍 tomcat 同时启动两个 app 应用时,抛出 “java.lang.IllegalStateException: Web app root system property already set to different value: 'webapp.root' = [****] instead of [****] - Choose unique values for the 'webAppRootKey' context-param in your web.xml files!” 错误信息。具体堆栈错误日志如下:
Feb 02, 2020 9:15:21 PM org.apache.catalina.core.StandardContext listenerStart 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' = [****] instead of [****] - Choose unique values for the 'webAppRootKey' context-param in your web.xml files! at org.springframework.web.util.WebUtils.setWebAppRootSystemProperty(WebUtils.java:163) 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:4651) at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5154) at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5149) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745) ... Feb 02, 2020 9:15:21 PM org.apache.catalina.core.ApplicationContext log INFO: Initializing Spring root WebApplicationContext Feb 02, 2020 9:15:27 PM org.apache.catalina.core.ApplicationContext log INFO: Closing Spring root WebApplicationContext Feb 02, 2020 9:15:27 PM org.apache.catalina.core.ApplicationContext log INFO: Shutting down log4j
解决办法:
看看上面的异常,还是挺简单的。应该是上面两个项目的设置重复了,导致出错。但我发现 web.xml 里并没有配置 webAppRootKey 项,原来是因为 web.xm 内没有设置 webAppRootKey 项,是默认设置。
public static void setWebAppRootSystemProperty(ServletContext servletContext) throws IllegalStateException { String param = servletContext.getInitParameter(WEB_APP_ROOT_KEY_PARAM); String key = (param != null ? param : DEFAULT_WEB_APP_ROOT_KEY); // 如果没有配置,采用默认值 String oldValue = System .getProperty(key); if (oldValue != null ) { throw new IllegalStateException("WARNING: Web app root system property already set: " + key + " = " + oldValue + " - Choose unique webAppRootKey values in your web.xml files!" ); } String root = servletContext.getRealPath("/" ); if (root == null ) { throw new IllegalStateException("Cannot set web app root system property when WAR file is not expanded"); } System .setProperty(key, root); servletContext.log("Set web app root system property: " + key + " = " + root); }
从代码看出,该方法其实就是把该 web application 的根目录的绝对文件路径作为属性保存在 System 的属性列表中。该属性的名字,由 web.xml 文件中的名为 "webAppRootKey" 的参数值指出。如果不在 web.xml 中定义 webAppRootKey 参数,那么属性名就是缺省的 "webapp.root"。
现在我们需要去做的就是为两个项目定义不同当 webAppRootKey 参数,修改 web.xml 文件。如下:
项目1:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>myapp001</display-name> <context-param> <param-name>webAppRootKey</param-name> <param-value>myapp001.root</param-value> </context-param> </web-app>
项目2:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>myapp002</display-name> <context-param> <param-name>webAppRootKey</param-name> <param-value>myapp002.root</param-value> </context-param> </web-app>