1. Обзор
Когда мы используем SLF4J в наших приложениях, мы иногда видим предупреждающее сообщение о нескольких привязках в пути к классам, выводимое на консоль.
В этом уроке мы попытаемся понять, почему мы видим это сообщение и как его решить.
2. Понимание предупреждения
Во-первых, давайте посмотрим на пример предупреждения:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:.../slf4j-log4j12-1.7.21.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:.../logback-classic-1.1.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
Это предупреждение сообщает нам, что SLF4J обнаружил две привязки. Один находится в slf4j-log4j12-1.7.21.jar
, а другой — в logback-classic-1.1.7.jar
.
Теперь давайте разберемся, почему мы видим это предупреждение.
Простой фасад ведения журналов для Java (SLF4J) служит простым фасадом или абстракцией для различных сред ведения журналов . Это позволяет нам подключить желаемую структуру ведения журнала во время развертывания.
Для этого SLF4J ищет привязки (так называемые провайдеры) в пути к классам. Привязки — это в основном реализации определенного класса SLF4J, предназначенные для расширения для подключения к определенной структуре ведения журнала.
По замыслу SLF4J будет одновременно связываться только с одной структурой ведения журналов. Следовательно, если в пути к классам присутствует более одной привязки, будет выдано предупреждение.
Стоит отметить, что встроенные компоненты, такие как библиотеки или фреймворки, никогда не должны объявлять зависимость от какой-либо привязки SLF4J. Это связано с тем, что когда библиотека объявляет зависимость времени компиляции от привязки SLF4J, она навязывает эту привязку конечному пользователю. Очевидно, это сводит на нет основную цель SLF4J. Значит, они должны зависеть только от библиотеки slf4j-api
.
Также важно отметить, что это всего лишь предупреждение. Если SLF4J обнаружит несколько привязок, он выберет одну структуру ведения журнала из списка и свяжется с ней. Как видно из последней строки предупреждения, SLF4J выбрал Log4j, используя org.slf4j.impl.Log4jLoggerFactory
для фактической привязки.
3. Поиск конфликтующих JAR-файлов
В предупреждении перечислены местоположения всех найденных привязок. Обычно этой информации достаточно, чтобы идентифицировать недобросовестную зависимость, которая транзитивно подтягивает нежелательную привязку SLF4J в наш проект.
Если невозможно определить зависимость из предупреждения, мы можем использовать цель maven dependency:tree :
mvn dependency:tree
Это отобразит дерево зависимостей для проекта:
[INFO] +- org.docx4j:docx4j:jar:3.3.5:compile
[INFO] | +- org.slf4j:slf4j-log4j12:jar:1.7.21:compile
[INFO] | +- log4j:log4j:jar:1.2.17:compile
[INFO] +- ch.qos.logback:logback-classic:jar:1.1.7:compile
[INFO] +- ch.qos.logback:logback-core:jar:1.1.7:compile
Мы используем Logback для входа в наше приложение. Итак, мы намеренно добавили привязку Logback, присутствующую в JAR-файле logback-classic
. Но зависимость docx4j
также связана с другой привязкой к JAR-файлу slf4j-log4j12
.
4. Разрешение
Теперь, когда мы знаем нарушающую зависимость, нам просто нужно исключить JAR-файл slf4j-log4j12
из зависимости docx4j
:
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j</artifactId>
<version>${docx4j.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
Поскольку мы не собираемся использовать Log4j, было бы неплохо исключить и его.
5. Вывод
В этой статье мы увидели, как мы можем устранить часто встречающееся предупреждение о множественных привязках, выдаваемых SLF4J.
Исходный код, сопровождающий эту статью, доступен на GitHub .