Java Classloading이 Linux에서 실패하지만 Windows에서 성공할 수있는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/519816

문제

Java Web 응용 프로그램 (Spring 사용)이 Jetty와 함께 배포되었습니다. Windows 시스템에서 실행하려고하면 모든 것이 예상대로 작동하지만 Linux 시스템에서 동일한 코드를 실행하려고하면 다음과 같이 실패합니다.

[normal startup output]
11:16:39.657 INFO   [main] org.mortbay.jetty.servlet.ServletHandler$Context.log>(ServletHandler.java:1145) >16> Set web app root system property: 'webapp.root' = [/path/to/working/dir]
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.mortbay.start.Main.invokeMain(Main.java:151)
        at org.mortbay.start.Main.start(Main.java:476)
        at org.mortbay.start.Main.main(Main.java:94)
Caused by: java.lang.ExceptionInInitializerError
        at org.springframework.web.util.Log4jWebConfigurer.initLogging(Log4jWebConfigurer.java:129)
        at org.springframework.web.util.Log4jConfigListener.contextInitialized(Log4jConfigListener.java:51)
        at org.mortbay.jetty.servlet.WebApplicationContext.doStart(WebApplicationContext.java:495)
        at org.mortbay.util.Container.start(Container.java:72)
        at org.mortbay.http.HttpServer.doStart(HttpServer.java:708)
        at org.mortbay.util.Container.start(Container.java:72)
        at org.mortbay.jetty.Server.main(Server.java:460)
        ... 7 more
Caused by: org.apache.commons.logging.LogConfigurationException: org.apache.commons.logging.LogConfigurationException: No suitable Log constructor [Ljava.lang.Class;@15311bd for org.apache.commons.logging.impl.Log4JLogger (Caused by java.lang.NoClassDefFoundError: org/apache/log4j/Category) (Caused by org.apache.commons.logging.LogConfigurationException: No suitable Log constructor [Ljava.lang.Class;@15311bd for org.apache.commons.logging.impl.Log4JLogger (Caused by java.lang.NoClassDefFoundError: org/apache/log4j/Category))
        at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:543)
        at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:235)
        at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:209)
        at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:351)
        at org.springframework.util.SystemPropertyUtils.(SystemPropertyUtils.java:42)
        ... 14 more
Caused by: org.apache.commons.logging.LogConfigurationException: No suitable Log constructor [Ljava.lang.Class;@15311bd for org.apache.commons.logging.impl.Log4JLogger (Caused by java.lang.NoClassDefFoundError: org/apache/log4j/Category)
        at org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFactoryImpl.java:413)
        at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:529)
        ... 18 more
Caused by: java.lang.NoClassDefFoundError: org/apache/log4j/Category
        at java.lang.Class.getDeclaredConstructors0(Native Method)
        at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)
        at java.lang.Class.getConstructor0(Class.java:2699)
        at java.lang.Class.getConstructor(Class.java:1657)
        at org.apache.commons.logging.impl.LogFactoryImpl.getLogConstructor(LogFactoryImpl.java:410)
        ... 19 more
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Category
        at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
        ... 24 more
[shutdown output]

나는 앱을 실행합니다 java -verbose:class, 그 출력에 따르면, org.apache.log4j.category는 첫 번째 예외가 발생하기 직전에 내 /web-inf /lib의 log4j jar에서로드됩니다.

이제 두 기계의 Java 버전은 약간 다릅니다. 두 기계에는 Sun의 Java가 있고 Linux 기계에는 1.6.0_10이 있고 Windows 머신에는 1.6.0_08 또는 07 또는 06이 있습니다. 현재 정확한 숫자를 기억할 수 없으며 기계가 없습니다. . 그러나 자바의 사소한 버전은 약간 다르더라도 코드는 이렇게 깨지 않아야합니다. 여기서 무엇이 잘못되었는지 이해하는 사람이 있습니까?

도움이 되었습니까?

해결책

클래스 로더가 모든 것을 볼 수는 없다는 것을 이해해야합니다. 부모 클래스 로더가로드 한 것만 또는 자신이로드 한 내용 만 볼 수 있습니다. 따라서 두 개의 클래스 로더가있는 경우, 하나는 Jetty와 WebApp 용으로 말하면 WebApp은 Log4J를 볼 수 있지만 (JAR은 Web-Inf/Lib이기 때문에) Jetty의 클래스 로더는 할 수 없습니다.

Log4J를 사용하지만 Jetty의 컨텍스트 (및 클래스 로더)에서 실행되는 Jetty (예 : DB 계층의 무언가)에 클래스를 사용할 수있게하려면 오류가 발생합니다.

이것을 디버그하려면 org.springframework.web.util.log4jwebconfigurer.initlogging ()에서 중단 점을 설정하십시오. 가능하다면이 클래스의 소스를 프로젝트에 복사하고 (나중에 삭제하는 것을 잊지 마십시오)이 줄을 추가하십시오.

ClassLoader cl = Thread.currentThread().getContextClassLoader();

디버거의 CL 객체를 살펴보십시오. 그것은 당신에게 그것을 만든 정보를 제공해야합니다. 내 생각에 이것은 부두의 클래스 로더라는 것입니다.

편집] 두 클래스 로더에 Log4J가있는 경우 다른 혼란에 빠지게됩니다.이 경우에는 The 수업 같은 할당되지 않는 객체를 만들어 호환되는 이름! 따라서이 JAR의 단일 인스턴스 만 있거나 LOG4J 인스턴스는 두 컨텍스트 사이 (일반적으로 불가능한) 사이에 전달되지 않습니다.

다른 팁

이것은 클래식 클래스 로더 문제처럼 보입니다. Log4J를 사용하는 다른 웹 앱이 먼저로드되었지만 테스트중인 앱에서 사용하는 버전과 다른 버전이 발생할 수 있습니다. 클래스 로더는 찾은 첫 번째 버전의 클래스를 사용합니다. 서버 클래스로드 정책은 일반적으로 구성 파일에서 변경할 수 있습니다. 죄송합니다. 이것에 대해 약간 녹슬었지만 아마도 올바른 방향으로 당신을 가리킬 수 있습니다.

  1. 웹 서버에 다른 설치된 앱이 없는지 확인하십시오.
  2. 로드중인 LOG4J가 올바른 버전인지 확인하십시오.
  3. 서버의 클래스 경로 어딘가에 Log4J가 숨어 있지 않은지 확인하십시오.

HTH

두 기계에서 동일한 전쟁을 사용하고 있습니까? 전쟁 파일이 동일한지 확인 했습니까 (전송 오류가 발생하지 않음)?

고려해야 할 몇 가지 임의의 것들 :

(1) Web-App 디렉토리 외부의 Linux 인스턴스에 떠 다니는 다른 버전의 Log4J가 있는지 확인하십시오.

(2) 아파치 커먼즈 로깅이 전혀 사용되고 있습니까? 고려하고 싶을 수도 있습니다 SLF4J 대신에?

(3) 항아리/전쟁이 어떤 식 으로든 부패 했습니까?

(4) 불일치가 있는지 확인하기 위해 각 경우에 클래스 로더 계층 구조를 인쇄합니까?

원래의 문제가 Asker에게 해결되었지만 Windows V Linux (또는 UNIX)에서 동일한 코드를 실행할 때 일반적인 문제의 원인이 사례 감도 문제임을 지적합니다. Linux 또는 Unix는 케이스에 민감한 반면 Windows는 경우를 무시합니다. 이것은 나를 두 번 이상 물었다.

따라서 ClassPath에 항아리 나 디렉토리를 지정하지만 올바른 경우는 아니지만 Linux에서는 실패하지만 Windows에서 성공합니다. 이것은 또한 filenotfoundExeceptions의 원천 일 수 있습니다.

같은 문제가 있었고 쉬운 솔루션/해결 방법을 찾았습니다.

선호도의 Eclipse> Java> 설치된 JRES에서 JRE> 편집을 선택하고 외부 항아리를 추가하고 Log4J.jar를 찾아보십시오.

다른 해결 방법은 ClassPath 탭의 모든 시작 정의에 log4j.jar를 추가하는 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top