Вопрос-ответ

Java, Classpath, Classloading => Multiple Versions of the same jar/project

Java, Classpath, загрузка классов => Несколько версий одного jar / проекта

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

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

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

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

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

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

Переведено автоматически
Ответ 1

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


  • Загрузчиков классов в приложении обычно больше, чем один. Загрузчик классов bootstrap делегирует соответствующему. При создании экземпляра нового класса вызывается более конкретный загрузчик классов. Если он не находит ссылку на класс, который вы пытаетесь загрузить, он делегирует его родительскому, и так далее, пока вы не доберетесь до загрузчика классов bootstrap. Если ни одна из них не находит ссылку на класс, который вы пытаетесь загрузить, вы получаете 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);

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

Ответ 2

При каждой загрузке классов выбирается ровно один класс. Обычно первый найденный.

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

Ответ 3

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

Ответ 4

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

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

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

2023-09-24 21:31 java jar