How do SLF4J / JPA / JAX-RS find their implementation?

I am learning Java and I find that there are many features that are standardized:

  • logging (using SLF4J)
  • Saving (using JPA)
  • REST (using JAX-RS)
  • SOAP (using JAX-WS)
  • and etc.

Take the Sl4j example: to use it correctly with log4j, we need to import the sl4j api, sl4j / log4j bridge and the implementation of log4j.

Question In my class, I only communicate with the Slf4j API.

How does my application know about the implementation of log4j? Can someone explain what exactly happens under the hood?

Hi

+6
source share
4 answers

The OP asks a general question about how implementation is introduced in some different cases.

entrance

As many answers SLF4J , SLF4J gives an interface, and log4j-slf4j gives an implementation.

When you use the following statement:

  import org.slf4j.Logger; import org.slf4j.LoggerFactory; ... private static final Logger LOG = LoggerFactory.getLogger(FooBarClass.class); ... LOG.debug("Foobar"); 

This is what happens:

We are trying to get Logger from the getLogger method declared in the LoggerFactory class :

 public static ILoggerFactory getILoggerFactory() { if (INITIALIZATION_STATE == UNINITIALIZED) { synchronized (LoggerFactory.class) { if (INITIALIZATION_STATE == UNINITIALIZED) { INITIALIZATION_STATE = ONGOING_INITIALIZATION; performInitialization(); } } } switch (INITIALIZATION_STATE) { case SUCCESSFUL_INITIALIZATION: return StaticLoggerBinder.getSingleton().getLoggerFactory(); } ... } 

So, the magic happens in this statement:

 return StaticLoggerBinder.getSingleton().getLoggerFactory(); 

Since the classpath knows that you implemented why, the StaticLoggerBinder implementation is provided by log4j . As we can see, log4j provides its own implementation:

 private final ILoggerFactory loggerFactory; ... private StaticLoggerBinder() { loggerFactory = new Log4jLoggerFactory(); } 

What is it!

Constancy

For the JPA / Hibernate part, you should include hibernate-jpa-api and hibernate-* (core, entitymanager, etc.).

Suppose you want to create an EntityManagerFactory :

  import javax.persitence.EntityManagerFactory import javax.persitence.Persistence; ... private static EntityManagerFactory EMF = Peristence.createEntityManagerFactory("foobar", null); 

As for List and ArrayList , your class path will be equipped with an interface and implementation thanks to the imported JAR servers.

EntityManagerFactory comes from hibernate-jpa-api , where we have a Persistence class . We can notice that the createEntityManagerFactory method first lists all the providers , and createEntityManagerFactory run for each of them. Here comes hibernate . It provides a HibernatePersistenceProvider that implements the PersistenceProvider class .

This is how hibernate is introduced.

+4
source

If you are talking about working with slf4j , for example:

 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FooClass.class); 

then it’s pretty simple: org.slf4j.Logger is just an interface that has several implementations. In the case of using the slf4j-log4j12 this interface is implemented by the org.slf4j.impl.Log4jLoggerAdapter class, which inside contains

final transient org.apache.log4j.Logger logger;

So this is a simple adapter that wraps your logging requests and calls them on the log4j logger object:

 public void debug(String msg) { logger.log(FQCN, Level.DEBUG, msg, null); } 

More specifically, the correct Logger implementation is created by a LoggerFactory , which first creates a Log4jLoggerFactory through

 StaticLoggerBinder.getSingleton().getLoggerFactory() 

the latter creates the required instance of Log4jLoggerAdapter .


As a rule, it works through the adaptation level, for example, on img from the documentation :

enter image description here

+2
source

Slf4j can be used with log4j or any other core logging library.

In the case of log4j it uses log4j-slf4j-impl.jar , which contains the necessary classes to communicate with the log4j library.

According to the documentation -

SLF4J does not allow logging at run time, but directly during compilation using the bridge API. So more than a JAR SLF4J, you need the following JARs: bridge JARs and JARs. Here is what you get with Log4J:

Slf4j-log4j integration

+2
source

The SLF4J manual refers to how the SLF4J hoop finds its application: Linking to the registration framework during deployment .

SLF4J refers to what allows you to use an implementation (Logback, Log4J, etc.) as "SLF4J bindings":

As mentioned earlier, SLF4J supports various logging structures. The SLF4J distribution includes several jar files called SLF4J Bindings, with each binding corresponding to the supported framework.

You have as many SLF4J bundles as your SLF4J implementation. And, of course, the implementation API can have various "SLF4J bindings" according to its version:

To switch registration frameworks, just replace the slf4j bindings with your class path. For example, to switch from java.util.logging to log4j, simply replace slf4j-jdk14-1.7.22.jar with slf4j-log4j12-1.7.22.jar.

Linking to an implementation is not performed at run time, but at compile time: each SLF4J binding is tightly bound at compile time to use one and only one specific logging structure.
So, you must include the SLF4J binding in the classpath (e.g. slf4j-jdk14-1.7.22.jar) so that SLF4J uses it:

SLF4J does not rely on special-class forklift equipment. In fact, each SLF4J binding is tightly bound at compile time to use one and only one specific logging structure. For example, Binding slf4j-log4j12-1.7.22.jar is bound at compile time to use log4j. In your code, in addition to slf4j-api-1.7.22.jar, you just drop one and only one binding of your choice to the appropriate path location. Do not place more than one binding to your class track. Here is a graphic illustration of a general idea.

Therefore, it is generally recommended that you do not set more than one SLF4J binding in the classpath, since SLF4J is not intended to be an implementation choice at runtime.

+1
source

Source: https://habr.com/ru/post/1014916/


All Articles