How to Resolve Java Logging Framework Conflicts in SpringBoot & Dubbo
This article explains why multiple Java logging frameworks often clash in SpringBoot and Dubbo projects, outlines the root causes such as transitive dependencies and duplicate versions, and provides step‑by‑step Maven configurations and adaptation techniques to unify logging under a single implementation.
Preface
Have you ever configured logging but saw no output? Encountered Logback errors at startup, or SLF4J warnings about multiple bindings? Issues with Dubbo, MyBatis, JPA/Hibernate, Tomcat, or SpringBoot logs appearing in multiple files are often caused by conflicting logging frameworks.
Logging Framework Conflicts
These problems usually stem from having several logging frameworks coexist or from misconfiguration. Common reasons include:
Manually adding multiple logging libraries (log4j, log4j2, logback, jboss‑logging, jcl, etc.)
Transitive dependencies that pull in additional logging jars (e.g., Dubbo → zkclient → log4j)
Multiple versions of the same logging framework
Java Logging Frameworks
Java logging consists of two layers: abstraction (facade) and implementation.
Abstraction / Facade
Facades define a common API (Logger, Level) but do not handle actual output. The most popular are SLF4J and JCL ; JBoss‑Logging is mainly used by JBoss‑related projects such as Hibernate.
Implementations
Common implementations are:
log4j (legacy, superseded by log4j2)
log4j2 (newer, high‑performance, simple configuration)
logback (the native SLF4J implementation)
java.util.logging (JUL, built into the JDK)
Typically developers combine a facade (e.g., SLF4J) with one concrete implementation.
SpringBoot + Dubbo Logging Conflict Example
The most common issue is a transitive dependency that introduces an unwanted logging framework.
Consider a clean SpringBoot project that adds Dubbo with Zookeeper:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.9</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>2.7.9</version>
</dependency>
</dependencies>Running the application produces errors such as:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/.../logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/.../slf4j-log4j12-1.7.30.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
---
log4j:WARN No appenders could be found for logger (org.apache.dubbo.common.logger.LoggerFactory).
log4j:WARN Please initialize the log4j system properly.The first part reports multiple SLF4J bindings; the second part warns that Log4j has no configured appender. The root cause is that Dubbo brings in Log4j (via transitive dependencies) while SpringBoot defaults to SLF4J + Logback.
Because both Logback and Log4j‑related bridges are present, the classloader loads the first SLF4J implementation it finds, leading to unpredictable behavior.
Resolving the Conflict
Unify the logging stack by choosing a single implementation (e.g., Logback) and adapting the other frameworks.
1. Exclude Log4j from Dubbo dependencies and add log4j-over-slf4j to route Log4j API calls through SLF4J:
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>2.7.9</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.30</version>
</dependency>2. Remove the unwanted SLF4J binding (e.g., slf4j-log4j12) so that only Logback remains:
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>2.7.9</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>After these changes, the application starts without logging errors, and all frameworks log through the single chosen implementation.
Logging Adaptation Overview
Various adapters exist to convert one logging API to another. The following diagram (click to enlarge) shows the most comprehensive mapping of Java logging frameworks and the required bridge libraries.
For example, to route SLF4J calls to Log4j2, add log4j-slf4j-impl. To adapt JCL to SLF4J, replace JCL with jcl-over-slf4j. Some arrows in the diagram indicate that an extra bridge jar is needed, while others represent built‑in support.
Conclusion
Resolving logging framework conflicts is straightforward if you follow these principles:
Use a single logging implementation across the project.
Remove unnecessary logging dependencies.
If coexistence is required, replace the original library with an “‑over‑” bridge that re‑exports the API but delegates to the chosen implementation.
When a bridge is not available, configure the provider (e.g., JBoss‑Logging) via environment variables or system properties.
Once the logging stack is unified, all logs flow through the selected framework, eliminating missing or misconfigured log output and allowing developers to finish work on time.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Interview Crash Guide
Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
