Java, Classpath, Classloading => Несколько версий одного и того же JAR / проекта

java jar classpath classloader

79490 просмотра

5 ответа

Я знаю, что это может быть глупый вопрос для опытных программистов. Но у меня есть библиотека (клиент http), которая требуется для некоторых других фреймворков / jar-файлов, используемых в моем проекте. Но все они требуют разных основных версий, таких как:

httpclient-v1.jar => Required by cralwer.jar
httpclient-v2.jar => Required by restapi.jar
httpclient-v3.jar => required by foobar.jar

Является ли загрузчик классов достаточно умным, чтобы как-то их разделить? Скорее всего нет? Как Classloader справляется с этим, если класс одинаков во всех трех банках. Какой из них загружен и почему?

Classloader подхватывает только один jar или он смешивает классы произвольно? Так, например, если класс загружен из Version-1.jar, все другие классы, загруженные из того же загрузчика классов, все попадут в тот же самый jar?

Как вы справляетесь с этой проблемой?

Есть ли какая-то хитрость, чтобы каким-то образом «включить» банки в «required.jar», чтобы они рассматривались как «одна единица / пакет» Classloaderили как-то связаны?

Автор: jens Источник Размещён: 12.11.2019 09:03

Ответы (5)


54 плюса

Решение

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

  • Загрузчики классов в приложении обычно больше, чем один. Загрузчик класса загрузчика делегирует соответствующий. Когда вы создаете новый класс, вызывается более специфический загрузчик классов. Если он не находит ссылку на класс, который вы пытаетесь загрузить, он делегирует его родителю и т. Д., Пока вы не попадете в загрузчик класса начальной загрузки. Если ни один из них не находит ссылку на класс, который вы пытаетесь загрузить, вы получаете ClassNotFoundException.

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

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

Я могу найти способ загрузки двух классов с одинаковыми двоичными именами, и он предполагает их загрузку (и все их зависимости) с помощью двух разных загрузчиков классов, переопределяющих поведение по умолчанию. Грубый пример:

    ClassLoader loaderA = new MyClassLoader(libPathOne);
    ClassLoader loaderB = new MyClassLoader(libPathTwo);
    Object1 obj1 = loaderA.loadClass("first.class.binary.name", true)
    Object2 obj2 = loaderB.loadClass("second.class.binary.name", true);

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

Автор: Luca Putzu Размещён: 24.05.2011 09:07

20 плюса

Каждый класс выбирает ровно один класс. Обычно первый найден.

OSGi стремится решить проблему нескольких версий одной и той же банки. Equinox и Apache Felix являются общими реализациями с открытым исходным кодом для OSGi.

Автор: Tarlog Размещён: 24.05.2011 08:15

6 плюса

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

Автор: Alex Gitelman Размещён: 24.05.2011 02:42

6 плюса

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

Вы, вероятно, столкнетесь LinkageErrorс сообщением о том, что для загрузчиков классов встречаются повторяющиеся определения классов, которые обычно не пытаются определить, какой класс должен быть загружен первым (если в пути к классам загрузчика присутствуют два или более классов с одинаковым именем). Иногда загрузчик классов загружает первый класс, встречающийся в пути к классам, и игнорирует дублирующиеся классы, но это зависит от реализации загрузчика.

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

Автор: Vineet Reynolds Размещён: 24.05.2011 03:13

0 плюса

Вы можете использовать команду URLClassLoaderfor require для загрузки классов из версии jar diff-2:

URLClassLoader loader1 = new URLClassLoader(new URL[] {new File("httpclient-v1.jar").toURL()}, Thread.currentThread().getContextClassLoader());
URLClassLoader loader2 = new URLClassLoader(new URL[] {new File("httpclient-v2.jar").toURL()}, Thread.currentThread().getContextClassLoader());

Class<?> c1 = loader1.loadClass("com.abc.Hello");

Class<?> c2 = loader2.loadClass("com.abc.Hello");

BaseInterface i1 = (BaseInterface) c1.newInstance();

BaseInterface i2 = (BaseInterface) c2.newInstance();
Автор: Pankaj Kalra Размещён: 24.04.2019 05:21
Вопросы из категории :
32x32