In the documentation for slf4j it says that the binding happens during complie time:
"SLF4J does not rely on any special class loader machinery. In fact, each SLF4J binding is hardwired at compile time to use one and only one specific logging framework. For example, the slf4j-log4j12-1.7.5.jar binding is bound at compile time to use log4j. In your code, in addition to slf4j-api-1.7.5.jar, you simply drop one and only one binding of your choice onto the appropriate class path location. Do not place more than one binding on your class path. Here is a graphical illustration of the general idea." http://www.slf4j.org/manual.html
How does this work?
Bindings are basically implementations of a particular SLF4J class meant to be extended to plug in a specific logging framework. By design, SLF4J will only bind with one logging framework at a time. Consequently, if more than one binding is present on the classpath, it will emit a warning.
So essentially, SLF4J does not replace log4j; they both work together. It removes the dependency on log4j from your application and makes it easy to replace it in the future with the more capable library.
Binary compatibility. An SLF4J binding designates an artifact such as slf4j-jdk14. jar or slf4j-log4j12. jar used to bind slf4j to an underlying logging framework, say, java.
This is the main purpose of SLF4J (Simple Logging Facade for Java) – a logging abstraction which helps to decouple your application from the underlying logger by allowing it to be plugged in – at runtime. Of course, the flexibility that such an abstraction provides is the main reason to use SLF4J.
Here is the source code of slf4j. Slf4j will find all the class in the class path whose path is "org/slf4j/impl/StaticLoggerBinder.class". And if there are more than one, jvm will pick up only one randomly.For more detail you can see here:http://www.slf4j.org/codes.html#multiple_bindings
// We need to use the name of the StaticLoggerBinder class, but we can't
// reference
// the class itself.
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
static Set<URL> findPossibleStaticLoggerBinderPathSet() {
// use Set instead of list in order to deal with bug #138
// LinkedHashSet appropriate here because it preserves insertion order
// during iteration
Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
try {
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration<URL> paths;
if (loggerFactoryClassLoader == null) {
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
}
while (paths.hasMoreElements()) {
URL path = paths.nextElement();
staticLoggerBinderPathSet.add(path);
}
} catch (IOException ioe) {
Util.report("Error getting resources from path", ioe);
}
return staticLoggerBinderPathSet;
}
It was my question too and I'd like to add my answer, since found the other two answer not clear enough (though are perfectly correct).
First, check this line in the implementation of LoggerFactory.bind()
in slf4j-api
(link)
// the next line does the binding
StaticLoggerBinder.getSingleton();
There is a class called org.slf4j.impl.StaticLoggerBinder
. Check its implementation on github.
Now go ahead and download the slf4j-api.jar from the central maven repository, extract it and find StaticLoggerBinder.class
file.
Don't try! You can't. In fact the whole org.slf4j.impl
has been removed from the package. Check the pom.xml
of the project:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<configuration>
<tasks>
<echo>Removing slf4j-api's dummy StaticLoggerBinder and StaticMarkerBinder</echo>
<delete dir="target/classes/org/slf4j/impl"/>
</tasks>
</configuration>
</plugin>
Last, check one of the SLF4j's binding packages, for example slf4j-simple
. Can you find org.slf4j.impl.StaticLoggerBinder
class?
In sum, when you have slf4j-api.jar
alongside one (and only one) of the binding packages in you runtime environment, you have only one org.slf4j.impl.StaticLoggerBinder
class which does the binding.
From what I have seen, it does this by expecting the class StaticLoggingBinder to be in the same package (org.slf4j.impl), regardless of the implementation - so it always finds it in the same place.
Technically, there's no magic "binding" happening at compile time. The "binding" happened when the SLF4J developers created libraries to handle the most popular Java logging frameworks.
When the docs say that the "binding is hardwired at compile time," it means the SLF4J developers have created a targeted library for a particular Java logging framework. SLF4J has libraries dedicated to Java Logging, Jakarta Commons Logging, Log4J, and console output. You will need to include only one of these libraries at runtime in order for SLF4J to successfully create log messages.
For more information on how SLF4J works: A more visual way to understand SLF4J.
It's just as @Rad said.
What I wanna replenish is that if you have multiple StaticLoggerBinder
implements in your runtime environment, slf4j choose one of them RANDOMLY, as said in multiple_bindings:
The way SLF4J picks a binding is determined by the JVM and for all practical purposes should be considered random. As of version 1.6.6, SLF4J will name the framework/implementation class it is actually bound to.
Another attention is that if your project is planned to be a library for other projects, only slf4j-api
should be included, any implementation for slf4j-api
is not allowed:
Embedded components such as libraries or frameworks should not declare a dependency on any SLF4J binding but only depend on slf4j-api. When a library declares a compile-time dependency on a SLF4J binding, it imposes that binding on the end-user, thus negating SLF4J's purpose.
The implementation is not bound at compile-time (it's not a static/early binding) or in other words the implementation it's not known at compile time.
Actually it's the vice-versa where the implementation is bound at runtime, meaning that the implementation is discovered through dynamic/runtime binding . The Slf4j folks have actually declared how the binding happens in their manual https://www.slf4j.org/manual.html:
SLF4J allows the end-user to plug in the desired logging framework at deployment time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With