Сумасшедший вопрос ClassLoader - PullRequest
1 голос
/ 18 августа 2010

Классы:

public interface Inter {
  ...some methods...
}

public class Impl implements Inter {
  ...some implementations...
}

Проблема в том, что по какой-то причудливой причине я должен загрузить интерфейс Inter с child ClassLoader и класс реализации Impl с parent ClassLoader.

В этом случае я получу NoClassDefError, потому что родительский ClassLoader, который пытается загрузить реализацию Impl, не знает об интерфейсе Inter, которыйбыл загружен в дочерний ClassLoader.

Есть ли способ загрузить реализацию с дочерним ClassLoader (контекст ClassLoader)?Или, может быть, мне нужно написать какой-то собственный ClassLoader для загрузки их обоих (нарушив правило делегирования)?

Ответы [ 2 ]

3 голосов
/ 18 августа 2010

Проблема в том, что по какой-то причудливой причине я должен загрузить интерфейс Inter с дочерним ClassLoader и класс реализации Impl с родительским ClassLoader.

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

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

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

  • Parent-first : Получить родительский загрузчик классов для загрузки класса первым.Обычно это транзитивное поведение - большинство родительских загрузчиков классов будут откладывать загрузку до своих родителей и т. Д., Пока загрузчик загрузчика классов (корень) не будет достигнут в иерархии загрузчиков классов.Если родительский загрузчик классов не может загрузить класс, дочерний элемент пытается загрузить его.Возможная ошибка при загрузке класса должна привести к возникновению исключения ClassNotFoundException.
  • Parent-last : Пользовательский загрузчик классов сначала пытается загрузить класс, прежде чем делегировать его родителю.Родительские загрузчики классов используются только в том случае, если дочерний процесс не может загрузить класс.

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

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

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

PS: не забывайте использовать AccessController.doPrivileged при загрузке и определении классов.

0 голосов
/ 18 августа 2010

Переопределяете ли вы loadClass (имя строки, логическое разрешение) java.lang.ClassLoader?

Гость, которого вы сделали.

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

...