I have a war web application which is using Tapestry framework. It uses slf4j + log4j and works well.

I also have a simple server application with embedded jetty 8 which I am using to deploy the war.

I would like to use slf4j + log4j in the server as well.

Therefore I add the slf4j and log4j dependency to my server 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>

I get:

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]

Fair enough, Tapestry dependency automatically includes slf4j-log4j12 and log4j. So I add following to my webapp pom.xml tapestry-core section:

<exclusions>  
    <exclusion>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
    </exclusion>

    <exclusion>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
    </exclusion>
</exclusions>

Now, the actual binding and logger should only be present in the server application. However upon server start I get:

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)
...

going all the way to my jetty Server.start() call;

What am I missing?

有帮助吗?

解决方案 3

Alright, thanks for help joostschouten and user2424794. I've got it working.

The mvn dependency:tree revealed, that other web app's dependency: qpid-client imported another slf4j-api to the war.
So another exclusion was necessary:

<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>

For the record, the tapestry-core 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>

The only problem left is that the war wouldn't compile without the slf4j-api, therefore I add it as war dependency for the compilation, not for the linking - maven's provided scope:

<dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-api</artifactId>
     <version>1.7.5</version>
     <scope>provided</scope>
</dependency>

Of course, the slf4j-api , slf4j-log4j12 and log4j are added as dependencies for the server, which 'provides' it to the war application.

Now everything compiles, runs and logs just fine.

其他提示

You have a dependency problem. Instead of using exclusion all the time I see the dependency tree and reorder the tags inside pom.xml. The rule here seams that the first appearance of the dependency wins. So when you want that a inherited dependency is omitted by another one, just move the dependency tag before the one you want the inherited dependency omitted.

That makes the pom more readable and also controls which version of the dependencies in the trees are used. In only rare cases I have to use the tag.

The problem is that you have two versions of slf4j-log4j12 on your classpath. By the looks of it you are managing to exclude the later version in stead of the older one. Slf4j is complaining about the fact it is expecting a newer version than the one it is finding.

It seems to me that the 1.6.1 version makes it onto your classpath though your embedded jetty server. Have you setup your jetty dependency through maven as well? If so, add the exclude to your jetty dependency too. Either way, you need to inspect your classpath and resolve the conflicting versions one way or the other

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top