Загрузчик классов Java , часть среды выполнения Java , динамически загружает классы Java в виртуальную машину Java . [1] Обычно классы загружаются только по требованию . Виртуальная машина будет загружать только файлы классов, необходимые для выполнения программы. [2] Системе выполнения Java не нужно знать о файлах и файловых системах, поскольку это делегировано загрузчику классов.
Библиотека программного обеспечения представляет собой набор связанного объектного кода . В языке Java библиотеки обычно упаковываются в файлы JAR . Библиотеки могут содержать объекты разных типов. Наиболее важным типом объекта, содержащегося в файле JAR, является класс Java . Класс можно рассматривать как именованную единицу кода. Загрузчик классов отвечает за поиск библиотек, чтение их содержимого и загрузку классов, содержащихся в библиотеках. Эта загрузка обычно выполняется «по требованию», то есть она не происходит до тех пор, пока класс не будет вызван программой. Класс с заданным именем может быть загружен только один раз заданным загрузчиком классов.
Каждый класс Java должен быть загружен загрузчиком классов. [3] [4] Кроме того, программы Java могут использовать внешние библиотеки (то есть библиотеки, написанные и предоставленные кем-то, кроме автора программы) или они могут состоять, по крайней мере частично, из нескольких библиотек.
При запуске JVM используются три загрузчика классов: [5] [6] [2]
Загрузчик классов bootstrap загружает основные библиотеки Java [fn 1] , расположенные в каталоге <JAVA_HOME>/jre/lib
(или <JAVA_HOME>/jmods>
для Java 9 и выше). Этот загрузчик классов, являющийся частью основной JVM, написан на машинном коде. Загрузчик классов bootstrap не связан ни с одним ClassLoader
объектом. [2] Например, возвращает . [2]StringBuilder.class.getClassLoader()
null
Загрузчик классов расширений загружает код в каталоги расширений ( <JAVA_HOME>/jre/lib/ext
, [5] или любой другой каталог, указанный системным java.ext.dirs
свойством).
Загрузчик системных классов загружает код, найденный в java.class.path
, который сопоставляется с CLASSPATH
переменной среды .
Загрузчик классов Java написан на Java. Поэтому можно создать собственный загрузчик классов, не разбираясь в тонкостях виртуальной машины Java. Помимо загрузчика классов Bootstrap, каждый загрузчик классов Java имеет родительский загрузчик классов. [7] Родительский загрузчик классов определяется, когда создается новый загрузчик классов или устанавливается в качестве системного загрузчика классов виртуальной машины по умолчанию.
Это позволяет (например):
Серверы приложений Jakarta EE (ранее Java EE и J2EE) обычно загружают классы из развернутого архива WAR или EAR с помощью дерева загрузчиков классов, изолируя приложение от других приложений, но разделяя классы между развернутыми модулями. Так называемые « контейнеры сервлетов » обычно реализуются в терминах нескольких загрузчиков классов. [4] [9]
JAR hell — это термин, похожий на DLL hell, используемый для описания всех возможных ситуаций, в которых процесс загрузки классов может не работать. [10] JAR hell может возникнуть тремя способами:
OSGi Alliance определил (начиная с JSR 8 в 1998 году) модульную структуру, которая направлена на решение проблемы JAR-ада для текущих и будущих виртуальных машин в ME, SE и EE, которая широко принята. Используя метаданные в манифесте JAR , файлы JAR (называемые пакетами) подключаются на основе пакетов. Пакеты могут экспортировать пакеты, импортировать пакеты и сохранять пакеты приватными, предоставляя основные конструкции модульности и управления зависимостями версий.
Чтобы исправить проблемы с JAR-адом, в 2005 году был инициирован Java Community Process — JSR 277. Резолюция — Java Platform Module System — была направлена на введение нового формата распространения, схемы управления версиями модулей и общего репозитория модулей (похожий по назначению на Global Assembly Cache Microsoft .NET ) . В декабре 2008 года Sun объявила, что JSR 277 был приостановлен. [12] Java Module System позже была перезагружена как «проект Jigsaw» [13] , который был включен в Java 9. Выпущенный в 2017 году, он включает поддержку модульного программного обеспечения, называемого «Java Platform Module System», которое контролируется на уровне исходного кода с помощью файлов module-info.java. Он следует философии, отличной от архитектуры OSGi, которая направлена на обеспечение модульности для Java Runtime Environment обратно совместимым способом, который использует механизм загрузки классов по умолчанию, предоставляемый JRE. Однако, поскольку он не обеспечивает возможности контролируемого сосуществования библиотек с разными версиями, он не подходит для решения проблемы JAR-ада. [14]