Standard Commons Logging discovery in action with spring-jcl
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
spring-jcl is Spring's replacement bridge for the Commons Logging API. It keeps the familiar org.apache.commons.logging.Log and LogFactory surface, but the discovery behavior is optimized for Spring's supported logging backends rather than following the older full Commons Logging discovery story.
What Standard Commons Logging Discovery Tries to Do
Classic Commons Logging was designed as a logging facade. Application code calls the Commons Logging API, and the library tries to discover a concrete logging implementation at runtime by inspecting the classpath.
At the call site, the code is simple:
The idea is that the application code does not commit directly to Log4J, SLF4J, or java.util.logging. Instead, discovery selects a backend based on what jars are present.
That flexibility was useful, but the original Commons Logging implementation was also known for classloader surprises and bridge conflicts in some container environments. This is exactly the kind of problem Spring wanted to smooth out.
What spring-jcl Changes
Spring ships spring-jcl as its own Commons Logging bridge. According to the Spring Framework API docs, it is a custom bridge with special support for Log4J 2, SLF4J, and java.util.logging, and it uses a minimized LogFactory implementation tailored for Spring.
In practical terms, that means:
- Spring code can keep using the Commons Logging API
- backend detection is simpler and more predictable
- common Spring logging setups work without adding extra JCL bridge jars
So when people talk about "Commons Logging discovery with Spring," the important nuance is that modern Spring applications usually are not using the original commons-logging artifact directly. They are using Spring's bridge layer instead.
How It Behaves in a Spring Application
In a typical Spring Boot application, you usually do not configure spring-jcl directly. It arrives transitively with the Spring framework jars, and the effective backend is then determined by the logging implementation on the classpath.
If SLF4J and Logback are present through Spring Boot's default logging starter, calls made through LogFactory.getLog will flow into that stack. If your application is using Log4J 2, the bridge resolves there instead. If neither SLF4J nor Log4J 2 is available, the fallback is typically java.util.logging.
The code inside your component stays unchanged:
That is the main value of the bridge: library and framework code can stay on a stable API while deployment chooses the concrete backend.
The Real Risk Is Bridge Conflicts
Most logging problems around spring-jcl are not about missing logger creation. They are about conflicting bridges on the classpath.
For example, this is a safe, explicit way to replace Spring Boot's default logging starter with Log4J 2:
What you should not do is pile on multiple incompatible bridge layers and hope discovery sorts it out. Mixing spring-jcl, the original commons-logging, and jcl-over-slf4j without understanding the resolution chain can create duplicate bindings or cycles.
As a rule:
- keep one Commons Logging bridge strategy
- keep one final logging backend
- inspect the dependency tree when logs behave strangely
How to Debug Discovery Issues
When the wrong backend seems active, inspect the runtime classpath first rather than editing application code. In Maven, this is a good first step:
That usually reveals duplicate bridges quickly. If both commons-logging and spring-jcl are present, or if you see multiple SLF4J bindings, clean that up before debugging anything else.
Also remember that Spring's own docs position spring-jcl mainly as a framework bridge. For application code, direct use of SLF4J or another chosen logging API is often clearer. The bridge is most valuable because Spring itself and Spring-based libraries can log consistently without forcing one backend on every application.
Common Pitfalls
The most common mistake is assuming spring-jcl is the same implementation as the original Commons Logging jar. It is not. The API is familiar, but the discovery and bridge behavior are Spring-specific.
Another common problem is bridge stacking. Adding jcl-over-slf4j on top of spring-jcl without excluding something usually creates more confusion, not less. Developers also sometimes debug the wrong layer entirely. If logs are missing, inspect the dependency graph and backend bindings before changing logger calls in the source.
Summary
- '
spring-jclkeeps the Commons Logging API but uses Spring's own bridge and backend detection behavior.' - In modern Spring apps, logging usually flows from
spring-jclinto SLF4J, Log4J 2, orjava.util.logging. - The main operational risk is conflicting bridge jars on the classpath.
- Use dependency inspection to debug discovery issues before touching application code.
- For application-facing code, direct SLF4J usage is often clearer, while
spring-jclremains valuable for framework integration.
Related reading
- Start kubernetes container with specific command
- Start one pod at a time when replica is greater than one
- Starting 2 hazelcast instances synchronously on a single machine (with hazelcast.initial.min.cluster.size=2)
- Starting a Kafka topics using Docker Compose with spotify/kafka?
- Standard concise way to copy a file in Java?
- Start thread at springboot application
- Starting a shell in the Docker Alpine container
- Starting Kafka Server Permanently

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.