2009-08-21 4 views
9

JAR을 동적으로로드하는 응용 프로그램을 개발하고 있습니다. JAR에는 사용하는 클래스 묶음의 정의가 들어 있습니다. 동적으로로드 된 JAR에있는 Exception 파생 클래스를 잡으려고 할 때까지 모든 것이 잘 진행되었습니다.Java에서 예외 클래스는 필요하기 전에 클래스 로더가 사용할 수 있어야하는 이유는 무엇입니까?

다음 코드는 문제를 보여줍니다 (DynamicJarLoader 실제로 JAR를로드하는 클래스이며, 모두 TestClassMyException 외부 JAR에) :

public static void main(String[] args) { 
    DynamicJarLoader.loadFile("../DynamicTestJar.jar"); 
    try { 
     String foo = new TestClass().testMethod("42"); 
    } catch(MyException e) { } 
} 

내가 그것을 실행하려고, 난이 얻을 : 내가 catch(Exception e)catch(MyException e)를 교체 할 경우

Exception in thread "main" java.lang.NoClassDefFoundError: dynamictestjar/MyException 
Caused by: java.lang.ClassNotFoundException: dynamictestjar.MyException 
     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 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) 
     at java.lang.ClassLoader.loadClass(ClassLoader.java:252) 
     at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320) 
Could not find the main class: dynamicjartestapp.Main. Program will exit. 

, 프로그램은 잘 실행됩니다. 즉, Java 이며, JAR이 이미로드 된 후 TestClass을 찾을 수 있습니다. 그래서 JVM은 프로그램이 실행될 때 (그리고 특정 try-catch 블록에 도달 할 때) 필요하지 않을 때가 아니라 모든 Exception 클래스를 정의해야합니다.

왜 이런 일이 발생합니까?

편집

나는 몇 가지 추가 테스트를 실행했습니다, 이것은 실제로 매우 이상하다.

package dynamictestjar; 
public class MyException extends RuntimeException { 
    public void test() { 
     System.out.println("abc"); 
    } 
} 

이 코드가 실행 :

public static void main(String[] args) { 
    DynamicJarLoader.loadFile("../DynamicTestJar.jar"); 
    String foo = new TestClass().testMethod("42"); 
    new MyException().test(); //prints "abc" 
} 

이되지 않습니다

public static void main(String[] args) { 
    DynamicJarLoader.loadFile("../DynamicTestJar.jar"); 
    String foo = new TestClass().testMethod("42"); 
    new MyException().printStackTrace(); // throws NoClassDefFoundError 
    } 

내가 넷빈즈에서 내 테스트를 실행할 때마다 지적한다이 MyException의 전체 소스입니다 모든 것이 계획대로 진행됩니다. 기묘함은 Java의 눈에서 강제로 외부 항아리를 제거하고 명령 줄에서 테스트 응용 프로그램을 실행할 때만 시작됩니다.

public static void main(String[] args) { 
    DynamicJarLoader.loadFile("../DynamicTestJar.jar"); 
    String foo = new TestClass().testMethod("42"); 
    class tempClass { 
     public void test() { 
      new MyException().printStackTrace(); 
     } 
    } 
    new tempClass().test(); // prints the stack trace, as expected 
    } 
+0

바이트 코드 재주문이로드 파일 명령문 앞에 Exception을 참조하면이 문제가 발생할 수 있지만 필자는 이러한 문제에 대해서는 충분히 잘 알고 있지 않습니다. – Yishai

+0

이 방법으로 JAR을로드하는 것을 정당화하는 것은 아무것도 없습니다. 간단한 예입니다 만, 본격적인 코드의 이유는 무엇입니까? – duffymo

+0

@duffymo : 애플릿은 두 개로 나뉩니다. 더 큰 절반은 로컬 컴퓨터에 설치되므로 사용자는 매번 다운로드하지 않습니다 (다소 크기가 큽니다). 실제 애플릿은 다른 애플릿을로드 한 다음 필요한 로직을 수행합니다. "로드 중"이라 함은 실제로 클래스 경로를 동적으로 변경하여 Jar를 가리키는 것을 의미합니다. 아마도 이것을 달성하는 더 좋은 방법이 있을까요? –

답변

1

런타임시 동적으로 JAR DynamicTestJar.jar을로드하지만 코드를 컴파일 할 때 classpath에 추가합니다.

기본 클래스 로더가 main()에 대한 바이트 코드를로드하려고하면 클래스 경로에서 MyException을 찾을 수 없으며 예외가 발생합니다. 이것은 이 발생하기 전에``DynamicJarLoader.loadFile ("../ DynamicTestJar.jar");`가 실행됩니다!

동적 JAR의 클래스가 필요하면 클래스가로드 될 때이 현재 활성화 된 클래스 로더 에 있는지 확인해야합니다. 나중에 JAR을 클래스 패스에 추가 할 수 있습니다. 특히 클래스에서 클래스를 가져 오는 것은 아닙니다.

6

"는 JVM이 모두 필요로 나타납니다 그래서 :

답변을 바탕으로

2, 내가 생각하는이 쓴 편집 # 내가 받아 들인 사람이 참으로 옳다 증명 프로그램이 실행될 때 정의 될 예외 클래스가 필요할 때가 아니라 "- 아니요, 이것이 정확하다고 생각하지 않습니다.

나는 당신의 문제는 JVM과는 아무 상관이 중 어느 것도 당신의 부분에 이러한 잠재적 인 오류로 인해 것을 장담 :

  1. 당신은 상단에 패키지 문을 놓치고 당신의 MyException.java 파일 그것은 당신이 "패키지 dynamictestjar"을 의미하는 것처럼 보이지만 거기에 없습니다.
  2. MyException.java 파일에 올바른 패키지 문이 있었지만 컴파일 할 때 "dynamictestjar"폴더의 MyException.class 파일로 끝나지 않았습니다.
  3. 코드를 DynamicTestJar에 패키지화했을 때.jar (Star Wars fan, 당신은) "dynamictestjar"폴더를 포함하는 디렉토리를 ZIP하지 않았기 때문에 경로를 올바르게 가져 오지 못했기 때문에 클래스 로더가 보는 경로가 올바르지 않습니다.

이들 중 어느 것도 클래스 로더에 대한 큰 신비로 인한 것이 아닙니다. 당신은 당신이 당신의 물건을 바르게하고 있는지 확인하고 확인해야합니다.

왜 동적으로 JAR을로드해야합니까? JAR 파일을 CLASSPATH에 넣고 클래스 로더가 파일을 가져 오면 수행 할 수없는 작업은 무엇입니까?

catch(MyException e) { } 

당신은 적어도 스택 추적을 인쇄하거나 예외를 로깅한다을 사용한다 :이 희망

는 예를 들어 자바에서 "모범 사례"를 표시하지 않습니다.

UPDATE :

내가 넷빈즈에서 내 테스트를 실행할 때마다, 모든 것이 계획대로가는 것을 지적한다. 기묘함은 Java의 눈에서 강제로 외부 항아리를 제거하고 명령 줄에서 테스트 응용 프로그램을 실행할 때만 시작됩니다.

이렇게하면 명령 줄에서 실행할 때 JAR 경로에 연결된 경로가 만족스럽지 않음을 알 수 있습니다.

JVM은 NetBeans와 함께 작동하지 않으며 또 다른 방법으로 작동하지 않습니다. CLASSPATH, 클래스 로더 및 경로 문제를 이해하는 것이 전부입니다. 당신이 당신의 것을 밖으로 분류하면, 효과가 있습니다.

+0

답변 해 주셔서 감사합니다! 뭔가 망칠 수도 있지만 두 가지 사실을 고려해야합니다. i) 'TestClass'가 발견되고 MyException과 동일한 패키지에 있습니다. 난 그냥 jar 파일을 검사하고,'MyException.class'는 있어야 할 곳입니다. ii) Java가 찾을 수있는 곳에 DynamicTestJar.jar을 남겨두면 (예 : lib /), 프로그램이 실행됩니다 (방금 확인했습니다). 또한 NetBeans에서 실행됩니다. 항아리를 삭제하고 Java가 보이지 않는 곳에 놓으면 문제가 나타납니다 (이 경우 ".."). –

+0

오, 그래, 나는 진짜 코드에서 이런 예외를 삼키고 있지 않다! 이것은 문제를 설명하는 가장 단순한 가능한 스 니펫 일 뿐이지 만 머리를 가져 주셔서 감사합니다. –

+0

"Java가 찾을 수있는 곳 ..."- Java에 내장 된/lib 디렉토리를 검색하는 것에 대한 가정은 없습니다. 하나님은 JDK 디렉토리에 코드를 추가하지 않으셨습니까? 날 믿어, 페드로, 아직도 너야. 코드 및 구성은 여전히 ​​문제입니다. TestClass를 "올바른"표시로 찾는 데 성공하지 마십시오. 당신이 그것을 올바르게 얻었을 때, JVM은 예외를 발견 할 것이고 CNF 문제는 사라질 것입니다. – duffymo

3

MyException은 동적으로로드하는 JAR의 예외 클래스입니까?

정적으로이며 코드를 문자 그대로 사용하고 있으므로 MyException 클래스를 사용한다는 점에 유의하십시오.

컴파일하는 동안 DynamicTestJar.jar을 클래스 경로에 넣었습니까? 프로그램을 실행하는 동안 DynamicTestJar.jar을 클래스 경로에 넣고 있습니까? 컴파일하는 동안 클래스 패스에 넣지 마십시오. 그러면 컴파일러가 JAR을 정적 인 방식으로 사용하는 위치를 보여줍니다.

+0

"정적으로"? 그게 무슨 뜻인지 모르겠다. 그는 인스턴스를 생성하고 인스턴스를 호출하기 위해 "new"를 호출합니다. – duffymo

+1

@duffymo :'main' 메소드를 포함한 클래스가로드 될 때,'MyException' 클래스를로드하려고 시도 할 것이고'MyException'을 포함하는 jar를 동적으로로드하는 코드가 아직 실행되지 않았기 때문에 실패 할 것입니다. 그것은 Jesper가 '정적으로 사용'하는 것을 의미합니다. –

+0

+1 - nice spot Jesper –

0

Java에서는 모든 클래스가 클래스의 클래스 로더 및 FQN에 의해 ​​고유하게 식별됩니다.

클래스 로더는 계층 적입니다. 즉, 동적으로로드 된 클래스가 모든 상위 클래스에 액세스 할 수 있지만 상위 클래스는 클래스에 직접 액세스 할 수 없음을 의미합니다.

이제 자식 클래스 로더가 부모를 확장하는 클래스를 정의하면 부모 코드가 리플렉션 또는 부모 클래스를 통해서만 해당 클래스를 참조 할 수 있습니다.

모든 Java 코드를 반사 형으로 생각하면 쉽게 될 수 있습니다. IE :

Class.forName("MyException") 

현재 클래스는 하위 클래스 로더에 액세스 할 수 없으므로이를 수행 할 수 없습니다.

관련 문제