Когда в энтерпрайз-приложении внезапно летят
ClassNotFoundException, NoSuchMethodError, LinkageError или растёт Metaspace — почти наверняка это ClassLoader Hell: побочный эффект того, как JVM грузит классы.Откуда берётся
1. Конфликт версий: в classpath оказываются разные версии одной библиотеки (например, log4j 1.x и 2.x). Разные ClassLoader’ы подтягивают разные классы →
IncompatibleClassChangeError, падения на старте.2. Утечки ClassLoader’ов: после undeploy web-приложения его ClassLoader не собирается GC (висят ссылки/потоки) → дубли классов, рост памяти,
OutOfMemoryError.Симптомы
-
ClassNotFoundException / NoClassDefFoundError-
LinkageError-ы (IllegalAccess, IncompatibleClassChange, NoSuchMethod)- Нестабильный старт сервера, случайные ошибки, постепенный memory bloat
Как выбраться
- Держи зависимости под контролем: Maven/Gradle,
mvn dependency:tree / gradle dependencies, исключай конфликтующие транзитивные, добивайся convergence версий.- Понимай иерархию серверных загрузчиков (Tomcat/JBoss/WebLogic): изоляция по веб-приложениям; по умолчанию пакуй либы внутрь WAR/EAR, не клади «общие» JAR’ы в shared/lib без крайней нужды.
- Shading/relocation: Maven Shade Plugin → fat JAR + переименование пакетов конфликтующих зависимостей.
- JPMS (Java 9+): явные
requires / exports, сильная инкапсуляция, надёжная конфигурация на старте.- Диагностика: запускай с
-XX:+TraceClassLoading, смотри JVisualVM/JConsole на живых ClassLoader’ах и metaspace.- KISS: меньше зависимостей, регулярные апдейты ключевых библиотек.
Чек-лист на 30 секунд
- Прогоняю дерево зависимостей и фиксирую версии.
- Убираю дубли и «скрытые» транзитивные.
- Проверяю, откуда грузится проблемный класс (трассировка/инструменты).
- Решаю: изоляция на уровне сервера, shading или миграция на JPMS.
Полный разбор с примерами тут
👉@BookJava