Вход со встроенной пристанью и гобеленом
У меня есть веб-приложение войны, которое использует каркас Tapestry. Он использует slf4j + log4j и работает хорошо.
У меня также есть простое серверное приложение со встроенным Jetty 8, которое я использую для развертывания войны.
Я хотел бы также использовать slf4j + log4j на сервере.
Поэтому я добавляю зависимость slf4j и log4j на мой сервер pom.xml:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Я получил:
SLF4J: Class path contains multiple SLF4J bindings.<br/>
SLF4J: Found binding in [jar:file:/tmp/jetty-0.0.0.0-8080-web-app-0.0.1.war-_-any-/webapp WEB-INF/lib/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/home/martin/monitoring-gui/trunk/release/target/release-0.0.1-webgui-distribution/release-0.0.1/lib/slf4j-log4j12-1.7.5.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-log4j12
а также log4j
, Поэтому я добавляю следующее в мой webapp pom.xml tapestry-core
раздел:
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
Теперь фактическая привязка и логгер должны присутствовать только в приложении сервера. Однако при запуске сервера я получаю:
Exception in thread "main" java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/eclipse/jetty/webapp/WebAppClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for resolved class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type taticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory; used in the signature
at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:299)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:269)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:281)
at org.apache.tapestry5.TapestryFilter.<init>(TapestryFilter.java:56)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at java.lang.Class.newInstance(Class.java:374)
at org.eclipse.jetty.servlet.ServletContextHandler$Context.createFilter(ServletContextHandler.java:1051)
at org.eclipse.jetty.servlet.FilterHolder.doStart(FilterHolder.java:104)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64)
at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:763)
at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:265)
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1242)
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:717)
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:494)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64)
at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:95)
at org.eclipse.jetty.server.Server.doStart(Server.java:282)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64)
...
пройти весь путь до моего вызова Jetty Server.start();
Что мне не хватает?
3 ответа
Хорошо, спасибо за помощь joostschouten и user2424794. У меня это работает.mvn dependency:tree
показал, что зависимость другого веб-приложения: qpid-client
импортировал другой slf4j-api
на войну.
Поэтому было необходимо другое исключение:
<dependency>
<groupId>org.apache.qpid</groupId>
<artifactId>qpid-client</artifactId>
<version>0.22</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
Для записи, зависимость ядра от гобелена:
<dependency>
<groupId>org.apache.tapestry</groupId>
<artifactId>tapestry-core</artifactId>
<version>${tapestry-release-version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
Единственная оставшаяся проблема заключается в том, что война не будет компилироваться без slf4j-api, поэтому я добавляю ее как военную зависимость для компиляции, а не для компоновки - maven's provided
объем:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
<scope>provided</scope>
</dependency>
Конечно, slf4j-api
, slf4j-log4j12
а также log4j
добавляются в качестве зависимостей для сервера, который "предоставляет" его приложению war.
Теперь все компилируется, запускается и регистрируется просто отлично.
У вас проблема с зависимостями. Вместо того, чтобы постоянно использовать исключение, я вижу дерево зависимостей и переупорядочиваю теги внутри pom.xml. Правило здесь гласит, что первое появление зависимости выигрывает. Поэтому, если вы хотите, чтобы унаследованная зависимость была опущена другой, просто переместите тег зависимости, прежде чем тот, который вы хотите, чтобы унаследованная зависимость была исключена.
Это делает pom более читабельным, а также контролирует, какая версия зависимостей в деревьях используется. Только в редких случаях я должен использовать тег.
Проблема в том, что у вас есть две версии slf4j-log4j12 на вашем пути к классам. Судя по всему, вы исключаете более позднюю версию вместо более старой. Slf4j жалуется на то, что ожидает более новую версию, чем та, которую он находит.
Мне кажется, что версия 1.6.1 делает это на вашем classpath через ваш встроенный джет-сервер. Вы также настроили свою зависимость от пристани через Maven? Если так, добавьте исключение к своей зависимости от молы. В любом случае, вам нужно проверить ваш путь к классу и разрешить конфликтующие версии тем или иным способом.