Будет предоставлен образец Java-программы, и я призываю вас скомпилировать и запустить этот пример с вашей рабочей станции, чтобы правильно воспроизвести и понять этот тип проблемы NoClassDefFoundError.
Пересмотрен статический инициализатор Java
Язык программирования Java предоставляет вам возможность «статически» инициализировать переменные или блок кода. Это достигается с помощью «статического» идентификатора переменной или использования статического блока {} в заголовке класса Java. Статические инициализаторы гарантированно выполняются только один раз в жизненном цикле JVM и являются поточно-ориентированными по своей конструкции, что делает их использование весьма привлекательным для инициализации статических данных, таких как внутренние кэши объектов, средства ведения журнала и т. Д.
В чем проблема? Я повторю еще раз, статические инициализаторы гарантированно будут выполняться только один раз в жизненном цикле JVM… Это означает, что такой код выполняется во время загрузки класса и никогда не будет выполняться снова, пока вы не перезапустите JVM. Что произойдет, если код, выполненный в это время (время загрузки @Class), завершится необработанным исключением?
Добро пожаловать в проблемный случай java.lang.NoClassDefFoundError # 2!
Проблема NoClassDefFoundError, вариант 2 — статическая ошибка инициализатора
Проблема такого типа возникает после сбоя статического кода инициализатора в сочетании с последовательными попытками создания нового экземпляра затронутого (незагруженного) класса.
Пример Java-программы
Следующая простая Java-программа разделена, как показано ниже:
— Основная Java-программа NoClassDefFoundErrorSimulator
— Уязвимый класс Java ClassA
— ClassA предоставляет вам переключатель ON / OFF, позволяющий вам воспроизвести тип проблемы, которую вы хотите изучить
Эта программа просто пытается создать новый экземпляр ClassA 3 раза (один за другим). Он продемонстрирует, что первоначальный сбой статической переменной или инициализатора статического блока в сочетании с последовательной попыткой создания нового экземпляра затронутого класса вызывает триггеры java.lang.NoClassDefFoundError.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
#### NoClassDefFoundErrorSimulator.javapackage org.ph.javaee.tools.jdk7.training2;/** * NoClassDefFoundErrorSimulator * @author Pierre-Hugues Charbonneau * */public class NoClassDefFoundErrorSimulator { /** * @param args */ public static void main(String[] args) { System.out.println("java.lang.NoClassDefFoundError Simulator - Training 2"); System.out.println("Author: Pierre-Hugues Charbonneau"); try { // Create a new instance of ClassA (attempt #1) System.out.println("FIRST attempt to create a new instance of ClassA...\n"); ClassA classA = new ClassA(); } catch (Throwable any) { any.printStackTrace(); } try { // Create a new instance of ClassA (attempt #2) System.out.println("\nSECOND attempt to create a new instance of ClassA...\n"); ClassA classA = new ClassA(); } catch (Throwable any) { any.printStackTrace(); } try { // Create a new instance of ClassA (attempt #3) System.out.println("\nTHIRD attempt to create a new instance of ClassA...\n"); ClassA classA = new ClassA(); } catch (Throwable any) { any.printStackTrace(); } System.out.println("\n\ndone!"); }} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
#### ClassA.javapackage org.ph.javaee.tools.jdk7.training2;/** * ClassA * @author Pierre-Hugues Charbonneau * */public class ClassA { private final static String CLAZZ = ClassA.class.getName(); // Problem replication switch ON/OFF private final static boolean REPLICATE_PROBLEM1 = true; // static variable initializer private final static boolean REPLICATE_PROBLEM2 = false; // static block{} initializer // Static variable executed at Class loading time private static String staticVariable = initStaticVariable(); // Static initializer block executed at Class loading time static { // Static block code execution... if (REPLICATE_PROBLEM2) throw new IllegalStateException("ClassA.static{}: Internal Error!"); } public ClassA() { System.out.println("Creating a new instance of "+ClassA.class.getName()+"..."); } /** * * @return */ private static String initStaticVariable() { String stringData = ""; if (REPLICATE_PROBLEM1) throw new IllegalStateException("ClassA.initStaticVariable(): Internal Error!"); return stringData; }} |
Проблема воспроизведения
Чтобы повторить проблему, мы просто «добровольно» вызовем сбой статического кода инициализатора. Пожалуйста, просто включите тип проблемы, которую вы хотите изучить, например, ошибка статической переменной или статического блока:
|
1
2
3
|
// Problem replication switch ON (true) / OFF (false) private final static boolean REPLICATE_PROBLEM1 = true; // static variable initializer private final static boolean REPLICATE_PROBLEM2 = false; // static block{} initializer |
Теперь давайте запустим программу с обоими переключателями в положении OFF (оба логических значения в false)
## Базовая линия (нормальное исполнение)
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
java.lang.NoClassDefFoundError Simulator - Training 2 Author: Pierre-Hugues Charbonneau http://javaeesupportpatterns.blogspot.com FIRST attempt to create a new instance of ClassA... Creating a new instance of org.ph.javaee.tools.jdk7.training2.ClassA... SECOND attempt to create a new instance of ClassA... Creating a new instance of org.ph.javaee.tools.jdk7.training2.ClassA... THIRD attempt to create a new instance of ClassA... Creating a new instance of org.ph.javaee.tools.jdk7.training2.ClassA... done! |
Для начального запуска (базовый уровень) основная программа смогла успешно создать 3 экземпляра ClassA без проблем.
## Запуск воспроизведения проблемы (ошибка инициализатора статической переменной)
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
java.lang.NoClassDefFoundError Simulator - Training 2 Author: Pierre-Hugues Charbonneau http://javaeesupportpatterns.blogspot.com FIRST attempt to create a new instance of ClassA... java.lang.ExceptionInInitializerError at org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main( NoClassDefFoundErrorSimulator.java:21 ) Caused by: java.lang.IllegalStateException : ClassA.initStaticVariable(): Internal Error! at org.ph.javaee.tools.jdk7.training2.ClassA.initStaticVariable( ClassA.java:37 ) at org.ph.javaee.tools.jdk7.training2.ClassA.<clinit>( ClassA.java:16 ) ... 1 more SECOND attempt to create a new instance of ClassA... java.lang.NoClassDefFoundError: Could not initialize class org.ph.javaee.tools.jdk7.training2.ClassA at org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main( NoClassDefFoundErrorSimulator.java:30 ) THIRD attempt to create a new instance of ClassA... java.lang.NoClassDefFoundError: Could not initialize class org.ph.javaee.tools.jdk7.training2.ClassA at org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main( NoClassDefFoundErrorSimulator.java:39> ) done! |
## Запуск воспроизведения проблемы (ошибка инициализатора статического блока)
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
java.lang.NoClassDefFoundError Simulator - Training 2 Author: Pierre-Hugues Charbonneau http://javaeesupportpatterns.blogspot.com FIRST attempt to create a new instance of ClassA... java.lang.ExceptionInInitializerError at org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main( NoClassDefFoundErrorSimulator.java:21 ) Caused by: java.lang.IllegalStateException> : ClassA.static{}: Internal Error! at org.ph.javaee.tools.jdk7.training2.ClassA.<clinit>( ClassA.java:22 ) ... 1 more SECOND attempt to create a new instance of ClassA... java.lang.NoClassDefFoundError: Could not initialize class org.ph.javaee.tools.jdk7.training2.ClassA at org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main( NoClassDefFoundErrorSimulator.java:30 ) THIRD attempt to create a new instance of ClassA... java.lang.NoClassDefFoundError: Could not initialize class org.ph.javaee.tools.jdk7.training2.ClassA at org.ph.javaee.tools.jdk7.training2.NoClassDefFoundErrorSimulator.main( NoClassDefFoundErrorSimulator.java:39 ) done! |
Что произошло? Как вы можете видеть, первая попытка создать новый экземпляр ClassA инициировала java.lang.ExceptionInInitializerError. Это исключение указывает на сбой нашего статического инициализатора для нашей статической переменной & блока, что именно то, что мы хотели достичь.
Ключевой момент, который необходимо понять, заключается в том, что этот сбой предотвратил загрузку всего класса ClassA. Как вы можете видеть, попытка № 2 и попытка № 3 сгенерировали java.lang.NoClassDefFoundError, почему? Ну, так как первая попытка не удалась, загрузка класса ClassA была предотвращена. Последовательные попытки создать новый экземпляр ClassA в текущем ClassLoader действительно генерировали java.lang.NoClassDefFoundError снова и снова, поскольку ClassA не был найден в текущем ClassLoader.
Как вы можете видеть, в этом контексте проблемы NoClassDefFoundError — это просто симптом или следствие другой проблемы. Первоначальная проблема — это ExceptionInInitializerError, срабатывающая после сбоя статического кода инициализатора. Это ясно демонстрирует важность правильной обработки ошибок и ведения журнала при использовании статических инициализаторов Java.
Рекомендации и стратегии решения
Теперь найдите ниже мои рекомендации и стратегии решения для проблемы 2 проблемы NoClassDefFoundError:
— Просмотрите ошибку java.lang.NoClassDefFoundError и определите отсутствующий класс Java.
— Выполните пошаговое выполнение кода для затронутого класса и определите, содержит ли он статический код инициализатора (переменные и статический блок)
— Просмотрите журналы сервера и приложения и определите, возникла ли какая-либо ошибка (например, ExceptionInInitializerError) из кода статического инициализатора. — После подтверждения проанализируйте код еще раз и определите основную причину сбоя кода инициализатора. Возможно, вам придется добавить некоторые дополнительные журналы вместе с надлежащей обработкой ошибок, чтобы предотвратить и лучше обрабатывать будущие сбои вашего кода статического инициализатора в будущем.
Пожалуйста, не стесняйтесь оставлять любые вопросы или комментарии.
Часть 4 начнет рассмотрение проблем NoClassDefFoundError, связанных с проблемами загрузчика классов.
Ссылка: java.lang.NoClassDefFoundError: Как решить — часть 3 от нашего партнера по JCG Пьера-Хьюга Шарбонно из блога по шаблонам поддержки Java EE и учебному пособию по Java .