헤르메스 LIFE

[Exception] Log4j 관련 java.lang.IllegalStateException: Cannot set web app root system property when WAR file is not expanded 본문

Exception

[Exception] Log4j 관련 java.lang.IllegalStateException: Cannot set web app root system property when WAR file is not expanded

헤르메스의날개 2012. 10. 17. 11:31
728x90


Spring Application을 war로 아카이브 배포할때 아래와 같은 exception이 발생할때가 있습니다. 

SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.util.Log4jConfigListener

java.lang.IllegalStateException: Cannot set web app root system property when WAR file is not expanded

at org.springframework.web.util.WebUtils.setWebAppRootSystemProperty(WebUtils.java:140)


참고 ( 도전의 미학 : http://chanwook.tistory.com/792 )

상황은 WebLogic에 Spring 기반 APP를 WAR로 배포하면 위와 같은 에러가 발생합니다. 저는 처음 봤는데 이미 포럼에도 몇 번 신고(?)가 된 에러입니다.

그리고 Log4jConfigListener의 javadoc에도 이미 warning으로 설명되어 있습니다.

WARNING: Assumes an expanded WAR file, both for loading the configuration file and for writing the log files. If you want to keep your WAR unexpanded or don't need application-specific log files within the WAR directory, don't use Log4J setup within the application(thus, don't use Log4jConfigListener or Log4jConfigServlet). Instead, use a global, VM-wide Log4J setup (for example, in JBoss) or JDK 1.4'sjava.util.logging (which is global too).

아, 참고로 Log4jConfigListener는 클래스 패스 루트가 아닌 위치에 log4j 설정을읽어들여 초기화를 지원하는 유틸 클래스 입니다.

문제는 log4j와 관련되어 나는 것처럼 느낄 수 있지만, 실제 소스를 뒤져보면 영 다른 문제로 발생하게 됩니다.
문제가 되는 WebUtils 클래스의 139번째의 코드는 다음과 같습니다.
String root = servletContext.getRealPath("/");
if (root == null) {
    throw new IllegalStateException("Cannot set web app root system property when WAR file is not expanded");
}

왜 그런지 모르겠지만, 단지 context root 값을 받아오고자 하는 위 메소드에서 웹로직일 경우에만 null이 반환 됩니다.


해결방법 1

web.xml 파일 수정


<context-param>

        <param-name>log4jExposeWebAppRoot</param-name>

        <param-value>/</param-value>

</context-param>


해결방법 2 (불친절한 자수씨 : http://vicki.tistory.com/1340)

스프링에서 사용하는 log4j 쪽이 문제인데 해당 문제는 아래와 같이 해결이 가능합니다.

 

어드민 콘솔에 접속하여 "[Your Domain] > 웹 응용 프로그램 > 아카이브된 실제 경로 사용" 을 체크해줍니다.

 

 

어드민 콘솔과 인스턴스를 재시작 해주면 반영됩니다.


해결방법 3 ( Knot's 블러그 : http://knot.tistory.com/75 )


첫번째로 WebLogic의 도메인 설정을 변경는 방법이 있다.
웹로직의 user project의 도메인 서버 콘솔을 열어서 왼쪽 판넬의  도메인 구조(domain structure)에서 도메인 이름을 클릭한다.
그리고 오른쪽 판넬의 웹 응용 프로그램(Web Application) 탭을 선택한다.
이 설정은 Web Application Container의 속성을 변경하는 것인데, 제일 아래에 보면 "보관된 실제 경로가 사용으로 설정됨" 부분을 체크하도록 한다. 이렇게 하면 war로 배포된 web application에 대한 실제 경로를 가져올 수 있다.
그렇게 하고 패포한 war가 연결된 서버를 재시작 해주고, web application이 정상적으로 시작된다.
이렇게 설정을 하면 
<<weblogic installed derectory>>\user_projects\domains\<<User Domain Name>>\config\config.xml에 
아래와 같은 내용이 추가되어 있는 것을 확인 할 수 있다.

</web-app-container>
        <!-- 기타 설정 내용들......... -->
       <show-archived-real-path-enabled>true</show-archived-real-path-enabled>
</web-app-container>

물론 위의  config.xml내용을 바로 수정해도 된다.


두번째 방법으로는 weblogic.xml 이나 weblogic-application.xml 파일의 내용을 수정하는 것이 있다.
war 배포인 경우(web application) WEB-INF 밑에 weblogic.xml파일을 만들어서 아래의 내용을 넣어주면 되고

<weblogic-web-app>
 <container-descriptor>
  <show-archived-real-path-enabled>true</show-archived-real-path-enabled>
 </container-descriptor>
</weblogic-web-app>



ear 배포인 경우(application )의 경우 META-INF 안에 weblogic-application.xml  파일을 만들어서  아래의 내용을 넣어주면 된다.

<application-param>

<param-name>webapp.getrealpath.accept_context_path
</param-name>

<param-value>true</param-value>
</application-param>

728x90