Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does slf4j bind to implementation? Does it really do so during compile time?

Tags:

slf4j

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?

like image 465
Erik Avatar asked Jul 24 '13 09:07

Erik


People also ask

How does SLF4J binding 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.

Does SLF4J use log4j internally?

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.

What is SLF4J simple binding?

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.

What is the purpose of SLF4J?

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.


6 Answers

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;
}
like image 66
Dai Kaixian Avatar answered Nov 09 '22 09:11

Dai Kaixian


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.

like image 24
Rad Avatar answered Nov 09 '22 08:11

Rad


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.

like image 41
Chris Kimpton Avatar answered Nov 09 '22 08:11

Chris Kimpton


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.

like image 36
Snapman Avatar answered Nov 09 '22 09:11

Snapman


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.

like image 38
puppylpg Avatar answered Nov 09 '22 09:11

puppylpg


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.

like image 42
Cristian Balint Avatar answered Nov 09 '22 09:11

Cristian Balint