zoukankan      html  css  js  c++  java
  • IllegalStateException : Web app root system property already set to different value问题详解

    一、问题描述

        最近公司有了一个新项目,这个项目最近部署到测试服务器上的时候出现了一个问题。

    严重: 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! 

        在eclipse下面启动是没问题的,打包的时候也没有报错。唯一的区别是测试服务器上tomcat里起了多个项目。

    二、解决方法

        从网上找了各种资料,解决方法是在web.xml中加一段代码

    <context-param>  
        <param-name>webAppRootKey</param-name>  
        <param-value>projectName.root</param-value>  <!-- 建议用"工程名字.root"-->
    </context-param>  

        加了之后,果然解决了。

    三、具体原因

        我是那种不找到具体原因就不甘心的人。

         首先,这个项目用到了log4j(貌似现在大部分项目都在用)。log4j启动时,默认会寻找source folder(src)下的log4j.xml配置文件,若没有,会寻找log4j.properties文件。如果log4j放到别的位置,则需要在web.xml中配置。通过log4jConfigLocation指定文件的位置。

      <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>classpath:config/log4j.properties</param-value>
      </context-param>
      <context-param>
        <param-name>log4jRefreshInterval</param-name>
        <param-value>6000</param-value>
      </context-param>
      <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
      </listener>

        问题来了,问题就出在这个org.springframework.web.util.Log4jConfigListener类里面,点进去看这个class。

    public class Log4jConfigListener implements ServletContextListener {
    
        @Override
        public void contextInitialized(ServletContextEvent event) {
            Log4jWebConfigurer.initLogging(event.getServletContext());
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent event) {
            Log4jWebConfigurer.shutdownLogging(event.getServletContext());
        }
    
    }

        再点进去initLogging这个方法。

    public static void initLogging(ServletContext servletContext) {
            // Expose the web app root system property.
            if (exposeWebAppRoot(servletContext)) {
                WebUtils.setWebAppRootSystemProperty(servletContext);
            }
    
            // Only perform custom log4j initialization in case of a config file.
            String location = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
            if (location != null) {
                // Perform actual log4j initialization; else rely on log4j's default initialization.
                try {
                    // Resolve property placeholders before potentially resolving a real path.
                    location = ServletContextPropertyUtils.resolvePlaceholders(location, servletContext);
    
                    // Leave a URL (e.g. "classpath:" or "file:") as-is.........
          .........

        再点进去setWebAppRootSystemProperty这个方法。

    public static void setWebAppRootSystemProperty(ServletContext servletContext) throws IllegalStateException {
            Assert.notNull(servletContext, "ServletContext must not be null");
            String root = servletContext.getRealPath("/");
            if (root == null) {
                throw new IllegalStateException(
                    "Cannot set web app root system property when WAR file is not expanded");
            }
            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 && !StringUtils.pathEquals(oldValue, root)) {
                throw new IllegalStateException(
                    "Web app root system property already set to different value: '" +
                    key + "' = [" + oldValue + "] instead of [" + root + "] - " +
                    "Choose unique values for the 'webAppRootKey' context-param in your web.xml files!");
            }
            System.setProperty(key, root);
            servletContext.log("Set web app root system property: '" + key + "' = [" + root + "]");
        }

        在这个类里面就能看到拋异常的语句以及拋异常之前处理的逻辑了。

        如果两个工程都不配webAppRootKey,第一个工程启动运行到这个ok,但是第二个工程启动的时候运行到这里,if那里就报错了。

        其实归根究底不是log4j的原因,只要涉及到这个方法,并且没有设置webAppRootKey都会报错。当启动多个工程的时候,应该要配置一下这个webAppRootKey。

  • 相关阅读:
    学习java第20天
    学习java第19天
    学习java第18天
    学习java第17天
    学习java第16天
    java架构师学习路线-Web分布式开发框架概述
    java架构师学习路线-并发编程的概念
    java架构师学习路线-Java系统中的微服务框架
    java架构师学习路线-HashMap的知识点总结归纳
    java架构师学习路线-Java并发编程的五种状态和两种创建方式
  • 原文地址:https://www.cnblogs.com/pwenlee/p/5922687.html
Copyright © 2011-2022 走看看