Загрузчики классов Java: зачем сначала искать родительский загрузчик классов? - PullRequest
16 голосов
/ 13 апреля 2011

Правильное поведение для загрузчика классов в Java:

  1. Если он уже был загружен, вернуть класс
  2. Вызовите родительский loadClass ()
  3. Попробуйте загрузить сам класс.

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

Насколько я понимаю, это по двум причинам:

  1. Во избежание проблем с использованием разных версий классов. Представьте, что я переопределил java.lang. Объект на войне, это был бы кошмар.
  2. Чтобы избежать зависимостей от дочерних загрузчиков классов: системный загрузчик классов не может зависеть от дочерних загрузчиков классов: например, будет трудно повторно развернуть войну.

Итак, вопрос в следующем:

В дополнение к вышеупомянутым проблемам, есть ли другие ловушки для реализации загрузчика классов, который сначала не выполняет родительский поиск?

Ответы [ 6 ]

14 голосов
/ 13 апреля 2011

Tomcat сначала не ищет родительский загрузчик классов. На самом деле это происходит наоборот: сначала он просматривает веб-приложение, а затем переходит к родительскому загрузчику классов (это «lib» для Tomcat 6/7 и «shared» для Tomcat 5.5). Исключением из этого правила являются системные классы (я думаю, что все, что имеет пакет java. * И javax. *), Эти классы просматривались только в системном загрузчике классов. Я считаю, что причина, по которой они это делают, - причина № 1, которую вы указали.

Так что, в принципе, можно реализовать стратегию «сначала родитель». Это также нормально для реализации parent-last. Обе стратегии имеют свои плюсы и минусы.

Я приведу еще одну причину, по которой нужно реализовать родительский план: вы уменьшаете количество классов, загружаемых в пермскую память. Представьте, что у вас есть несколько веб-приложений, использующих одну и ту же библиотеку. С parent-first библиотека может быть загружена один раз. С parent-last он будет загружен несколько раз.
Тем не менее, для parent-first все веб-приложения должны будут использовать одну и ту же версию библиотеки, а для parent-last они могут использовать разные версии.

3 голосов
/ 13 апреля 2011

Единственная причина, по которой я могу придумать, - убедиться, что путь к классам работает так, как ожидалось. Выполняя поиск родителя, вы фактически помещаете classpath родителя (то есть системный classpath) перед дочерним classpath. Так что, если вы укажете конкретные jar-файлы при запуске jvm с помощью -cp, они будут «затенять» любые jar-файлы, которые вы включили в любой архив, который вы пытаетесь загрузить. Если вы сначала не проверяете родителя, то путь к дочернему классу будет затенять родителя.

3 голосов
/ 13 апреля 2011

Не совсем.На самом деле это так же просто, как создание экземпляра URLClassLoader и предоставление ему null для родителя:

myClassLoader = new URLClassLoader(myUrlArray, null);

http://download.oracle.com/javase/6/docs/api/java/net/URLClassLoader.html

2 голосов
/ 13 апреля 2011

Tarlog правильный, вам не нужно делать это таким образом.В Java не было такого варианта использования, как tomcat.

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

0 голосов
/ 12 января 2019

Загрузчик классов веб-приложений Tomcat не подчиняется «сначала используйте родителя».Как упомянуто в docs :

Как упоминалось выше, загрузчик классов веб-приложений отличается от модели делегирования Java по умолчанию (в соответствии с рекомендациями в спецификации сервлета, версия 2.4,раздел 9.7.2 веб-приложения Classloader).Когда обрабатывается запрос на загрузку класса из загрузчика классов WebappX веб-приложения, этот загрузчик классов сначала просматривает локальные репозитории, а не делегирует их перед поиском.Есть исключения.Классы, которые являются частью базовых классов JRE, не могут быть переопределены.

0 голосов
/ 13 апреля 2011

Если вы вообще не будете искать своего родителя, вы потеряете доступ ко всем стандартным Java-объектам и, скорее всего, вообще не сможете работать.

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

JVM этого не делает, потому что поиск вашего родителя в первую очередь имеет смысл. Если вы знаете, что делаете, вы можете делать довольно интересные вещи с загрузчиками классов. Взгляните на Classworlds .

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