В работе, особенно при реализации промежуточного ПО, часто встречаются конфликты пакетов jar.В этой статье будут проанализированы существующие в отрасли решения по изоляции пакетов jar.
1. Суть конфликта пакетов jar
По какой-то причине приложение Java не загружает правильные классы и ведет себя не так, как ожидалось.
2. Два случая конфликта пакетов jar
Первый тип проблемы конфликта пакетов jar (разные версии одного и того же пакета jar)
- Существует несколько версий одного и того же пакета Jar, от которого зависит приложение, и выбрана неправильная версия, из-за чего JVM не загружает требуемые классы или загружает неправильную версию класса.
- Для возникновения этой проблемы есть три необходимых условия:
- Несколько версий одного и того же jar-файла отображаются в дереве зависимостей.
- Интерфейс изменился между несколькими версиями пакета jar (имя класса, изменение подписи метода, изменение поведения метода).
- механизм арбитража maven выбирает неправильную версию
Второй тип проблемы конфликта пакетов jar (разные пакеты jar имеют разные версии одного и того же класса)
- Один и тот же класс (полное имя класса точно такое же) появляется в нескольких различных зависимых пакетах Jar, то есть существует несколько версий класса, и из-за порядка, в котором загружаются пакеты Jar (самый короткий Maven принцип приоритета пути и покрытия) JVM загрузила неправильную версию класса. Например: предположим, что естьA,B,CДля трех пакетов jar из-за длины пути, от которого зависит пакет Jar, порядка объявлений или порядка загрузки файлов файловой системы, загрузчик классов сначала запускается из пакета Jar.AПосле того, как класс загружен в jar, класс в остальных пакетах jar не будет загружен.
- Для возникновения этой проблемы есть три необходимых условия:
- Один и тот же класс M присутствует в двух (или более двух) разных упаковках банок A и B.
- Класс M имеет отличия от A и B и ведет себя по-разному.
- Загруженный класс M — это не то, что нам нужно.
3. Решения
Способ 1: ручное расследование
- Определите имя класса, вызвавшего конфликт, на основе информации о стеке исключений.
- Используйте mvn dependency:tree -Dverbose -Dincludes=
: , чтобы увидеть, где была введена версия пакета jar. - Если это первый тип конфликта пакетов Jar, вы можете использовать
для исключения нежелательных версий пакетов Jar или объявить версию в управлении зависимостями . - Если это второй тип конфликта пакетов Jar, если его можно исключить, используйте<excludes>Удалите ненужный пакет Jar. Если его нельзя слить, подумайте об обновлении пакета Jar или замените его отдельным пакетом Jar.
Способ 2: реализовать изоляцию с помощью пользовательского ClassLoaderв блогеРеализация изолированных контейнеров в JavaУпоминается, что каждый пакет jar рассматривается как несколько пакетов, выполняется изолированно через настраиваемый загрузчик классов, а также может понимать, что несколько пакетов jar имеют общий класс. Демо запускается путем запуска класса KContainer, который в основном содержит BundleList и SharedClassList. Каждый Bundle представляет собой пакет jar или путь к классу. Класс Bundle содержит собственный класс BundleClassLoader (наследующий UrlClassLoader). Из-за разных BundleBundleClassLoader его можно реализоватьработать в изоляции, и этот BundleClassLoader должен пройти в SharedClassList.Когда загрузчик классов загружает класс, если он не загружен, он может быть загружен из SharedClassList, переданного извне, что достигаетсяНесколько пакетов jar имеют общий класс.
protected Class<?> findClass(String name) throws ClassNotFoundException {
logger.debug(“try find class {}”, name);
Class<?> claz = null;
try {
claz = super.findClass(name);
} catch (ClassNotFoundException e) {
claz = null;
}
if (claz != null) {
logger.debug(“load from class path for {}”, name);
return claz;
}
//如果没有加载到,从共享的类中加载
claz = sharedClasses.get(name);
if (claz != null) {
logger.debug(“load from shared class for {}”, name);
return claz;
}
logger.warn(“not found class {}”, name);
throw new ClassNotFoundException(name);
}
Классы, которые должны быть общими для других, могут быть указаны через файл свойств в пути к классам и загружены в SharedClassList при загрузке loadBundle.
Способ 3: Легкий изолированный контейнер SOFAArkSOFAArk также использует разные загрузчики классов для загрузки конфликтующих сторонних зависимостей, чтобы они могли сосуществовать при запуске одного и того же приложения.SOFAArk различает, какие зависимые пакеты в приложении должны быть загружены отдельным загрузчиком классов через плагин Ark.. С подключаемым модулем упаковки maven, официально предоставляемым SOFABoot, разработчики могут упаковывать несколько распространенных пакетов JAR в подключаемый модуль Ark для зависимостей приложений или преобразовывать обычные модули Java в подключаемый модуль Ark. Приложение вводит подключаемый модуль Ark, добавляя зависимости maven.Во время выполнения платформа SOFAArk автоматически определяет, содержит ли сторонний пакет зависимостей приложения подключаемый модуль Ark, а затем использует отдельный загрузчик классов для его загрузки. Его логическая схема времени выполнения выглядит следующим образом:
- Контейнер SOFAARk находится внизу и отвечает за запуск приложений.
- Каждый плагин Ark загружается контейнером SOFAArk с использованием независимого загрузчика классов, изолированных друг от друга.
- Бизнес-код приложения и другие распространенные сторонние пакеты зависимостей, отличные от Ark Plugin, вместе именуются Ark Biz. Нужно полагаться на нижний плагин Ark.
В файле POM плагина Ark будет настроена конфигурация экспортируемых и импортируемых классов. Экспорт классов означает экспорт классов в плагине Ark, чтобы они были видны в Ark Biz и других плагинах Ark. Для плагина Ark, если вам нужно использовать экспортированный класс другого плагина Ark, он должен быть объявлен как собственный класс импорта.
Метод 4: Изолирующий контейнер Пандоры АлиPandora Али имеет закрытый исходный код, и в Интернете относительно мало информации. Из PPT выступления Али можно узнать, что Pandora по-прежнему основана на недостатках изолированных контейнеров, таких как Pandora, реализованных ClassLoader:
- Использование сложное и трудное для понимания.
- Медленный запуск, пользователи не могут выбирать по требованию
- Сложность отладки
- Сложность развертывания и эксплуатации
Следующая статья будет посвящена использованию контейнера Ant Financial SOFA-ARK и анализу исходного кода.