Skip to content

Latest commit

 

History

History
127 lines (84 loc) · 6.37 KB

File metadata and controls

127 lines (84 loc) · 6.37 KB

Динамическая загрузка классов, ClassLoader

1. Что такое динамическая загрузка классов

Java не загружает сразу все классы приложения при старте. Вместо этого классы подгружаются в память по мере необходимости:

  • когда вы впервые обращаетесь к классу,
  • либо явно через API загрузчиков классов (class loaders).

Зачем это нужно?

  • Экономия памяти (загружаются только реально используемые классы).
  • Возможность подгружать новые классы во время работы программы (плагины, hot reload).
  • Разделение окружений (например, Tomcat изолирует приложения с помощью разных загрузчиков).

2. Как происходит загрузка

Когда JVM встречает новый класс, выполняются три шага:

  1. Loading (загрузка) Класс-файл считывается загрузчиком (ClassLoader) в байт-код.

  2. Linking (связывание)

    • Verify — проверка корректности байткода.
    • Prepare — выделение памяти под статические поля, установка значений по умолчанию.
    • Resolve — связывание ссылок на другие классы.
  3. Initialization (инициализация) Выполнение статических инициализаторов (static { ... }) и присвоение реальных значений статическим полям.


3. Основные загрузчики классов в JVM

В Java загрузчики образуют иерархию с делегированием: если класс не найден у родителя, ищет сам.

A. Bootstrap Class Loader

  • Написан на C, встроен в JVM.
  • Загружает классы стандартной библиотеки Java (rt.jar или java.base в Java 9+).
  • Это не объект класса ClassLoader, а часть JVM.

B. Platform (или Extension) Class Loader

  • Загружает стандартные расширения Java (например, библиотеки из $JAVA_HOME/lib/ext в старых версиях или модули в Java 9+).
  • В Java 9 переименован в Platform ClassLoader.

C. Application (или System) Class Loader

  • Загружает классы приложения из classpath (-cp или CLASSPATH).
  • Это обычный объект Java (sun.misc.Launcher$AppClassLoader или его аналог в новых версиях).

4. Кастомные загрузчики (Custom ClassLoaders)

Вы можете написать свой загрузчик, чтобы:

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

Пример:

class MyClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] bytes = loadClassData(name); // читаем байты откуда угодно
        return defineClass(name, bytes, 0, bytes.length);
    }
}

5. Принцип делегирования (Parent Delegation Model)

  • При загрузке класса ClassLoader сначала спрашивает родителя, загружен ли класс.
  • Если родитель не нашёл, класс загружает сам.
  • Это предотвращает подмену системных классов (java.lang.String) пользовательскими.

Исключение: Некоторые загрузчики (например, в Tomcat, OSGi) частично нарушают эту модель, чтобы позволить загружать свои версии библиотек до системных.


6. Динамическая загрузка во время выполнения

JVM позволяет загружать классы явно:

Class<?> cls = Class.forName("com.example.MyClass");
Object obj = cls.getDeclaredConstructor().newInstance();

или

ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?> cls = loader.loadClass("com.example.MyClass");

Разница:

  • Class.forName() сразу инициализирует класс (выполняет static-блоки).
  • loadClass() только загружает, без инициализации — до первого обращения.

7. Где используется динамическая загрузка

  • Сервлет-контейнеры (Tomcat, Jetty) — изолируют приложения.
  • Spring / Hibernate — загружают классы через context class loader.
  • OSGi / JPMS (Java 9+) — модульные системы.
  • Плагины / скрипты — динамическое подключение новых модулей.

📌 Кратко для собеседования

Классы загружаются динамически по мере использования. За это отвечает иерархия загрузчиков: Bootstrap → Platform → Application. По умолчанию используется модель делегирования — сначала родитель, потом свой код. Классы можно загружать явно через Class.forName() или ClassLoader.loadClass(), а при необходимости писать собственные загрузчики, например для плагинов или горячей подгрузки кода.