Java classloaders: зачем сначала искать родительский загрузчик классов?
Правильное поведение для загрузчика классов в Java:
- Если он уже загружен, верните класс
- Вызвать родительский loadClass()
- Попробуйте загрузить сам класс.
Таким образом, класс, определенный в пути к системе, всегда должен загружаться первым. Tomcat определяет загрузчик классов для каждой войны, у которого есть системный загрузчик классов как родительский, поэтому, если вы попытаетесь загрузить класс, он сначала рассмотрит путь к системному классу, а затем в пути к классам, определенном в военном файле.
По моему пониманию, это происходит по двум причинам:
- Чтобы избежать проблем с различными версиями используемых классов. Представьте, что я переопределил java.lang.Object в войне, это был бы кошмар.
- Чтобы избежать зависимостей от дочерних загрузчиков классов: системный загрузчик классов не может зависеть от дочерних загрузчиков классов: например, было бы трудно переустановить войну.
Итак, вопрос:
В дополнение к вышеуказанным проблемам есть ли какие-либо другие проблемы для реализации загрузчика классов, который сначала не выполняет родительский поиск?
Ответы
Ответ 1
Tomcat сначала не ищет родительский загрузчик классов. На самом деле все делается наоборот: сначала он просматривается в webapp и только потом переходит к родительскому загрузчику классов (который является "lib" для Tomcat 6/7 и "shared" для Tomcat 5.5). Исключением для этого правила являются системные классы (я думаю, что все, что имеет пакет java. * И javax. *), Эти классы рассматривались только в системном загрузчике классов. Я верю, что причина, по которой они это делают, - это причина №1, которую вы заявили.
Так что в принципе это нормально, чтобы реализовать родительскую стратегию. Также нормально реализовать parent-last. Обе стратегии имеют свои минусы и плюсы.
Я дам вам еще одну причину, почему для реализации parent-first: вы уменьшаете количество классов, загружаемых в пермскую память. Представьте, что у вас несколько веб-приложений, использующих одну и ту же библиотеку. С родительским - сначала библиотека, которая будет загружена один раз. С parent-last он будет загружен несколько раз.
Тем не менее, с родительским - сначала все веб-приложения будут обязаны использовать одну и ту же версию библиотеки, а с родительским - последним они могут использовать разные версии.
Ответ 2
Не совсем. На самом деле это так же просто, как создание экземпляра URLClassLoader
и предоставление ему null
для родителя:
myClassLoader = new URLClassLoader(myUrlArray, null);
http://download.oracle.com/javase/6/docs/api/java/net/URLClassLoader.html
Ответ 3
Единственная причина, по которой я могу думать, это убедиться, что путь к классам работает так, как ожидалось. При первом поиске родителя вы фактически помещаете родительский путь к классам (то есть системный путь к классам) до дочернего пути к классам. Поэтому, если вы укажете конкретные банки при запуске jvm с помощью -cp, они будут "затенять" любые банки, которые вы включили в любой архив, который вы пытаетесь загрузить. Если вы сначала не проверите родителя, тогда путь дочернего класса будет теневым родителем.
Ответ 4
Тарлог правильный, вам не нужно так поступать. Java не предполагал использовать случай, например tomcat.
Однако вызывает сомнения, почему контейнеры размещают несколько приложений в одной виртуальной машине. Отдельные процессы приятнее.
Ответ 5
Если вы вообще не ищете своего родителя, вы потеряете доступ ко всем стандартным объектам Java и, вероятно, не сможете вообще запускать.
Но разумно сначала искать свой загрузчик классов, прежде чем пытаться родитель. Если вы хотите переопределить поведение, которое вы предлагаете выше, вам нужно будет сделать это таким образом.
JVM не делает этого, потому что поиск вашего родителя в первую очередь имеет смысл. Если вы знаете, что вы делаете, вы можете сделать довольно интересный материал с загрузчиками классов. Посмотрите Classworlds.
Ответ 6
Загрузчик классов веб-приложений Tomcat не подчиняется "сначала используйте родителя". Как упомянуто в документах:
Как упомянуто выше, загрузчик классов веб-приложений отличается от модели делегирования Java по умолчанию (в соответствии с рекомендациями в спецификации сервлета, версия 2.4, раздел 9.7.2 Загрузчик классов веб-приложений). При обработке запроса на загрузку класса из загрузчика классов WebappX веб-приложения этот загрузчик классов сначала просматривает локальные репозитории, а не делегирует их перед поиском. Есть исключения. Классы, которые являются частью базовых классов JRE, не могут быть переопределены.