Что такое загрузчик классов Classloader

Русские Блоги

ClassLoader, как следует из его названия, является «загрузчиком классов». Специальная функция заключается в загрузке файла класса в виртуальную машину jvm, и программа может работать правильно.

Любой программный код, связанный с Java, неотделим от ClassLoader. Например, при запуске JVM ему необходимо загрузить некоторые базовые загрузочные файлы .class, загрузить базовые файлы, такие как String | Integer.class, и загрузить свои собственные написанные бизнес-файлы .class.

Однако при запуске JVM загружает не все файлы классов одновременно, а динамически загружает их по мере необходимости. В конце концов, загружая так много jar-пакетов и так много классов одновременно, странно, что память не падает

1. Класс распознавания файлов

Мы все знаем, что программы на Java работают на виртуальной машине. Обычно мы пишем текстовые редакторы или IDE для написания программ в формате .java. Это самый простой исходный код, но такие файлы не могут быть запущены напрямую. ,

Но виртуальная машина java напрямую не распознает исходные файлы .java, которые мы обычно пишем, поэтому команду javac необходимо преобразовать в файлы .class.

Кроме того, если программа, написанная на C или PYTHON, правильно преобразована в файл .class, виртуальная машина Java также может быть распознана для запуска. Для получения дополнительной информации вы можете обратиться к этомуГлубокое понимание формата файла Java Class (1)

Если мы напишем простую программу HelloWorld.java

Затем нам нужно скомпилировать файл Java в командной строке, вы можете увидеть, что файл .class генерируется в каталоге

Затем мы выполняем команду из командной строки:

这里写图片描述

[Figure helloWord]

После понимания файла .class давайте подумаем о том, как работает Java-программа, которую мы обычно пишем в разработке, то естьКак различные классы, написанные нами, загружаются в jvm (виртуальная машина Java) и выполняются

Во-вторых, понимание переменных среды Java

Когда я впервые изучил java, самой страшной вещью была настройка переменных среды после загрузки JDK, главное, что я не понимал этого в то время, поэтому я следовал инструкциям в книгах или в Интернете.

Вопрос 1. Так зачем нам настраивать переменные среды?

Фактически, если вы хотите заниматься разработкой на Java, вы должны полагаться на некоторые Integer, String, List.class и другие классы, эти классы будут импортированы в наш код средой компиляции при обращении к ним.

Вопрос 2: Итак: мы подумаем об интересном вопросе, где эти классы.

Ответ — несколько пакетов jar в каталоге jdk / lib или jdk / ext, а переменная окружения — это местоположение пакета jar

2.1 Переменные среды

  • JAVA_HOME

Указывает на местоположение вашей установки JDK, обычно устанавливаемой на диск C по умолчанию, например

После включения пути программы в PATH,Вы можете ввести его имя непосредственно в окне командной строки вместо того, чтобы вводить полный путьНапример, две команды javac и java используются в приведенном выше коде.
Обычно добавьте каталог bin в каталоге JDK и bin в каталоге jre к исходному пути PATH.

С одного взглядаУказывать на различные пути пакета jar, Следует отметить, что предыдущий.;,. Представляет текущий каталог

2.2 Установка и просмотр переменных среды

В настройках можно щелкнуть правой кнопкой мыши мой компьютер, затем выбрать «Свойства», затем «Дополнительно», а затем «Переменные среды», в частности, вы сами не понимаете документацию.

Если вы проверите это, вы можете открыть окно командной строки

Три, JAVA класс погрузчик

Языковая система Java поставляется с тремя загрузчиками классов:

Bootstrap ClassLoader класс загрузки верхнего уровня

  • sun.boot.class.path : Загрузить пакет jar по этому пути
  • В основном загружайте базовую библиотеку классов, rt.jar, resources.jar, charsets.jar и класс в% JRE_HOME% lib.
  • Вы можете изменить каталог загрузки Bootstrap ClassLoader, указав -Xbootclasspath и путь при запуске jvm. Например, файл, указанный в java -Xbootclasspath / a: path, добавляется к пути начальной загрузки по умолчанию. Мы можем открыть мой компьютер и проверить в вышеуказанном каталоге, чтобы увидеть, существуют ли эти пакеты JAR в этом каталоге.

Extention ClassLoader расширенный класс загрузчик

  • java.ext.dirs : Загрузить пакет jar по этому пути
  • Загрузите пакет jar и файлы классов в каталог% JRE_HOME% lib ext.
  • Вы также можете загрузить каталог, указанный в опции -D java.ext.dirs.

Приложение ClassLoader также называется SystemAppClass

  • java.class.path : Загрузить пакет jar по этому пути
  • Загрузить все классы текущего пути к классам приложения

Конечно, Java позволяет нам настраивать загрузчик классов:

  • Пользовательский ClassLoader
    • Загрузите .class в любом месте, например, файл, загруженный в сеть, файл на диске D

    3.1 Порядок создания загрузчика

    Мы увидели три класса загрузчиков системы. В какое время и в каком порядке они были созданы? Ответ:

    1. Bootstrap CLassloder
    2. Extention ClassLoader
    3. AppClassLoader

    Мы смотрим на вход в их экземпляр, который является входным приложением виртуальной машины Java,sun.misc.Launcher

    Исходный код оптимизирован, мы можем получить соответствующую информацию:

    1. Launcher инициализирует ExtClassLoader и AppClassLoader.
    2. BootstrapClassLoader не отображается в Launcher, потому что это загрузчик реализации C,
      • Но через System.getProperty («sun.boot.class.path») получил строку bootClassPath, это должен быть путь к пакету jar, загруженному BootstrapClassLoader.

    BootstrapClassLoader, ExtClassLoader, AppClassLoader фактически обращаются к соответствующим свойствам среды sun.boot.class.path 、 java.ext.dirs с участием java.class.path Загрузить файлы ресурсов

    3.1.1 Bootstrap ClassLoader

    Загрузчик ClassLoader естьНаписанный на C ++, он является частью самой виртуальной машины, поэтому это не класс JAVA, То есть вы не можете получить его ссылку в коде Java

    Когда JVM запускается, загрузите файлы классов в основном пакете jar, например rt.jar, через загрузчик классов Bootstrap, Предыдущий int.class, String.class загружаются им

    Bootstrap не имеет родительского загрузчика, но его можно использовать как родительский загрузчик любого ClassLoader, Такие как ExtClassLoader

    • Понимание этого предложения должно сочетаться с процессом loadClass () следующим образом, то есть вДоверено родителямиИтерируя родительский загрузчик в модели,Если родительский загрузчик имеет значение null, встроенный загрузчик jvm заменяется на Bootstrap ClassLoader.

    Сначала мы можем проверить код, что такое sun.boot.class.path:

    3.1.2 ExtClassLoader

    Как мы уже говорили ранее, вы можете указать параметр -D java.ext.dirs для добавления и изменения пути загрузки ExtClassLoader.

    Здесь мы можем написать тестовый код:

    3.1.3 AppClassLoader

    Вы можете видеть, что AppClassLoader загружает путь в java.class.path.

    3.2 У каждого класса есть загрузчик

    1. Создайте файл Test.java
    2. Написать файл ClassLoaderTest.java

    Мы получили загрузчик классов файла Test.class и распечатали его. Результаты:

    Этот класс Test написан нами самими, так кто же загружает int.class или String.class?

    Запустите его, но сообщите об ошибке

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

    Вообще-то нетint.class загружается загрузчиком ClassLoader, Но слой Java не имеет своей ссылки, он загружен слоем C, все возвращают ноль

    Четыре, класс загрузки

    Два способа динамически загружать класс Java:

    1. Неявное, то есть использование функции создания экземпляров для динамической загрузки класса
    2. Есть два явных метода:
      1. java.lang.Class forName () метод
      2. Метод loadClass () класса java.lang.ClassLoader

      4.1 У каждого загрузчика классов есть родительский загрузчик

      4.1.1 Родительским загрузчиком AppClassLoader является ExtClassLoader

      У каждого загрузчика классов есть родительский загрузчик, например, загрузка Test.class выполняется AppClassLoader, затем у AppClassLoader также есть родительский загрузчик, как его получить?
      очень просто с помощью метода getParent.

      Например, код может быть написан так:

      Результаты приведены ниже:

      метод getParent ()

      Мы все уже знаем

      这里写图片描述

      [Figure URLClassLoader]

      Метод getParent () не найден в исходном коде URLClassLoader. Этот метод находится в ClassLoader.java:

      Мы можем видеть, что то, что фактически возвращает getParent (), является родителем объекта ClassLoader, и назначение parent находится в конструкторе объекта ClassLoader. Он имеет две ситуации:

      1. При создании ClassLoader из внешнего класса, прямо укажите ClassLoader в качестве родителя.
      2. Генерируется методом getSystemClassLoader (), который находится в sun.misc.Laucher по getClassLoader() Получить, то есть AppClassLoader 。
        • Проще говоря, если при создании ClassLoader родитель не указан, то его родителем по умолчанию является AppClassLoader.

      Теперь мы смотрим назад, в Launcher.launcher ():

      1. В разработке ExtClassLoader , Родитель ExtClassLoader является нулевым
      1. В разработке AppClassLoader время loader = AppClassLoader.getAppClassLoader(extcl) , Который уже показывает, что родительский элемент AppClassLoader является экземпляром ExtClassLoader

      4.1.2. Родительская загрузка ExtClassLoader — Bootstrap ClassLoader.

      Мы уже говорили в вышеРодитель ExtClassLoader является нулевымТак почему же мы до сих пор говорим, что у него есть родительский загрузчик?

      На самом деле это формальный родительский загрузчик, или он должен быть помещен в процесс loadclass () позжеДоверено родителямиМодель имеет смысл

      Выполните метод loadClass родительского загрузчика. Если родительский загрузчик имеет значение null, будет заменен встроенный загрузчик jvm, то есть Bootstrap ClassLoader.

      Это также объясняет, что родительский элемент ExtClassLoader равен нулю, но все же говорит, что Bootstrap ClassLoader является его родительским загрузчиком.

      4.2 Родительское делегирование

      Каждый ClassLoader поддерживает свое собственное пространство имен, и никакие два класса с одинаковыми именами не могут появляться в одном и том же пространстве имен.

      Когда загрузчик классов ищет класс и ресурс, это делается через «режим делегирования»

      Сначала он определяет, был ли класс успешно загружен (в кэш-памяти загрузчика класса текущего уровня), если нет, он не ищет себя, но сначала передает родительский загрузчик, а затем рекурсивно до Bootstrap ClassLoader. Если Bootstrap

      Если загрузчик классов Bootstrap найден, он возвращается напрямую, если он не найден, он возвращает один уровень за раз и, наконец, достигает себя, чтобы найти эти объекты.

      这里写图片描述

      d Фото автора】

      Мы можем увидетьДелегирование происходит снизу вверх (вверх, чтобы определить, загружен ли кэш), затем конкретный процесс поиска идет сверху вниз (вниз, чтобы найти соответствующий путь и присоединиться к кешу).Опишите это с помощью последовательности:

      1. Когда AppClassLoader находит ресурс, он сначала проверяет наличие кеша, который получается из кеша, в противном случае он делегируется родительскому загрузчику.
      2. Рекурсивно повторите операцию в шаге 1.
      3. Если ExtClassLoader не был загружен, то Bootstrap ClassLoader выйдет вперед.
        • Bootstrap ClassLoader сначала находит кеш, если он не найден, он идет по собственному указанному пути, который sun.mic.boot.class Путь ниже. Вернитесь, если вы найдете это, если вы не найдете его, позвольте загрузчику найти его самостоятельно
      4. Если Bootstrap ClassLoader не найден успешно, ExtClassLoader находится в java.ext.dirs Найдите по пути и верните, если поиск был успешным. Если поиск не дал результатов, пусть загрузчик смотрит вниз
      5. Поиск ExtClassLoader не выполнен, AppClassLoader найдет его сам, в java.class.path Поиск по пути. Вернитесь, когда найдете. Если не найдено, пусть подкласс найдет
      6. Если нет подкласса, будут выданы различные исключения

      这里写图片描述

      Зачем использовать эту модель родительского делегирования?

      1. Поскольку это может избежать повторной загрузки, когда отец загрузил класс, нет необходимости снова загружать дочерний ClassLoader.
      2. Принимая во внимание безопасность, давайте представим, что если мы не используем эту модель делегирования, мы всегда можем использовать пользовательские String.class Для динамической замены типов, определенных в java core api, будет очень большой риск безопасности, и способ родительского делегирования может избежать этой ситуации, потому что String.class Он был загружен при запуске, поэтому пользовательские классы не могут загрузить пользовательский ClassLoade

      4.3 loadClass()

      Процесс загрузки был подробно описан выше, конкретная реализация кода на самом деле

      • loadClass()
        • findLoadedClass()
        • findClass()
        • defineClass()
          Этот метод очень важен при написании пользовательского загрузчика классов. Он может преобразовывать двоичное содержимое класса в объект Class. Если он не соответствует требованиям, он вызывает различные исключения.

        Мы смотрим на loadClass ():

        1. Запустите findLoadedClass (String), чтобы проверить, был ли загружен класс.
        2. Выполните метод loadClass родительского загрузчика. Если родительский загрузчик пуст, встроенный загрузчик jvm будет заменен, то есть Bootstrap ClassLoader. Это также объясняет, что родительский элемент ExtClassLoader равен нулю, но все же говорит, что Bootstrap ClassLoader является его родительским загрузчиком.
        3. Если делегированный вверх родительский загрузчик не был успешно загружен, найдите через findClass (String)

        4.4 forName()

        Class.forName используетЗагрузчик класса CalleeЧтобы загрузить класс.

        Эта функция доказывает, что пространство имен в загрузчике классов Java является уникальным и не будет мешать друг другу.
        В общем, гарантияДругие классы, связанные с тем же классом, определяются загрузчиком классов текущего классаЗагруженный

        В приведенном выше описании ClassLoader.getCallerClassLoader является загрузчиком классов, который получает класс, вызывающий текущий метод forName.

        Пять, пользовательский ClassLoader

        Независимо от того, является ли это Bootstrap ClassLoader или ExtClassLoader и т. Д., Эти загрузчики классов просто загружают пакеты JAR или ресурсы в указанный каталог. Что если нам нужно что-то загружать динамически при определенных обстоятельствах? Например, загрузите файл класса из папки на диске D или загрузите основное содержимое класса из Интернета, а затем загрузите его. Возможно ли это?

        Если вы хотите сделать это, нам нужно настроить загрузчик классов

        1. Напишите класс, унаследованный от ClassLoader Абстрактный класс.
        2. Скопируйте это findClass() метод.
        3. в findClass() Вызов метода defineClass()

        Если при создании ClassLoader родитель не указан, то его родитель по умолчанию — AppClassLoader, так что он может обеспечить доступ к файлу класса, загруженному встроенным загрузчиком системы.

        5.1 Пример DiskClassLoader

        Предположим, нам нужен пользовательский загрузчик классов, путь загрузки по умолчанию — пакет jar и ресурсы в папке D: lib.

        Мы определили метод поиска класса в методе findClass (), а затем данные сгенерировали объект Class с помощью defineClass ()

        5.2 Пример загрузчика класса расшифровки

        Шесть, Context ClassLoader

        Ранее я упоминал Bootstrap ClassLoader, ExtClassLoader, AppClassLoader, а теперь снова появился такой загрузчик классов. Почему?

        Причина, по которой первые три поставлены вперед, заключается в том, что они являются реальными классами и следуют механизму «родительского делегирования».

        ContextClassLoader на самом деле является концептом, просто переменной-членом, устанавливаемой методом setContextClassLoader () и устанавливаемой getContextClassLoader ()

        Каждый поток имеет связанный ClassLoader, по умолчанию это AppClassLoader. И дочерний поток использует родительский загрузчик классов по умолчанию, если дочерний поток не установлен специально

        Используя загрузчик класса контекста потока, вы можете отказаться от режима цепочки загрузки родительского делегирования в потоке выполнения и использовать загрузчик класса в контексте потока для загрузки класса.
        Типичным примером является загрузка реализации jndi сторонней библиотеки через контекст потока без использования родительского делегирования. Большинство серверов приложений Java (jboss, tomcat ..) также используют contextClassLoader для обработки веб-сервис. Существуют также фреймворки, которые используют функцию горячей замены, а также используют загрузчики классов контекста потока, такие как seasar (фреймворк полного стека на японском языке).

        6.1 Пример

        Давайте посмотрим на использование в теме:

        这里写图片描述

        【Рисунок 1】

        Мы можем получить следующую информацию:

        1. DiskClassLoader1 успешно загрузил файл SpeakTest.class и успешно выполнен.
        2. ContextClassLoader дочернего потока является AppClassLoader.
        3. AppClassLoader не может загрузить содержимое SpeakTest.class, уже загруженное в родительский поток

        Давайте изменим код, добавив такое предложение в начало дочернего потока: Thread.currentThread().setContextClassLoader(diskLoader1);

        这里写图片描述

        [рисунок 2]
        Мы можем получить следующую информацию:

        Что такое загрузчик классов Classloader

        This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

        • Open with Desktop
        • View raw
        • Copy raw contents Copy raw contents

        Copy raw contents

        Copy raw contents

        Все примеры написаны с использованием Java 8 .

        Программы, написанные на Java , оперируют классами и объектами классов. При этом классы сначала компилируются в байт-код, после чего уже интерпетируются виртуальной машиной Java .

        Но как скомпилированный байт-код классов попадает в JVM ? Ответ прост: его должен кто-то загрузить.

        Этой задачей в Java занимаются загрузчики классов или classloader -ы.

        Любой класс в среде выполнения Java был загружен каким-либо загрузчиком.

        При этом загружать ‘все’ классы не логично и странно, так как ни к чему загружать то, что не используется.

        Поэтому большинство классов загружаются только по мере надобности, при первой необходимости.

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

        Каждый из загрузчиков отвечает за свою область ответственности.

        Различают три вида загрузчиков:

        Bootstrap Classloader — базовый загрузчик.

        Загружает внутренние классы JDK из $JAVA_HOME/lib , например, rt.jar .

        System Classloader — системный загрузчик.

        Загружает классы, пути к которым указаны в переменной окружения CLASSPATH или пути, которые указаны в командном ряде после ключей –classpath или –cp .

        Extention Classloader — загрузчик расширений.

        Загружает пакеты расширений, которые располагаются в директории /lib/ext или другой директории, описанной в системном параметре java.ext.dirs .

        Существует также возможность создания собственных загрузчиков.

        В таком случае ваш собественный загрузчик должен быть отнаследован от класса java.lang.ClassLoader .

        Загрузчики классов образуют иерархию, корнем которой является базовый загрузчки:

        Classloader hierarchy

        У каждого загрузчика есть ссылка на родительский загрузчик при инициализации, что позволяет делегировать загрузку класса родителю.

        Еще одним важным свойством является то, что каждый загрузчик имеет свое пространство имен для создаваемых классов.

        Это значит, что если два одинаковых класса находятся в одном пакете, но загружаются разными загрузчиками, то такие классы будут считаться двумя разными классами.

        Таким образом можно, например, создать два singleton -объекта.

        Схема загузки класса

        Рассмотрим пример, когда произошло обращение к классу BestNumber .

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

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

        А вот в случае, когда класса у текущего загрузчика нет, происходит делегирование загрузки родительскому загрузчику. В случае, если и там его нет, будет снова вызван родительский загрузчик уже для того, которому делегировали загрузку.

        И так будет происходить пока либо искомый класс не будет найден у загрузчиках, либо цепочка вызовов не дойдет до корневого загрузчика Bootstrap .

        Если в базовом загрузчике нет информации о классе, значит этот класс не был загружен и необходимо его загрузить.

        Базовый загрузчик попытается найти искомый класс в области своей ответственности. Если базовый загрузчик искомый класс найти не смог, то происходит проход по загрузчикам в обратном направлении от текущего, корневого.

        При этом каждый загрузчик будет пытаться найти класс в своей области ответственности.

        Область ответственности — это то, где загрузчик будет искать классы.

        Для корневого загрузчика — это rt.jar , для системного — это в основном classpath .

        Это будет происходить до тех пор, пока либо класс не будет найден, либо поиск не вернет нас к тому загрузчику, с которого все начиналось. И либо тот найдет класс, либо будет сгенерировано исключение java.lang.ClassNotFoundException .

        Проиллюстрируем выше сказанное:

        Classloading

        Для закрепления ответим на несколько вопросов.

        Вопрос:

        Почему, когда мы поняли, что класс не загружен, происходит попытка загрузки у родительского загрузчика?

        С поиском в кэше делегирование понятно, но зачем происходит делегирование загрузки?

        Ответ:

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

        Таким образом достигается максимальная область видимости классов.

        Под областью видимости подразумевается следующее: каждый загрузчик ведет учет классов, которые были им загружены. Этот кэш, содержащий множество загруженных классов, и называется областью видимости.

        Благодаря такому подходу поиск классов будет происходить в источниках в порядке их доверия: сначала в стандартной библиотеке JDK , с помощью базового загрузчика, потом в папке расширений, с помощью загрузчика расширений, и только потом в CLASSPATH уже системным.

        Вопрос:

        Какой класс будет реально загружен, если в $JAVA_HOME/lib/ext и в CLASSPATH есть классы с одинаковыми полными именами?

        Ответ:

        Из всего вышеперечисленного можно заключить, что это будет из $JAVA_HOME/lib/ext , а не из CLASSPATH .

        Вопрос:

        Что произойдет, если в CLASSPATH добавить два jar -файла, содержащих одинаковые классы, с одинаковыми пакетами?

        Например, у меня в CLASSPATH попало две версии одной библиотеки и некоторые классы в jar -никах одинаковы. Что будет в таком случае?

        Ответ:

        Классы загружаются в том порядке, в котором они были указаны в CLASSPATH .

        Это означает, что при наличии двух jar -файлов, например Test1.jar и Test2.jar , содержащих одинаковые классы, и перечисленные в CLASSPATH как Test1.jar;Test2.jar , в память загрузится класс из Test1.jar , а класс из Test2.jar будет проигнорирован.

        Стоит отметить, что ситуаций, когда в CLASSPATH оказывается две версии одной библиотеки надо стараться избегать, так как от того, какая из версий будет использоваться, зависит то, как сформируется CLASSPATH .

        Работа с загрузчиком

        Для того, чтобы получить загрузчик, которым был загружен класс можно воспользоваться методом getClassLoader() у класса:

        Результат запуска кода выше:

        Читателя может смутить вывод null , поэтому стоит объяснить это поведение.

        Здесь null означает то, что класс загружен базовым загрузчиком.

        Решение о возврате null -значения объяснимо тем, чтобы запретить возможность пользователю загружать классы базовым загрузчиком, так как это что-то вроде root в unix .

        Стоит отметить еще то, что при загрузке класса можно явно указать то, каким загрузчиком он должен быть загружен:

        В качестве name передается полное имя класса, с указанием пакета, а в качестве loader необходимый загрузчик.

        Для примера приведем следующий код, где тем же самым загрузчиком, что загружал класс Main , мы загрузим класс java.lang.Thread :

        Возникновение ошибки java.lang.ClassNotFoundException было объяснено при описании процесса загрузки класса. Чаще всего эта ошибка возникает тогда, когда класса нет в CLASSPATH .

        Но существует еще одна популярная и часто встречаемая ошибка, связанная с загрузкой классов. Речь идет о java.lang.NoClassDefFoundError .

        Данная ошибка может возникнуть в случае, если во время компиляции, в compile time , искомый класс был доступен, однако в процессе выполнения программы, в runtime , класс не доступен. Это может произойти, если в поставку программы забыли включить библиотеку, которую она использует.

        Все вышеперечисленное справедливо для повседневной работы. Однако, когда дело касается Java EE -сервера приложений, например Wildfly , все становится немного иначе.

        В окруженни Java EE загрузчик web -модуля опрашивается первыми и не делегирует загрузку родительским загрузчикам классов. Т.е в самом начале он пытается загрузить классы сам и только потом делегирует загрузку.

        При этом данное поведение настраиваемое — его можно переопределить.

        Поэтому при работе с серверами приложений стоит об этом помнить и ознакомиться с документацией по серверу приложений.

        Загрузка классов происходит с помощью classloader -ов или загрузчиков классов, которые выстроены в четкую иерархию, где каждому принадлежит своя область ответственности.

        Попытка загрузить класс текущим загрузчиком выполняется только в том случае, если родительский загрузчик не смог найти и загрузить класс.

        Каждый загрузчик ведет учет классов, которые были загружены именно им, помещая их в свой кэш.

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

        Различают три вида загрузчиков:

        Bootstrap Classloader — базовый загрузчик.

        Загружает внутренние классы JDK из rt.jar .

        System Classloader — системный загрузчик.

        Загружает классы, пути к которым указаны в переменной окружения CLASSPATH или пути, которые указаны в командном ряде после ключей –classpath или –cp .

        Extention Classloader — загрузчик расширений.

        Загружает пакеты расширений, которые располагаются в директории /lib/ext или другой директории, описанной в системном параметре java.ext.dirs .

        Процесс загрузки класса в кратце выглядит следующим образом:

        1. Системный загрузчик проверяет: был ли данный класс загружен ранее?
        2. Если да — то класс вернется из кэша, если нет — то он делегирует загрузку вышестоящему родительскому классу-загрузчику.
        3. Вышестоящий загрузчик проделывает ту же процедуру.
        4. Это происходит до тех пор, пока либо класс не находится в кэше у загрузчиков, либо не достигается базовый загрузчик.
        5. Базовый загрузчик также проверяет свой кэш и если не находит класс, то пытается загрузить класс самостоятельно оттуда, областью котрой заведует, т.е из rt.jar .
        6. Если там искомого класса нет, то происходит обратный обход иерархии.
        7. Это происходит до тех пор, пока либо класс будет загружен, либо будет выброшено исключение java.lang.ClassNotFoundException .

        В Java также существует возможность использовать свои собственные загрузчики классов.

        Внутренности JVM, Часть 1 — Загрузчик классов

        В этой серии статей я расскажу о том, как работает Java Virtual Machine. Сегодня мы рассмотрим механизм загрузки классов в JVM.

        Виртуальная машина Java — это сердце экосистемы Java-технологий. Она делает для Java-программ возможность реализации принципа «написано один раз, работает везде» (write once run everywhere). Как и другие виртуальные машины, JVM представляет собой абстрактный компьютер. Основная задача JVM — загружать class-файлы и выполнять содержащийся в них байт-код.

        В состав JVM входят различные компоненты, такие как загрузчик классов (Classloader), сборщик мусора (Garbage Collector) (автоматическое управление памятью), интерпретатор, JIT-компилятор, компоненты управления потоками. В этой статье рассмотрим загрузчик классов (Class loader).

        Загрузчик классов загружает class-файлы как для вашего приложения, так и для Java API. В виртуальную машину загружаются только те class-файлы Java API, которые действительно требуются при выполнении программы.

        Байт-код выполняется подсистемой исполнения (execution engine).

        Что такое загрузка классов?

        Загрузка классов — это поиск и загрузка типов (классов и интерфейсов) динамически во время выполнения программы. Данные о типах находятся в бинарных class-файлах.

        Этапы загрузки классов

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

        • Загрузка (loading) — поиск и импорт бинарных данных для типа по его имени, создание класса или интерфейса из этого бинарного представления.
        • Связывание, линковка (linking) — выполнение верификации, подготовки и, необязательного, разрешения:
          • Верификация (verification) — проверка корректности импортируемого типа.
          • Подготовка (preparation) — выделение памяти для статических переменных класса и инициализация памяти значениями по умолчанию.
          • Разрешение (resolution) — преобразование символьных ссылок типов в прямые ссылки.

          Примечание — загрузчик классов, помимо загрузки классов, также отвечает за поиск ресурсов. Ресурс — это некоторые данные (например, “.class” файл, данные конфигурации, изображения), которые идентифицируются с помощью абстрактного пути, разделенного символом «/». Ресурсы обычно упаковываются вместе с приложением или библиотекой для того, чтобы их можно было использовать в коде приложения или библиотеки.

          Механизм загрузки классов в Java

          Примечание переводчика — в данном разделе описано поведение для java < 9, в java 9+ произошли небольшие изменения, которые описаны ниже.

          В Java используется модель делегирования загрузки классов. Основная идея состоит в том, что у каждого загрузчика классов есть “родительский” загрузчик. Когда происходит загрузка класса, то загрузчик “делегирует” поиск класса своему родителю, перед тем как искать класс самостоятельно.

          Модель делегирования загрузчиков классов представляет собой граф загрузчиков, которые передают друг другу запросы на загрузку. Корнем в этом графе является bootstrap-загрузчик. Загрузчики классов создаются с одним родителем, которому они могут делегировать загрузку, и осуществляют поиск класса в следующих местах:

          • Кэш
          • Родитель
          • Сам загрузчик

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

          В Java SE Platform API исторически было определено два загрузчика классов:

          Bootstrap class loader (базовый, первичный загрузчик) — загружает классы из bootstrap classpath.

          System class loader (системный загрузчик) — родительский класс для новых загрузчиков классов и, как правило, загрузчик классов, используемый для загрузки и запуска приложения.

          Загрузчики классов JDK 9+

          Application class loader — обычно используется для загрузки классов приложения из classpath. Также это загрузчик по умолчанию для некоторых модулей JDK, которые содержат утилиты или экспортируют API утилит. (Примечание переводчика: например, jdk.jconsole , jdk.jshell и др)

          Platform class loader — загружает выбранные (на основе безопасности / разрешений) модули Java SE и JDK. Например, java.sql.

          Bootstrap class loader — загружает основные модули Java SE и JDK.

          Эти три встроенных загрузчика классов работают вместе следующим образом:

          • Application class loader сначала ищет именованные модули, определенные для всех встроенных загрузчиков. Если для одного из этих загрузчиков определен подходящий модуль, то этот загрузчик загружает класс. Если в именованном модуле, определенном для одного из этих загрузчиков, класс не найден, тогда application class loader делегирует его родителю. Если класс не найден родителем, то application class loader ищет его в classpath. Классы, найденные в classpath, загружаются как члены безымянного модуля этого загрузчика.
          • Platform class loader выполняет поиск именованных модулей, определенных для всех встроенных загрузчиков. Если подходящий модуль определен для одного из этих загрузчиков, тогда этот загрузчик загружает класс. Если в именованном модуле, определенном для одного из этих загрузчиков, класс не найден, тогда platform class loader делегирует его родителю.
          • Bootstrap class loader выполняет поиск именованных модулей, определенных для него самого. Если класс не найден в именованном модуле, определенном для bootstrap-загрузчика, тогда bootstrap-загрузчик ищет файлы и каталоги, добавленные в bootstrap classpath, с помощью параметра -Xbootclasspath/a (позволяет добавить файлы и каталоги к bootstrap classpath). Классы, найденные в bootstrap classpath, загружаются как члены безымянного модуля этого загрузчика.

          Запустив этот код на установленном у меня Amazon Corretto 11.0.3, получим следующий результат:

          Подробно про ClassLoader в Java – примеры

          Работая на Java, мы часто используем большое количество классов. Они не загружаются все сразу в память, вместо этого загружаются, когда требуется приложением. Тогда и требуется ClassLoaders.

          Что такое ClassLoader в Java?

          ClassLoader в Java вызывается средой выполнения для динамической загрузки классов, когда это требуется приложением на виртуальной машине. Поскольку ClassLoaders являются частью Java Runtime Environment, виртуальная машина не будет иметь никакого представления о базовых файлах и файловых системах.

          • Расширение (Extension ClassLoader).
          • Приложение или Система (Application or System ClassLoader).
          • Загрузчик (Bootstrap ClassLoader).

          Расширение

          Как следует из названия, загружает расширения основных классов Java из библиотеки расширений JDK. Он является дочерним элементом загрузчика Bootstrap ClassLoader и загружает расширения из каталога JRE / lib / text или любого другого каталога, указанного в системном свойстве java.ext.dirs.

          Приложение или система

          Является дочерним по отношению к Extension ClassLoader. Этот тип загружает все классы уровня приложения, найденные в параметре командной строки -cp или в переменной среды CLASSPATH.

          Загрузчик

          Как все мы знаем, что Java-классы загружаются экземпляром java.lang.ClassLoade. Но поскольку ClassLoaders являются классами, Bootstrap ClassLoader отвечает за загрузку внутренних классов JDK. По сути, это машинный код, который запускает операцию, когда JVM вызывает ее и загружает классы из rt.jar. Таким образом, вы можете понять, что служба Bootstrap ClassLoader не имеет родительского ClassLoader и поэтому известна как Primordial ClassLoader.

          Примечание. Приоритет Bootstrap выше, чем Extension, а приоритет, присвоенный Extension ClassLoader, выше, чем Application ClassLoader. Обратитесь к изображению ниже:

          Типы загрузчика классов

          Принципы

          Набор правил, на основе которых работает ClassLoader, состоит из следующих трех принципов:

          • Свойство уникальности.
          • Модель делегирования.
          • Принцип видимости.

          Свойство уникальности

          Это свойство гарантирует, что нет повторения классов, и все классы являются уникальными. Также гарантирует, что классы, загружаемые родительским ClassLoader, не загружаются дочерним. В сценарии, где родительский ClassLoader не может найти класс, текущий экземпляр попытается сделать это сам.

          Модель делегирования

          ClassLoader работает на основе набора операций, заданных моделью делегирования. Таким образом, всякий раз, когда генерируется запрос на поиск класса или ресурса, экземпляр ClassLoader делегирует поиск класса или ресурса родительскому ClassLoader.

          Набор операций, на основе которых работает ClassLoader:

          • Виртуальная машина проверяет, загружен ли класс или нет, всякий раз, когда он сталкивается с классом.
          • В случае, когда класс загружен, JVM продолжает выполнение класса, но когда класс не загружен, JVM просит подсистему ClassLoader загрузить этот конкретный класс. После этого подсистема передает управление Application ClassLoader.
          • Затем Application делегирует запрос Extension, которое затем передает запрос Bootstrap .
          • Теперь Bootstrap ищет в пути Bootstrap classpath, чтобы проверить, доступен ли класс или нет. Если класс доступен, он загружается, в противном случае запрос снова передается в Extension.
          • Extension проверяет класс в расширении classpath. Если класс доступен, он загружается, в противном случае запрос снова передается в Application.
          • Наконец, Application ищет класс в пути к классам приложения. Если класс доступен, то загружается, иначе вы увидите исключение ClassNotFoundException.

          работа classloader

          Обратитесь к изображению ниже.

          Принцип видимости

          Согласно этому принципу, дочерние классы видны для классов, загруженных их родительскими ClassLoaders, но наоборот не соответствует действительности. Таким образом, классы, загруженные Application, имеют видимость классов, загруженных Extension и Bootstrap.

          Например, если у нас есть два класса: A и B, предположим, что класс A загружается Application, а класс B загружается Extension. Здесь классы A и B видны всем тем классам, которые загружены Application, но класс B виден только тем классам, которые загружены Extension.

          Кроме того, если вы попытаетесь загрузить эти классы с помощью Bootstrap ClassLoader, вы увидите java.lang.ClassNotFoundException исключение.

          Методы

          Вот несколько основных методов:

          • loadClass (имя строки, логическое разрешение);
          • defineClass();
          • findClass (Строковое имя);
          • Class.forName (имя строки, логическая инициализация, загрузчик ClassLoader);
          • getParent();
          • getResource().

          loadClass()

          Этот метод является точкой входа ClassLoader и используется для загрузки класса, на который ссылается JVM. Он принимает имя класса в качестве параметра. JVM вызывает метод loadClass() для разрешения ссылок на класс, устанавливая логическое значение true. Только если нам нужно определить, существует ли класс или нет, логический параметр имеет значение false.

          defineClass()

          Последний метод, используемый для определения массива байтов как экземпляра класса. В случае, если класс является недействительным, он выдает ClassFormatError.

          findClass ()

          Метод используется для поиска указанного класса. Таким образом, он просто находит класс с полностью определенным именем в качестве параметра, но не загружает его. Метод loadClass() вызывает этот метод, если родительский ClassLoader не может найти запрошенный класс. Кроме того, если ни один из родителей ClassLoader не находит класс, реализация по умолчанию генерирует исключение ClassNotFoundException.

          Class.forName ()

          Этот метод используется для загрузки и инициализации класса. Это дает возможность выбрать любой из ClassLoaders и в случае, если параметр ClassLoader равен NULL, тогда автоматически используется Bootstrap ClassLoader.

          GetParent()

          Метод getParent используется для возврата родительского ClassLoader для делегирования.

          getResource()

          Метод getResource() пытается найти ресурс с заданным именем. Первоначально он делегирует запрос родительскому ClassLoader для ресурса. В случае, если родительский элемент является нулевым, ищется путь к ClassLoader, встроенному в JVM.

          Теперь, если это не удается, тогда метод вызовет findResource (), чтобы найти ресурс, где имя ресурса указывается как вход, который может быть как абсолютным, так и относительным путем к классу. Затем он возвращает объект URL для чтения ресурса или возвращает нулевое значение, если у ресурса нет соответствующих прав для возврата ресурса или он не найден.

          Пользовательский ClassLoader в Java

          Встроенные ClassLoaders позаботятся о большинстве случаев, когда файлы уже находятся в файловой системе, но если вы хотите загрузить классы с локального жесткого диска, вам нужно использовать пользовательские ClassLoaders.

          Как создать

          Чтобы создать, вам нужно расширить класс ClassLoader и переопределить метод findClass().

          Пример: Давайте создадим собственный ClassLoader, который расширяет стандартный ClassLoader и загружает байтовый массив из указанного файла.

          Как происходит загрузка классов в JVM

          После того, как самая сложная часть в работе программиста выполнена и приложение «Hello World 2.0» написано, осталось собрать дистрибутив и передать его заказчику, ну или хотя бы в службу тестирования. В дистрибутиве у нас все как полагается и, запуская нашу программу, на сцену выходит Java Virtual Machine. Ни для кого не секрет, что виртуальная машина считывает команды, представленные в class-файлах в виде байт-кода и транслирует их в виде инструкций процессору. Предлагаю немного разобраться в схеме попадания байт-кода в виртуальную машину.

          Загрузчик классов

          загрузка байт-кода из ресурсов и создание экземпляра класса Class

          сюда входит поиск запрошенного класса среди загруженных ранее, получение байт-кода для загрузки и проверка его корректности, создание экземпляра класса Class (для работы с ним в runtime), загрузка родительских классов. Если родительские классы и интерфейсы не были загружены, то и рассматриваемый класс считается не загруженным.

          связывание (или линковка)

          по спецификации этот этап разбивается еще на три стадии:

          • Verification, происходит проверка корректности полученного байт-кода.
          • Preparation, выделение оперативной памяти под статические поля и инициализация их значениями по умолчанию (при этом явная инициализация, если она есть, происходит уже на этапе инициализации).
          • Resolution, разрешение символьных ссылок типов, полей и методов.

          инициализация полученного объекта

          здесь, в отличие от предыдущих пунктов, вроде бы все понятно, что должно происходить. Было бы, конечно, интересно разобраться как именно это происходит.

          • Класс должен быть полностью загружен прежде, чем слинкован.
          • Класс должен быть полностью проверен и подготовлен прежде, чем проинициализирован.
          • Ошибки разрешения ссылок происходят во время выполнения программы, даже если были обнаружены на этапе линковки.

          Типы загрузчиков Java

          Bootstrap – базовый загрузчик, также называется Primordial ClassLoader.

          загружает стандартные классы JDK из архива rt.jar

          Extension ClassLoader – загрузчик расширений.

          загружает классы расширений, которые по умолчанию находятся в каталоге jre/lib/ext, но могут быть заданы системным свойством java.ext.dirs

          System ClassLoader – системный загрузчик.

          загружает классы приложения, определенные в переменной среды окружения CLASSPATH

          Абстрактный класс ClassLoader

          Каждый загрузчик, за исключением базового, является потомком абстрактного класса java.lang.ClassLoader . Например, реализацией загрузчика расширений является класс sun.misc.Launcher$ExtClassLoader , а системного загрузчика – sun.misc.Launcher$AppClassLoader . Базовый загрузчик является нативным и его реализация включена в JVM. Любой класс, который расширяет java.lang.ClassLoader , может предоставить свой способ загрузки классов с блэк-джеком и этими самыми. Для этого необходимо переопределить соответствующие методы, которые на данный момент я могу рассмотреть только поверхностно, т.к. не разбирался детально в этом вопросе. Вот они: loadClass(String name) один из немногих публичных методов, который и является точкой входа для загрузки классов. Его реализация сводится к вызову другого protected метода loadClass(String name, boolean resolve) , его и необходимо переопределить. Если посмотреть Javadoc этого защищенного метода, то можно понять примерно следующее – на вход подаются два параметра. Один это бинарное имя класса (или полностью определенное имя класса), который необходимо загрузить. Имя класса указывается с перечислением всех пакетов. Второй параметр – это флаг, определяющий, требуется ли выполнять процедуру разрешения символьных ссылок. По умолчанию он равен false, что означает использование ленивой загрузки классов. Далее, согласно документации, в реализации метода по умолчанию происходит вызов findLoadedClass(String name) , который проверяет был ли класс уже загружен ранее и если это так, вернет ссылку на этот класс. Иначе будет вызван метод загрузки класса у родительского загрузчика. Если ни один из загрузчиков не смог найти загруженный класс, каждый из них, следуя в обратном порядке, попытается этот класс найти и загрузить, переопределяя метод findClass(String name) . Подробнее об этом будет рассмотрено в главе «Схема загрузки классов». И наконец, в последнюю очередь, после того как класс удалось загрузить, в зависимости от флага resolve будет решено стоит ли выполнять загрузку классов по символьным ссылкам. Явный пример того, что стадия Resolution может быть вызвана на этапе загрузки класса. Соответственно, расширяя класс ClassLoader и переопределяя его методы, пользовательский загрузчик может осуществлять свою логику поставки байт-кода в виртуальную машину. Также в Java поддерживается понятие «текущего» загрузчика классов. Текущий загрузчик это тот, который загрузил класс, выполняющийся в данный момент. Каждый класс знает, каким загрузчиком он был загружен, и можно получить эту информацию, вызвав у него метод String.class.getClassLoader() . Для всех классов приложения «текущий» загрузчик, как правило, системный.

          Три принципа загрузки классов

          Делегирование

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

          Видимость

          Загрузчик видит только «свои» классы и классы «родителя» и понятия не имеет о классах, которые были загружены его «потомком».

          Уникальность

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

          Схема загрузки классов

          Когда происходит вызов загрузки какого-либо класса, происходит поиск этого класса в кэше уже загруженных классов текущего загрузчика. Если желаемый класс еще не загружался ранее, по принципу делегирования управление передается родительскому загрузчику, который находится по иерархии на уровень выше. Родительский загрузчик также пытается найти желаемый класс у себя в кэше. Если класс уже был загружен и загрузчик знает о его местонахождении, то будет возвращен объект Class этого класса. Если нет, поиск будет продолжаться до тех пор, пока не дойдет до базового загрузчика. Если и в базовом загрузчике нет информации об искомом классе (т.е. он еще не был загружен), будет выполнен поиск байт-кода этого класса по расположению классов, о котором знает данный загрузчик, и, если загрузить класс не удастся, управление вернется обратно загрузчику-потомку, который будет пытаться выполнить загрузку из известных ему источников. Как уже упоминалось выше, расположение классов для базового загрузчика это библиотека rt.jar, для загрузчика расширений – каталог с расширениями jre/lib/ext, для системного – CLASSPATH, для пользовательского это может быть что-то свое. Таким образом, ход загрузки классов идет в обратном направлении — от корневого загрузчика до текущего. Когда байт-код класса найден, происходит загрузка класса в JVM и получение экземпляра типа Class . Как нетрудно заметить, описанная схема загрузки похожа на приведенную выше реализацию метода loadClass(String name) . Ниже можно рассмотреть эту схему на диаграмме.

          Как происходит загрузка классов в JVM - 2

          В качестве заключения

          На первых шагах изучения языка нет какой-то особой необходимости в понимании того, как происходит загрузка классов в Java, но знание этих базовых принципов позволит не впадать в отчаяние, встретив такие ошибки, как ClassNotFoundException или NoClassDefFoundError . Ну или хотя бы примерно понимать, в чем корень проблемы. Так исключение ClassNotFoundException возникает при динамической загрузке класса во время выполнения программы, когда загрузчики не могут найти требуемый класс ни в кэше, ни по пути нахождения классов. А вот ошибка NoClassDefFoundError является более критичной и возникает в том случае, когда во время компиляции искомый класс был доступен, но не виден во время выполнения программы. Это может произойти, если в поставку программы забыли включить библиотеку, которую она использует. Ну и сам факт понимания принципов устройства того инструмента, которым пользуешься в работе (не обязательно четкое и детальное погружение в его недра), добавляет некоторую ясность в понимании протекающих внутри этого механизма процессов, что, в свою очередь, ведет к уверенному использованию этого инструмента.

          Источники

          How ClassLoader Works in Java В целом очень полезный источник с доступным изложением информации. Загрузка классов, ClassLoader Довольно объемная статья, но с уклоном на то, как сделать свою реализацию загрузчика с этими самыми. ClassLoader: динамическая загрузка классов К сожалению, этот ресурс сейчас недоступен, но там я нашел самую понятную диаграмму со схемой загрузки классов, поэтому не могу не добавить. Java SE Specification: Chapter 5. Loading, Linking, and Initializing

          ClassLoader в Java

          ClassLoader в Java вызывается средой выполнения для динамической загрузки классов, когда это требуется приложением на виртуальной машине. Поскольку загрузчики классов являются частью среды выполнения, виртуальная машина не будет иметь никакого представления о базовых файлах и файловых системах.

          • Расширение ClassLoader (Extension).
          • Приложение или Система ClassLoader (Application or System).
          • Загрузчик ClassLoader (Bootstrap).

          Расширение

          Загружает расширения основных классов Java из библиотеки расширений JDK. Он является дочерним элементом Bootstrap и загружает расширения из каталога JRE / lib / text или любого другого каталога, указанного в системном свойстве java.ext.dirs.

          Приложение или Система

          Является дочерним по отношению к Extension. Этот тип загружает все классы уровня приложения, найденные в параметре командной строки -cp или в переменной среды CLASSPATH.

          Загрузчик

          Как все мы знаем, что Java-классы загружаются экземпляром java.lang.ClassLoade. Но поскольку ClassLoaders являются классами, Bootstrap отвечает за загрузку внутренних классов JDK. Представляет собой машинный код, который запускает операцию, когда JVM вызывает ее и загружает классы из rt.jar. Таким образом, вы можете понять, что служба Bootstrap не имеет родительского ClassLoader и, таким образом, называется Primordial ClassLoader.

          Примечание. Приоритет Bootstrap выше, чем Extension, а приоритет, присвоенный Extension ClassLoader, выше, чем Application ClassLoader. Обратитесь к изображению ниже:

          Типы загрузчика классов

          Принципы

          Набор правил, на основе которых работает Java ClassLoader, состоит из следующих трех принципов:

          • Свойство уникальности.
          • Модель делегирования.
          • Принцип видимости.

          Свойство уникальности

          Это свойство гарантирует, что нет повторения классов, и все классы являются уникальными. Свойство уникальности также гарантирует, что классы, загружаемые родительским ClassLoader, не загружаются дочерним. В сценарии, где родительский ClassLoader не может найти класс, текущий экземпляр попытается сделать это самостоятельно.

          Модель делегирования

          ClassLoader работает на основе набора операций, заданных моделью делегирования. Таким образом, всякий раз, когда генерируется запрос на поиск класса или ресурса, экземпляр ClassLoader делегирует поиск класса или ресурса родительскому ClassLoader.

          Набор операций, на основе которых работает ClassLoader:

          • Виртуальная машина проверяет, загружен ли класс или нет, всякий раз, когда она сталкивается с классом.
          • В случае, если класс загружен, JVM продолжает выполнение класса, но в сценарии, где класс не загружен, JVM просит подсистему ClassLoader загрузить этот конкретный класс. После этого подсистема ClassLoader передает управление приложению ClassLoader.
          • Затем приложение ClassLoader делегирует запрос расширению ClassLoader, которое затем передает запрос загрузчику ClassLoader.
          • Теперь загрузчик ClassLoader ищет в пути своем classpath, чтобы проверить, доступен ли класс или нет. Если класс доступен, он загружается, в противном случае запрос снова передается в расширение.
          • Расширение проверяет класс в расширении classpath. Если класс доступен, он загружается, в противном случае запрос снова передается в приложение ClassLoader.
          • Наконец, приложение ClassLoader ищет класс в пути к классам приложения. Если класс доступен, то загружается, иначе вы увидите исключение ClassNotFoundException.

          работа ClassLoader

          Обратитесь к изображению ниже.

          Принцип видимости

          Согласно этому принципу, дочерние классы видны для классов, загруженных их родительскими ClassLoaders, но наоборот не соответствует действительности. Таким образом, классы, загруженные приложением ClassLoader, имеют видимость классов, загруженных расширением и загрузчиком ClassLoader.

          Например, если у нас есть два класса: AB, предположим, что класс A загружается приложением ClassLoader, а класс B загружается расширением ClassLoader. Здесь классы A и B видны всем тем классам, которые загружены приложением ClassLoader, но класс B виден только тем классам, которые загружены расширением ClassLoader.

          Кроме того, если вы попытаетесь загрузить эти классы с помощью загрузчика ClassLoader, вы увидите. исключение.

          Методы

          Вот несколько основных методов ClassLoader:

          • loadClass (имя строки, логическое разрешение);
          • defineClass();
          • findClass (Строковое имя);
          • Class.forName (имя строки, логическая инициализация, загрузчик ClassLoader);
          • GetParent();
          • getResource().

          loadClass (имя строки, логическое разрешение)

          Этот метод является точкой входа ClassLoader и используется для загрузки класса, на который ссылается JVM. Он принимает имя класса в качестве параметра. JVM вызывает метод loadClass() для разрешения ссылок на класс, устанавливая логическое значение true. Только если нам нужно определить, существует ли класс или нет, логический параметр имеет значение false.

          defineClass()

          Последний метод, используемый для определения массива байтов как экземпляра класса. В случае, если класс недопустим, он выдает ClassFormatError.

          findClass (Строковое имя)

          Используется для поиска указанного класса. Таким образом, он просто находит класс с полностью определенным именем в качестве параметра, но не загружает класс. Метод loadClass() вызывает этот метод, если родительский ClassLoader не может найти запрошенный класс. Кроме того, если ни один из родителей ClassLoader не находит класс, реализация по умолчанию генерирует исключение ClassNotFoundException.

          Class.forName (имя строки, логическая инициализация, загрузчик ClassLoader)

          Этот метод используется для загрузки и инициализации класса. Это дает возможность выбрать любой из ClassLoaders и в случае, если параметр ClassLoader равен NULL, тогда автоматически используется Bootstrap ClassLoader.

          GetParent()

          Используется для возврата родительского ClassLoader для делегирования.

          getResource()

          Пытается найти ресурс с заданным именем. Первоначально он делегирует запрос родительскому ClassLoader для ресурса. Если родительский объект имеет значение null, то ищется путь к ClassLoader, встроенному в JVM. Теперь, если это не удается, тогда метод вызовет findResource(String), чтобы найти ресурс, где имя ресурса указывается в качестве входных данных, которые могут быть как абсолютным, так и относительным путем к классу. Затем он возвращает объект URL для чтения ресурса или возвращает нулевое значение, если у ресурса нет достаточных прав для возврата ресурса или он не найден.

          Пользовательский

          Встроенные ClassLoaders позаботятся о большинстве случаев, когда файлы уже находятся в файловой системе, но если вы хотите загрузить классы с локального жесткого диска, вам нужно использовать пользовательские ClassLoaders.

          Чтобы создать собственный ClassLoader, вам нужно расширить класс ClassLoader и переопределить метод findClass():

          Средняя оценка / 5. Количество голосов:

          Спасибо, помогите другим — напишите комментарий, добавьте информации к статье.

          ClassLoader in Java

          The Java ClassLoader is a part of the Java Runtime Environment that dynamically loads Java classes into the Java Virtual Machine. The Java run time system does not need to know about files and file systems because of classloaders.

          Java classes aren’t loaded into memory all at once, but when required by an application. At this point, the Java ClassLoader is called by the JRE and these ClassLoaders load classes into memory dynamically.

          Types of ClassLoaders in Java

          Not all classes are loaded by a single ClassLoader. Depending on the type of class and the path of class, the ClassLoader that loads that particular class is decided. To know the ClassLoader that loads a class the getClassLoader() method is used. All classes are loaded based on their names and if any of these classes are not found then it returns a NoClassDefFoundError or ClassNotFoundException.

          A Java Classloader is of three types:

          1. BootStrap ClassLoader: A Bootstrap Classloader is a Machine code which kickstarts the operation when the JVM calls it. It is not a java class. Its job is to load the first pure Java ClassLoader. Bootstrap ClassLoader loads classes from the location rt.jar. Bootstrap ClassLoader doesn’t have any parent ClassLoaders. It is also called as the Primodial ClassLoader.
          2. Extension ClassLoader: The Extension ClassLoader is a child of Bootstrap ClassLoader and loads the extensions of core java classes from the respective JDK Extension library. It loads files from jre/lib/ext directory or any other directory pointed by the system property java.ext.dirs.
          3. System ClassLoader: An Application ClassLoader is also known as a System ClassLoader. It loads the Application type classes found in the environment variable CLASSPATH, -classpath or -cp command line option. The Application ClassLoader is a child class of Extension ClassLoader.

          Note: The ClassLoader Delegation Hierarchy Model always functions in the order Application ClassLoader->Extension ClassLoader->Bootstrap ClassLoader. The Bootstrap ClassLoader is always given the higher priority, next is Extension ClassLoader and then Application ClassLoader.

          Principles of functionality of a Java ClassLoader

          Principles of functionality are the set of rules or features on which a Java ClassLoader works. There are three principles of functionality, they are:

            Delegation Model: The Java Virtual Machine and the Java ClassLoader use an algorithm called the Delegation Hierarchy Algorithm to Load the classes into the Java file.

          The ClassLoader works based on a set of operations given by the delegation model. They are:

          • ClassLoader always follows the Delegation Hierarchy Principle.
          • Whenever JVM comes across a class, it checks whether that class is already loaded or not.
          • If the Class is already loaded in the method area then the JVM proceeds with execution.
          • If the class is not present in the method area then the JVM asks the Java ClassLoader Sub-System to load that particular class, then ClassLoader sub-system hands over the control to Application ClassLoader.
          • Application ClassLoader then delegates the request to Extension ClassLoader and the Extension ClassLoader in turn delegates the request to Bootstrap ClassLoader.
          • Bootstrap ClassLoader will search in the Bootstrap classpath(JDK/JRE/LIB). If the class is available then it is loaded, if not the request is delegated to Extension ClassLoader.
          • Extension ClassLoader searches for the class in the Extension Classpath(JDK/JRE/LIB/EXT). If the class is available then it is loaded, if not the request is delegated to the Application ClassLoader.
          • Application ClassLoader searches for the class in the Application Classpath. If the class is available then it is loaded, if not then a ClassNotFoundException exception is generated.

          Methods of Java.lang.ClassLoader

          After the JVM requests for the class, a few steps are to be followed in order to load a class. The Classes are loaded as per the delegation model but there are a few important Methods or Functions that play a vital role in loading a Class.

Горин Павел/ автор статьи

Павел Горин — психолог и автор популярных статей о внутреннем мире человека. Он работает с темами самооценки, отношений и личного роста. Его экспертность основана на практическом консультировании и современных психологических подходах.

Понравилась статья? Поделиться с друзьями:
psihologiya-otnosheniy.ru
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: