Эта статья является второй частью нашей серии устранения неполадок NoClassDefFoundError. Он сфокусирует и опишет простейший тип проблемы NoClassDefFoundError. Эта статья идеально подходит для начинающих Java, и я настоятельно рекомендую вам скомпилировать и запустить образец Java-программы самостоятельно.
Следующий формат письма будет использоваться идти вперед и предоставит вам:
—
Описание проблемного случая и типа NoClassDefFoundError
Описание проблемного случая и типа NoClassDefFoundError
—
Пример Java-программы, «имитирующей» проблемный случай
Пример Java-программы, «имитирующей» проблемный случай
—
Представление цепочки ClassLoader
Представление цепочки ClassLoader
—
Рекомендации и стратегии решения
Рекомендации и стратегии решения
Проблема NoClassDefFoundError, вариант 1 — отсутствует файл JAR
Первый проблемный случай, который мы рассмотрим, связан с проблемой упаковки программ Java и / или пути к классам. Типичная Java-программа может включать в себя один или несколько файлов JAR, созданных во время компиляции. NoClassDefFoundError часто можно наблюдать , когда вы забыли добавить JAR файл (ы) , содержащий классы Java , на которые ссылается ваш Java или Java EE приложения .
Этот тип проблемы обычно не трудно решить, если проанализировать исключение Java и пропущенное имя класса Java.
Пример Java-программы
Следующая простая Java-программа разделена, как показано ниже:
—
Основная Java-программа
NoClassDefFoundErrorSimulator
Основная Java-программа
NoClassDefFoundErrorSimulator
—
вызывающий Java класс
CallerClassA
вызывающий Java класс
CallerClassA
—
Ссылочный Java-класс
ReferencingClassA
Ссылочный Java-класс
ReferencingClassA
—
класс утилит для ClassLoader и средства ведения журналов
JavaEETrainingUtil
класс утилит для ClassLoader и средства ведения журналов
JavaEETrainingUtil
Эта программа просто пытается создать новый экземпляр и выполнить метод класса Java
CallerClassA,
который ссылается на класс
ReferencingClassA.
Он продемонстрирует, как простая проблема с classpath может вызвать NoClassDefFoundError. Программа также отображает сведения о текущей цепочке загрузчиков классов во время загрузки классов, чтобы помочь вам отслеживать этот процесс. Это будет особенно полезно для будущих и более сложных проблемных ситуаций при работе с более крупными цепями загрузчиков классов.
CallerClassA,
который ссылается на класс
ReferencingClassA.
Он продемонстрирует, как простая проблема с classpath может вызвать NoClassDefFoundError. Программа также отображает сведения о текущей цепочке загрузчиков классов во время загрузки классов, чтобы помочь вам отслеживать этот процесс. Это будет особенно полезно для будущих и более сложных проблемных ситуаций при работе с более крупными цепями загрузчиков классов.
#### NoClassDefFoundErrorSimulator.java package org.ph.javaee.training1; import org.ph.javaee.training.util.JavaEETrainingUtil; /** * NoClassDefFoundErrorTraining1 * @author Pierre-Hugues Charbonneau * */ public class NoClassDefFoundErrorSimulator { /** * @param args */ public static void main(String[] args) { System.out.println("java.lang.NoClassDefFoundError Simulator - Training 1"); System.out.println("Author: Pierre-Hugues Charbonneau"); System.out.println("http://javaeesupportpatterns.blogspot.com"); // Print current Classloader context System.out.println("\nCurrent ClassLoader chain: "+JavaEETrainingUtil.getCurrentClassloaderDetail()); // 1. Create a new instance of CallerClassA CallerClassA caller = new CallerClassA(); // 2. Execute method of the caller caller.doSomething(); System.out.println("done!"); } }
#### CallerClassA.java package org.ph.javaee.training1; import org.ph.javaee.training.util.JavaEETrainingUtil; /** * CallerClassA * @author Pierre-Hugues Charbonneau * */ public class CallerClassA { private final static String CLAZZ = CallerClassA.class.getName(); static { System.out.println("Classloading of "+CLAZZ+" in progress..."+JavaEETrainingUtil.getCurrentClassloaderDetail()); } public CallerClassA() { System.out.println("Creating a new instance of "+CallerClassA.class.getName()+"..."); } public void doSomething() { // Create a new instance of ReferencingClassA ReferencingClassA referencingClass = new ReferencingClassA(); } } #### ReferencingClassA.java package org.ph.javaee.training1; import org.ph.javaee.training.util.JavaEETrainingUtil; /** * ReferencingClassA * @author Pierre-Hugues Charbonneau * */ public class ReferencingClassA { private final static String CLAZZ = ReferencingClassA.class.getName(); static { System.out.println("Classloading of "+CLAZZ+" in progress..."+JavaEETrainingUtil.getCurrentClassloaderDetail()); } public ReferencingClassA() { System.out.println("Creating a new instance of "+ReferencingClassA.class.getName()+"..."); } public void doSomething() { //nothing to do... } } #### JavaEETrainingUtil.java package org.ph.javaee.training.util; import java.util.Stack; import java.lang.ClassLoader; /** * JavaEETrainingUtil * @author Pierre-Hugues Charbonneau * */ public class JavaEETrainingUtil { /** * getCurrentClassloaderDetail * @return */ public static String getCurrentClassloaderDetail() { StringBuffer classLoaderDetail = new StringBuffer(); Stack<ClassLoader> classLoaderStack = new Stack<ClassLoader>(); ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); classLoaderDetail.append("\n-----------------------------------------------------------------\n"); // Build a Stack of the current ClassLoader chain while (currentClassLoader != null) { classLoaderStack.push(currentClassLoader); currentClassLoader = currentClassLoader.getParent(); } // Print ClassLoader parent chain while(classLoaderStack.size() > 0) { ClassLoader classLoader = classLoaderStack.pop(); // Print current classLoaderDetail.append(classLoader); if (classLoaderStack.size() > 0) { classLoaderDetail.append("\n--- delegation ---\n"); } else { classLoaderDetail.append(" **Current ClassLoader**"); } } classLoaderDetail.append("\n-----------------------------------------------------------------\n"); return classLoaderDetail.toString(); } }
Проблема воспроизведения
Чтобы повторить проблему, мы просто «добровольно» опустим один из файлов JAR из пути к классам, который содержит ссылочный класс Java
ReferencingClassA.
ReferencingClassA.
Программа на Java упакована согласно ниже:
—
MainProgram.jar (содержит
NoClassDefFoundErrorSimulator.class
и
JavaEETrainingUtil.class
)
MainProgram.jar (содержит
NoClassDefFoundErrorSimulator.class
и
JavaEETrainingUtil.class
)
—
CallerClassA.jar (содержит
CallerClassA.class
)
CallerClassA.jar (содержит
CallerClassA.class
)
—
ReferencingClassA.jar (содержит
ReferencingClassA.class
)
ReferencingClassA.jar (содержит
ReferencingClassA.class
)
Теперь давайте запустим программу как есть:
## Базовая линия (нормальное исполнение)
.\bin>java -classpath CallerClassA.jar;ReferencingClassA.jar;MainProgram.jar org.ph.javaee.training1.NoClassDefFoundErrorSimulator java.lang.NoClassDefFoundError Simulator - Training 1 Author: Pierre-Hugues Charbonneau http://javaeesupportpatterns.blogspot.com Current ClassLoader chain: ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@17c1e333 --- delegation --- sun.misc.Launcher$AppClassLoader@214c4ac9 **Current ClassLoader** ----------------------------------------------------------------- Classloading of org.ph.javaee.training1.CallerClassA in progress... ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@17c1e333 --- delegation --- sun.misc.Launcher$AppClassLoader@214c4ac9 **Current ClassLoader** ----------------------------------------------------------------- Creating a new instance of org.ph.javaee.training1.CallerClassA... Classloading of org.ph.javaee.training1.ReferencingClassA in progress... ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@17c1e333 --- delegation --- sun.misc.Launcher$AppClassLoader@214c4ac9 **Current ClassLoader** ----------------------------------------------------------------- Creating a new instance of org.ph.javaee.training1.ReferencingClassA... done!
Для начального запуска (базовый уровень) основная программа смогла создать новый экземпляр
CallerClassA
и успешно выполнить его метод; включая успешную загрузку класса
ссылочного
класса ReferencingClassA .
CallerClassA
и успешно выполнить его метод; включая успешную загрузку класса
ссылочного
класса ReferencingClassA .
## Ошибка запуска воспроизведения (с удалением
ReferencingClassA.jar
)
ReferencingClassA.jar
)
../bin>java -classpath CallerClassA.jar;MainProgram.jar org.ph.javaee.training1.NoClassDefFoundErrorSimulator java.lang.NoClassDefFoundError Simulator - Training 1 Author: Pierre-Hugues Charbonneau http://javaeesupportpatterns.blogspot.com Current ClassLoader chain: ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@17c1e333 --- delegation --- sun.misc.Launcher$AppClassLoader@214c4ac9 **Current ClassLoader** ----------------------------------------------------------------- Classloading of org.ph.javaee.training1.CallerClassA in progress... ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@17c1e333 --- delegation --- sun.misc.Launcher$AppClassLoader@214c4ac9 **Current ClassLoader** ----------------------------------------------------------------- Creating a new instance of org.ph.javaee.training1.CallerClassA... Exception in thread "main" java.lang.NoClassDefFoundError: org/ph/javaee/training1/ReferencingClassA at org.ph.javaee.training1.CallerClassA.doSomething(CallerClassA.java:25) at org.ph.javaee.training1.NoClassDefFoundErrorSimulator.main(NoClassDefFoundErrorSimulator.java:28) Caused by: java.lang.ClassNotFoundException: org.ph.javaee.training1.ReferencingClassA at java.net.URLClassLoader$1.run(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) ... 2 more
Что произошло? Удаление ReferencingClassA.jar, содержащего
ReferencingClassA
, не позволило текущему загрузчику классов найти этот ссылочный Java-класс во время выполнения, что привело к ClassNotFoundException и NoClassDefFoundError.
ReferencingClassA
, не позволило текущему загрузчику классов найти этот ссылочный Java-класс во время выполнения, что привело к ClassNotFoundException и NoClassDefFoundError.
Это типичное исключение, которое вы получите, если пропустите JAR-файл (-ы) из вашего начального пути к классу Java или в EAR / WAR для приложений, связанных с Java EE.
ClassLoader view
Теперь давайте рассмотрим цепочку ClassLoader, чтобы вы могли правильно понять этот проблемный случай. Как вы видели из журнала вывода программ Java, были найдены следующие загрузчики классов Java:
Classloading of org.ph.javaee.training1.CallerClassA in progress... ----------------------------------------------------------------- sun.misc.Launcher$ExtClassLoader@17c1e333 --- delegation --- sun.misc.Launcher$AppClassLoader@214c4ac9 **Current ClassLoader** -----------------------------------------------------------------
** Обратите внимание, что загрузчик классов Java начальной загрузки отвечает за загрузку основных классов JDK и написан на собственном коде **
## sun.misc.Launcher $ AppClassLoader
Это загрузчик системных классов, отвечающий за загрузку кода нашего приложения, найденного по пути к классам Java, указанному при запуске.
## sun.misc.Launcher $ ExtClassLoader
Это загрузчик классов расширений, отвечающий за загрузку кода в каталогах расширений (<JAVA_HOME> / lib / ext или любой другой каталог, указанный в системном свойстве java.ext.dirs).
Как вы можете видеть из вывода журнала Java-программы, загрузчик классов расширений является фактическим супер-родителем загрузчика системных классов. Наш образец Java-программы был загружен на уровне загрузчика системного класса. Обратите внимание, что эта цепочка загрузчиков классов очень проста в этом проблемном случае, так как мы не создавали загрузчики дочерних классов на данном этапе. Это будет рассмотрено в следующих статьях.
Рекомендации и стратегии решения
Теперь найдите ниже мои рекомендации и стратегии решения для проблемы 1 NoClassDefFoundError:
—
Просмотрите ошибку java.lang.NoClassDefFoundError и определите отсутствующий класс Java.
Просмотрите ошибку java.lang.NoClassDefFoundError и определите отсутствующий класс Java.
—
Проверьте и найдите отсутствующий класс Java в вашей среде компиляции / сборки.
Проверьте и найдите отсутствующий класс Java в вашей среде компиляции / сборки.
—
Определите, отсутствует ли класс Java из кода вашего приложения, API третьей части или даже самого контейнера Java EE. Проверьте, где / где должны быть найдены отсутствующие JAR-файлы
Определите, отсутствует ли класс Java из кода вашего приложения, API третьей части или даже самого контейнера Java EE. Проверьте, где / где должны быть найдены отсутствующие JAR-файлы
—
Найдя, проверьте вашу среду выполнения Java classpath на наличие опечаток или отсутствующих файлов JAR.
Найдя, проверьте вашу среду выполнения Java classpath на наличие опечаток или отсутствующих файлов JAR.
—
Если проблема вызвана приложением Java EE, выполните те же действия, что и выше, но проверьте упаковку файла EAR / WAR на предмет отсутствия JAR и других зависимостей файла библиотеки, таких как MANIFEST.
Если проблема вызвана приложением Java EE, выполните те же действия, что и выше, но проверьте упаковку файла EAR / WAR на предмет отсутствия JAR и других зависимостей файла библиотеки, таких как MANIFEST.
Пожалуйста, не стесняйтесь оставлять любые вопросы или комментарии. Часть 3 будет доступна в ближайшее время.