Проблемы с использованием log4j в затененной банке
У меня следующая ситуация в моем проекте:
большой модуль (называемый конвертером) со своими собственными зависимостями интегрируется в основное приложение (которое было разработано разными людьми отдельно и имеет свои, частично перекрывающиеся, зависимости);
первоначально этот модуль преобразователя можно было вызывать из командной строки как исполняемый файл jar, поэтому он имеет свои собственные точки входа (выполняемые классы с определенными методами main()); этот исполняемый jar всегда создавался как uber-jar с помощью плагина maven shade;
теперь этот модуль преобразователя должен дополнительно вызываться из основного приложения (для этого я сейчас вызываю напрямую main() классов точки входа после формирования аргументов командной строки). Основное приложение также было создано как uber-jar и планируется продолжать создавать таким же образом.
Таким образом, я собираюсь добиться правильного разделения зависимостей, используя плагин Shade для этого случая, для этого я добавил следующие спецификации перемещения в pom.xml для модуля преобразователя:
<relocations>
<relocation>
<pattern>com</pattern>
<shadedPattern>quase.com</shadedPattern>
</relocation>
<!-- ... other top-level patterns for converter dependencies -->
<relocation>
<pattern>org</pattern>
<shadedPattern>quase.org</shadedPattern>
<excludes>
<exclude>org.aau.**</exclude> <!-- my own code for converter is not shaded -->
</excludes>
</relocation>
</relocations>
В результате все зависимости модуля преобразователя заштрихованы (с предваряющей квазой) к ним, в то время как объединены в супер-jar основного приложения.
Проблема с этой конфигурацией состоит в том, что и приложение, и преобразователь используют ведение журнала (slf4j с log4j), и после вызова метода преобразователя из кода приложения и начала использования ведения журнала возникает следующая ошибка:
log4j:ERROR A "org.apache.log4j.FileAppender" object is not assignable to a "quase.org.apache.log4j.Appender" variable.
log4j:ERROR The class "quase.org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.FileAppender" was loaded by [sun.misc.Launcher$AppClassLoader@55f96302].
log4j:ERROR Could not instantiate appender named "file1".
log4j:ERROR A "org.apache.log4j.FileAppender" object is not assignable to a "quase.org.apache.log4j.Appender" variable.
log4j:ERROR The class "quase.org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.FileAppender" was loaded by [sun.misc.Launcher$AppClassLoader@55f96302].
log4j:ERROR Could not instantiate appender named "file2".
log4j:ERROR A "org.apache.log4j.ConsoleAppender" object is not assignable to a "quase.org.apache.log4j.Appender" variable.
log4j:ERROR The class "quase.org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.ConsoleAppender" was loaded by [sun.misc.Launcher$AppClassLoader@55f96302].
log4j:ERROR Could not instantiate appender named "console".
log4j:WARN No appenders could be found for logger (org.aau.quase.quontology.builder.QuLogHandler).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Поэтому мне кажется, что заштрихованный код журнала, вызываемый из модуля преобразователя, получает ссылку на незатененный код журнала, уже инициализированный в основном приложении, и завершается неудачно, поскольку ожидает затененный код (см. Ошибку назначения незатененного кода). org.apache.log4j.FileAppender
в тени quase.org.apache.log4j.Appender
).
Я попытался исключить зависимости журналирования от затенения в pom.xml конвертера:
<excludes>
<exclude>org.aau.**</exclude>
<exclude>org.apache.log4j.**</exclude>
<exclude>org.slf4j.**</exclude>
</excludes>
но это привело к дальнейшим проблемам: все приложение не работает следующим образом:
Exception in thread "main" java.lang.NoClassDefFoundError
at org.apache.log4j.Category.class$(Category.java:118)
at org.apache.log4j.Category.<clinit>(Category.java:118)
at org.apache.log4j.LogManager.<clinit>(LogManager.java:82)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:66)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:277)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:288)
at org.aau.quase.application.LoggingProtocolHandler.<clinit>(LoggingProtocolHandler.java:16)
at org.aau.quase.application.QuASEApplication$1.<init>(QuASEApplication.java:71)
at org.aau.quase.application.QuASEApplication.<init>(QuASEApplication.java:65)
at org.aau.quase.application.util.QuASERunner.main(QuASERunner.java:8)
Caused by: java.lang.ClassNotFoundException: quase/org.apache.log4j.Category
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
... 10 more
Похоже, код конвертера все еще ожидает затененную версию, так как не может найти quase/org.apache.log4j.Category
и quase - это префикс затенения.
Что я делаю неправильно? Любая помощь с благодарностью.
1 ответ
Мы столкнулись с той же проблемой, и мы исправили ее, исключив log4j из самого корня, а не переместив их.
<configuration>
<filters>
<filter>
<artifact>groupId:artifactId:*</artifact>
<excludes><exclude>org/apache/log4j/**</exclude></excludes>
</filter>
</filters>
<relocations>
<relocation>
<pattern>com</pattern>
<shadedPattern>xyz.shaded.com</shadedPattern>
</relocation>
</relocations>
</configuration>