>>>> 😜😜😜 Github: 👉 github.com/black-ant CASE Backup: 👉 gitee.com/antblack/ca…

A. The preface

This article discusses a few simple things, mainly to understand what a logging portal is and how it is integrated.

2. Log portal

The Java development manual published by Ali contains this mandatory rule:

Instead of using apis from Logging systems (Log4j, Logback), applications should rely on apis from Logging frameworks (SLF4J, JCL–Jakarta Commons Logging). Using a facade Logging framework is beneficial for maintenance and consistency of log processing for each class.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Test.class);
Copy the code

So why use it that way?

What is a logging portal?

The Simple Logging Facade for Java (SLF4J) acts as a Simple Facade or abstraction for various Logging frameworks such as java.util.logging, Logback, log4J, allowing end users to plug in the required Logging frameworks at deployment time.

To put it simply, the purpose of a portal is for decoupling, and SLF4J is like an abstract class with no focus on implementation. In use, it can also be used flexibly.

3. Integration method

Class diagram

As you can see, the core pre-processing is the initialization stage, which is used to load the corresponding plug-in into the system.

3.1 Initialization Phase

// S1: initiation of initialization
// Log loading is also done in LogFactory
C- SpringApplication
private static final Log logger = LogFactory.getLog(SpringApplication.class);


// S2: LogFactory initiates the process and loads the Adapter Adapter
getLog -> LogAdapter.createLog(name);


// S3: the LogAdapter loads the specific processing class
public static Log createLog(String name) {
    switch(logApi) {
    // The code is simple and critical, and is created by type
    // As you can also see here, using a logging framework leads to coupling, so using a portal makes more sense
    case LOG4J:
        return LogAdapter.Log4jAdapter.createLog(name);
    case SLF4J_LAL:
        return LogAdapter.Slf4jAdapter.createLocationAwareLog(name);
    case SLF4J:
        return LogAdapter.Slf4jAdapter.createLog(name);
    default:
        returnLogAdapter.JavaUtilAdapter.createLog(name); }}// S4: Invoke the concrete implementation class (Slf4j as an example)
C- org.slf4j.LoggerFactory # getILoggerFactory 
    1-performinitialization () : Get LoggerFactoru -> s5-bind () : Scan class - StaticLoggerBinder. GetSingleton (.) getLoggerFactory () : returns the final object2- iloggerFactory.getLogger (name) : Obtains a Logger object from the Factory// S5: Binder binds concrete implementation classesC- org.slf4j.LoggerFactory # bind() ? - The whole process is mainly divided into the following steps1- obtain implementation class | - Set the < URL > staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet ();2- more binding check: is that also if there are multiple versions of different type or different log | - reportMultipleBindingAmbiguity framework will remind of reason3- print the actual binding type (can see the final implementation class) | - reportActualBinding (staticLoggerBinderPathSet);// s5-1: perform specific class load
// STATIC_LOGGER_BINDER_PATH -> org/slf4j/impl/StaticLoggerBinder.classSet<URL> staticLoggerBinderPathSet = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH); ? - Here is the way to load the implementation of different implementation frameworks by scanning the packageCopy the code

Added: Compatible mode

Since time is decoupled, you can’t introduce actual processing classes into it, so how does it integrate? An additional introduction can be seen in logback:

jar:file:/D:/java/resource/repo/ch/qos/logback/logback-classic/1.23./logback-classic-1.23..jar! /org/slf4j/impl/StaticLoggerBinder.classCopy the code

As you can see, in fact, this kind of integration requires third-party compatibility. For example, the log4j

jar:file:/D:/java/resource/repo/org/slf4j/slf4j-log4j12/1.730./slf4j-log4j12-1.730..jar! /org/slf4j/impl/StaticLoggerBinder.classCopy the code

3.2 Actual call phase

In the actual call, we call loggerFactory.getLogger (test.class); When initiated, the final implementation Factory class will be obtained according to the above process, and then the specific Logger object will be obtained through its iloggerFactory.getLogger (name), at this time the object is already the implementation class

conclusion

  • The real decoupling is done through LogFactory
  • When you use Logger, you actually use the implementation class

4. Mybatis analogy

Of course, direct calls are easy to understand, but how would you use this feature if you were a framework?

Slf4j + logback SQL output

We only need two simple steps to realize the Log output:

S1: Configure the Mybatis log mode
mybatis-plus:
    configuration:
        log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
        
// S2: Logback is configured
<logger name="com.apache.ibatis" level="debug"/>
<logger name="java.sql.Connection" level="debug"/>
<logger name="java.sql.Statement" level="debug"/>
<logger name="java.sql.PreparedStatement" level="debug"/>
<logger name="com.gang.test.dao.mapper" level="debug"/>
Copy the code

Slf4jImpl = Slf4jImpl = Slf4jImpl = Slf4jImpl = Slf4jImpl

We know that the core processing class of Mybatis Log is BaseJdbcLogger, which provides a variety of different Log implementation classes: StdOutImpl/Slf4jImpl and so on

If we choose StdOutImpl, we can only simply print to the console, so we usually use Slf4jImpl or Log4jImpl to print to the log and log fetch.

// Core: BaseJdbcLogger handles the Logger, but as you can see here, the Log is actually passed in externally
public BaseJdbcLogger(Log log, int queryStack) 


// Where is the incoming place?When building a MappedStatement, Mybatis will use the LogFactory to build the LogS1: Load the Log implementation class
private static void setImplementation(Class<? extends Log> implClass) {
    // Get the actual log-handling class by constructor reflection
    Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
    Log log = candidate.newInstance(LogFactory.class.getName());
    logConstructor = candidate;
}


// S2 : LogFactory # getLog
public static Log getLog(String logger) {
    return logConstructor.newInstance(logger);
}

Copy the code

Adaptation method of Mybatis

Different from business systems with clear purpose, slF4J can be used at the beginning. Frameworks such as Mybatis cannot be used clearly at the beginning, so the internal approach of Mybatis is: try to process all, and if any process succeeds, the following will not be processed

C-logfactory: Try loading different logging frameworks in turnstatic {
  tryImplementation(LogFactory::useSlf4jLogging);
  tryImplementation(LogFactory::useCommonsLogging);
  tryImplementation(LogFactory::useLog4J2Logging);
  tryImplementation(LogFactory::useLog4JLogging);
  tryImplementation(LogFactory::useJdkLogging);
  tryImplementation(LogFactory::useNoLogging);
}

Copy the code

Note that this is not directly related to the log-impl configuration, which is handled in the following sections


// S1: attribute loading
C- org.apache.ibatis.session.Configuration
public void setLogImpl(Class<? extends Log> logImpl) {
  if(logImpl ! =null) {
    this.logImpl = logImpl;
    LogFactory.useCustomLogging(this.logImpl); }}// S2: override the custom processing class
public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
  setImplementation(clazz);
}

Copy the code

It can also be seen here that the processing of Mybatis is actually divided into two steps:

  • The log processing implementation classes are loaded in full sequence
  • If you customize the log implementation class, override logConstructor for custom processing

conclusion

Rather than reflecting the implementation class subjectively, or having multiple frameworks implement a more abstract interface, Slf4j requires the logging framework to actively adapt to implement its StaticLoggerBinder class and then use the concrete framework class by sweeping packages

Through the analysis of Mybatis, we can also see the influence brought by different logging frameworks. Class coupling needs to be carried out in the code to adapt to different logging frameworks.

If it is only internal business system, Slf4j can bring a lot of advantages. If it is to write open source framework, it is also a good choice to use Mybatis in the way of full quantity first and then customization