Why slF4J
There are so many logging frameworks out there! Log4j, logback, java.util.logging,log4j2, there may be other new and better logging boxes in the future, or you may develop your own logging component based on your company’s needs. So the question is, if I’m using Log4J and I’m on a project team using Logback, do I have to go through the API documentation again (although most logging frameworks are pretty much the same). But it adds to the cost of learning.
Slf4j solves this problem.
What is the slf4j
Slf4j is an abstract set of logging interfaces that defines a unified specification and, in fact, does not provide a concrete implementation of its own. Create an empty project, pom.xml as follows
<?xml version="1.0" encoding="UTF-8"? >
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>logtest</artifactId>
<version>1.0 the SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
</project>
Copy the code
The test class:
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestLog {
@Test
public void testLog(a) {
Logger logger = LoggerFactory.getLogger(TestLog.class);
logger.error("Yan"); }}Copy the code
Test method testLog() :
<?xml version="1.0" encoding="UTF-8"? >
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>logtest</artifactId>
<version>1.0 the SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</project>
Copy the code
Run the test case again
Let’s try multiple logging implementation frameworks together again
<?xml version="1.0" encoding="UTF-8"? >
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>logtest</artifactId>
<version>1.0 the SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
</dependencies>
</project>
Copy the code
The running results are as follows:
The advantage of this design pattern, called facade pattern, is that whatever logging framework we use in the implementation layer, we use the org.slf4J.logger.java interface methods, shielding the differences between different logging frameworks and saving unnecessary learning costs.
How does SLF4J do this
Let’s take a look at the loggerFactory.getLogger (TestLog.class) in the test method
private final static void bind(a) {
try {
Set<URL> staticLoggerBinderPathSet = null;
// skip check under android, see also
// http://jira.qos.ch/browse/SLF4J-328
if(! isAndroid()) { staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet(); reportMultipleBindingAmbiguity(staticLoggerBinderPathSet); }// the next line does the binding
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
reportActualBinding(staticLoggerBinderPathSet);
fixSubstituteLoggers();
replayEvents();
// release all resources in SUBST_FACTORY
SUBST_FACTORY.clear();
} catch (NoClassDefFoundError ncde) {
String msg = ncde.getMessage();
if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
Util.report("Defaulting to no-operation (NOP) logger implementation");
Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
} else {
failedBinding(ncde);
throwncde; }}catch (java.lang.NoSuchMethodError nsme) {
String msg = nsme.getMessage();
if(msg ! =null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) {
INITIALIZATION_STATE = FAILED_INITIALIZATION;
Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
Util.report("Your binding is version 1.5.5 or earlier.");
Util.report("Upgrade your binding to version 1.6.x.");
}
throw nsme;
} catch (Exception e) {
failedBinding(e);
throw new IllegalStateException("Unexpected initialization failure", e); }}Copy the code
See first line 7 findPossibleStaticLoggerBinderPathSet () method, it will get many times before StaticLoggerBinder, namely slf4j and real connection between the logging implementation link, since not only introduced a log implementation framework, So we get a Set. Click in and have a look
org/slf4j/impl/StaticLoggerBinder.class
StaticLoggerBinder.getSingleton()
NoClassDefFoundError
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Copy the code
If multiple log implementation framework is introduced, in reportMultipleBindingAmbiguity (staticLoggerBinderPathSet) this step will print out the following information:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in[jar: file: / C: / Users / 72037717 / m2 / repository/ch/qos/logback/logback - classic / 1.2.3 / logback - classic - 1.2.3. Jar! /org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found bindingin[jar: file: / C: / Users / 72037717 / m2 / repository/org/slf4j/slf4j - simple / 1.7.25 / slf4j - simple - 1.7.25. Jar! /org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found bindingin[jar: file: / C: / Users / 72037717 / m2 / repository/org/slf4j/slf4j - log4j12 1.7.21 / slf4j - log4j12-1.7.21. Jar! /org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
Copy the code
In the next * * reportActualBinding (staticLoggerBinderPathSet) * * will determine the real use of the logging implementation framework
Log4j in SLF4J concrete implementation
Log4j is not quite the same as Logback. Since Apache Log4j itself is not considered compatible with implementing the SLF4J framework, the slf4J-log4j12 package appears as an adapter connecting the two. This is a typical adapter pattern.