java.lang.NoClassDefFoundError для файла JAR, загруженного во время выполнения - PullRequest
3 голосов
/ 21 февраля 2012

Мое Java-приложение запускается примерно так: / usr / java6_64 / bin / java -cp main.jar: updater.jar: jtapi.jar

В некоторых случаях jtapi.jar отсутствует и загружается во время выполнения. Main.jar и Updater.jar предназначены для того, чтобы позаботиться об этом. Это работает безупречно на нескольких ОС, включая AIX 5.3.

Однако в AIX 7.1 происходит сбой, если для начала отсутствует файл jtapi.jar. Вот исключение:

Exception in thread "main" java.lang.NoClassDefFoundError: com.cisco.jtapi.extensions.CiscoProviderObserver
        at java.lang.ClassLoader.defineClass(ClassLoader.java:275)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:69)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:540)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:451)
        at java.net.URLClassLoader.access$300(URLClassLoader.java:79)
        at java.net.URLClassLoader$ClassFinder.run(URLClassLoader.java:1038)
        at java.security.AccessController.doPrivileged(AccessController.java:284)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:429)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:660)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:358)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:626)
        at com.genesyslab.ciscocm.JtapiUpdater.main(JtapiUpdater.java:107)
Caused by: java.lang.ClassNotFoundException: com.cisco.jtapi.extensions.CiscoProviderObserver
        at java.net.URLClassLoader.findClass(URLClassLoader.java:434)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:660)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:358)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:626)
        at java.lang.ClassLoader.defineClassImpl(Native Method)
        ... 12 more

Запуск его снова, сразу после этого, он работает нормально, так как jtapi.jar уже присутствует. Я проверил, что файл jtapi.jar успешно загружен, и даже увеличил задержку, чтобы обеспечить его время. Опять же, в настоящее время это прекрасно работает в более ранних версиях AIX и других ОС.

Есть идеи?

Изменить: До сих пор теория «удаления несуществующих файлов», кажется, подходит лучше всего. Я проверил каноническую идею, используя приведенный ниже код, и вывод один и тот же, независимо от существования jtapi.jar:

File jtapiFile = new File(".", JTAPI_JARFILE);
try {
  LogMain("JtapiUpdater: getCanonicalPath() " +  jtapiFile.getCanonicalPath() + ".");
} catch (IOException e) {}

Выход:
JtapiUpdater: getCanonicalPath () /home/ddg/aix/jtapi.jar.

Однако у меня до сих пор нет простого способа решить эту проблему.

Edit:
Я добавил параметры трассировки в строку выполнения Java:
-Dibm.cl.verbose = com.cisco.jtapi.extensions.CiscoProviderObserver
-Dibm.dg.trc.methods = java / lang / ClassLoader. * () -Dibm.dg.trc.print = m

Выводит, как загрузчик находит классы. Вот что это показывает ...

Если jtapi.jar изначально не присутствует , но загружен Updater.jar:

AppClassLoader attempting to find com.cisco.jtapi.extensions.CiscoProviderObserver
AppClassLoader using classpath /home/ddg/aix/ccm-tserver.jar:/home/ddg/aix/updater.jar:/home/ddg/aix/jtapi.jar
AppClassLoader could not find com/cisco/jtapi/extensions/CiscoProviderObserver.class in /home/ddg/aix/ccm-tserver.jar
AppClassLoader could not find com/cisco/jtapi/extensions/CiscoProviderObserver.class in /home/ddg/aix/updater.jar
AppClassLoader could not find com.cisco.jtapi.extensions.CiscoProviderObserver

Если jtapi.jar присутствует присутствует:

AppClassLoader attempting to find com.cisco.jtapi.extensions.CiscoProviderObserver
AppClassLoader using classpath /home/ddg/aix/ccm-tserver.jar:/home/ddg/aix/updater.jar:/home/ddg/aix/jtapi.jar
AppClassLoader could not find com/cisco/jtapi/extensions/CiscoProviderObserver.class in     /home/ddg/aix/ccm-tserver.jar
AppClassLoader could not find com/cisco/jtapi/extensions/CiscoProviderObserver.class in /home/ddg/aix/updater.jar
AppClassLoader found com/cisco/jtapi/extensions/CiscoProviderObserver.class in /home/ddg/aix/jtapi.jar
AppClassLoader found com.cisco.jtapi.extensions.CiscoProviderObserver

Обратите внимание, что AppClassLoader даже не выполняет поиск /home/ddg/aix/jtapi.jar в случае " не является ", даже если jtapi.jar был успешно загружен и указан в пути к классам!

Я предполагаю, что это ошибка в JVM для AIX 7.1, поскольку она не была проблемой ни в каких других ОС, включая более ранние версии AIX.

1 Ответ

1 голос
/ 21 февраля 2012

Похоже, что JVM в AIX может иметь загрузчик классов по умолчанию, который проверяет, существуют ли записи пути к классам при запуске, и удаляет те, которые не существуют. Однако я не могу проверить это ни в одной документации.

Разве вы не можете просто подождать, пока приложение запустится, пока все файлы .jars не загрузятся?

Если вы не можете, вам может понадобиться использовать собственный загрузчик классов в своем коде, а не вызывать Class.forName().

Редактировать: Я немного покопался: системный загрузчик классов sun.misc.Launcher$AppClassLoader преобразует записи пути к классам в канонические пути и затем создает массив файловых URL-адресов из них. Но каков канонический путь файла, который не существует ?

Каждый путь, который обозначает несуществующий файл или каталог, также имеет уникальную каноническую форму. Каноническая форма пути к несуществующему файлу или каталогу может отличаться от канонической формы того же пути после создания файла или каталога. Точно так же каноническая форма имени пути существующего файла или каталога может отличаться от канонической формы того же имени пути после удаления файла или каталога.

Может быть, в AIX канонические имена существующих и несуществующих файлов различаются?

...