>>>> 😜😜😜 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