Happy Moment
I was talking to my sister today.
Me: I'm in love with a female colleague in our company, she's so pretty, I'm moved, what should I do?
Sis: You can't like a girl just by looking at her appearance
Me: I know, it depends on what's inside her.
Sis: You're overthinking it, but also look at your appearance
Background
existSpringBoot 2.7 Overwhelming Logback 1.3 → not sweet but thirst quenching That part of the schematic analysis, I'm interested inLogback
The expression is a euphemism for
Then I thought, as a software developer, how can I be so undisciplined, it's really not right, in order to express my most sincere apologies, please allow me to punish myself with three slaps!
To make up for it, I'm going to take you through the rest of it.Logback 1.3.14
part of the source code. ReferencesUnderstanding slf4j bindings from the source code, and logback's loading of configuration filesThe same is based on two issues
- How SLF4J is bound to Logback
- How Logback loads configuration files
to start the analysis. Before I analyze it, let me help you with a point of doubt that you may have encountered
How come the version of SLF4J that Logback 1.3.14 depends on is 1.7.36?
Suppose our content is as follows
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0"
xmlns:xsi="http:///2001/XMLSchema-instance"
xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.">
<modelVersion>4.0.0</modelVersion>
<groupId></groupId>
<artifactId>spring-boot-2_7_18</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId></groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>
<properties>
<>8</>
<>8</>
<>UTF-8</>
<>1.3.14</>
</properties>
<dependencies>
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId></groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>logback-classic</artifactId>
<version>${}</version>
</dependency>
</dependencies>
</project>
But we'll see that logback has the following dependency tree
Whether it's logbackofficial post
Or the dependencies in the logback 1.3.14 pom file
slf4j-api
The versions are all2.
(logback 1.3.14
relies on theslf4j-api 2.0.7
) ,slf4j-api 1.7.36
Where did that come from?
This is due to the introduction of the parent dependency
<parent>
<groupId></groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>
(indicates contrast)spring-boot-starter-parent
parent dependency
<parent>
<groupId></groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.18</version>
</parent>
existspring-boot-dependencies
The slf4j version is specified
Then why not?logback-parent-1.3.
hit the nail on the head effective, but rather
spring-boot-dependencies-2.7.
hit the nail on the head What about entry into force? This involves
maven
Dependency prioritization, interested parties can go to the relevant information, this article will not be expanded, because the deviation from our original goal is getting farther and farther away
So how will theslf4j
adapt (a story to another medium)2.0.7
The two ways to do this are as follows
-
If not
spring-boot
Then remove the parent dependency.spring-boot-starter-parent
This is equivalent to bringing in slf4j from logback, which introduces the version that logback depends on
-
In our pom file, specify the
<>2.0.7</>
Here again, it's about prioritizing maven dependencies, which are higher in our own pom file
Either way, get the version right anyway!
SLF4J Binding Logback
Preparing the test code
public class LogbackTest {
private static Logger LOGGER = ();
public static void main(String[] args)
{
("......info");
}
}
You should know where to start with the source code, right? You don't have a choice, you have to choose.getLogger
methodologies
Recommended for everyonedebug
The way to follow, otherwise it is easy to lose; come to theorg.#bind
method here to complete theslf4j
There are two things about the bind method that we need to analyze for ourselves.
-
findServiceProviders
static List<SLF4JServiceProvider> findServiceProviders() { // retain behaviour similar to that of 1.7 series and earlier. More specifically, use the class loader that // loaded the present class to search for services final ClassLoader classLoaderOfLoggerFactory = (); ServiceLoader<SLF4JServiceProvider> serviceLoader = getServiceLoader(classLoaderOfLoggerFactory); List<SLF4JServiceProvider> providerList = new ArrayList<>(); Iterator<SLF4JServiceProvider> iterator = (); while (()) { safelyInstantiate(providerList, iterator); } return providerList; }
Does it feel a little familiar? Let's review.JDK SPIIs it dawning on you? I'm gonna go.
classpath
lowerMETA-INF/services
Look in the catalogorg..SLF4JServiceProvider
fileThen read the contents of it and instantiate the
Got it here.
Provider
It is notLogger
-
initialize
Let's take a look.
defaultLoggerContext
types ofLoggerContext
public class LoggerContext extends ContextBase implements ILoggerFactory, LifeCycle
The second point is related to the Logback loading configuration file, and we'll look at it in more detail later, so let's just look at the first point for now.
Watch this.
Logger
types ofpublic final class Logger
implements org., LocationAwareLogger, LoggingEventAware, AppenderAttachable, Serializable Realized
org.
It's the same asslf4j
It's connected.Next out of the stack and back to the
public static ILoggerFactory getILoggerFactory() { return getProvider().getLoggerFactory(); }
getProvider()
It's already been analyzed, so let's look at the nextgetLoggerFactory()
public ILoggerFactory getLoggerFactory() { return defaultLoggerContext; // if (!initialized) { // return defaultLoggerContext; // // // if (() == null) { // throw new IllegalStateException("contextSelector cannot be null. See also " + NULL_CS_URL); // } // return ().getLoggerContext(); }
It's very simple, just go straight back to
defaultLoggerContext
, defaultLoggerContext in the previousinitialize
It's already been covered, so if you've forgotten, go back to the top and take a look.through (a gap)
getILoggerFactory()
Continue out of the stack topublic static Logger getLogger(String name) { ILoggerFactory iLoggerFactory = getILoggerFactory(); return (name); }
Here.
iLoggerFactory
Is that what it is?defaultLoggerContext
? Read next.(name)
This method is slightly longer, but not difficult, there is just a cache design, I won't expand on it, you guys go through it on your own
summarize
- Binding of SLF4JServiceProvider by means of SPI ()
- LogbackServiceProvider (used form a nominal expression) initialize method instantiates the defaultLoggerContext( implement org.)
- pass (a bill or inspection etc) defaultLoggerContext gain logger( implements org.)
- org. binding completed
Logback Load Configuration File
As already mentioned.#initializeLoggerContext
Finish loading the configuration file
private void initializeLoggerContext() {
try {
try {
new ContextInitializer(defaultLoggerContext).autoConfig();
} catch (JoranException je) {
("Failed to auto configure default logger context", je);
}
// LOGBACK-292
if (!(defaultLoggerContext)) {
(defaultLoggerContext);
}
// (defaultLoggerContext, KEY);
} catch (Exception t) { // see LOGBACK-1159
("Failed to instantiate [" + () + "]", t);
}
}
At a glance, the next step is straightforwardautoConfig
If you follow 2 steps, you will come to the following method
public void autoConfig(ClassLoader classLoader) throws JoranException {
// see /qos-ch/logback/issues/715
classLoader = (classLoader);
String versionStr = ();
if (versionStr == null) {
versionStr = ;
}
().add(new InfoStatus(CoreConstants.LOGBACK_CLASSIC_VERSION_MESSAGE + versionStr, loggerContext));
(loggerContext);
// invoke custom configurators
List<Configurator> configuratorList = (, classLoader);
(rankComparator);
if (()) {
("No custom configurators were discovered as a service.");
} else {
printConfiguratorOrder(configuratorList);
}
for (Configurator c : configuratorList) {
if (invokeConfigure(c) == .DO_NOT_INVOKE_NEXT_IF_ANY)
return;
}
// invoke internal configurators
for (String configuratorClassName : INTERNAL_CONFIGURATOR_CLASSNAME_LIST) {
("Trying to configure with "+configuratorClassName);
Configurator c = instantiateConfiguratorByClassName(configuratorClassName, classLoader);
if(c == null)
continue;
if (invokeConfigure(c) == .DO_NOT_INVOKE_NEXT_IF_ANY)
return;
}
}
The first part reads custom configurations, which can be ignored since we don't have any custom configurations, and goes straight to the
// invoke internal configurators
for (String configuratorClassName : INTERNAL_CONFIGURATOR_CLASSNAME_LIST) {
("Trying to configure with "+configuratorClassName);
Configurator c = instantiateConfiguratorByClassName(configuratorClassName, classLoader);
if(c == null)
continue;
if (invokeConfigure(c) == .DO_NOT_INVOKE_NEXT_IF_ANY)
return;
}
INTERNAL_CONFIGURATOR_CLASSNAME_LIST
It reads as follows
String[] INTERNAL_CONFIGURATOR_CLASSNAME_LIST = {"",
"", ""}
The for loop is once theinvoke
on it, then it returns directly, so it'sINTERNAL_CONFIGURATOR_CLASSNAME_LIST
Element by element, front to backinvoke
, which ends directly once it succeeds; bydebug
We'll find out.DefaultJoranConfigurator
invoke, itsperformMultiStepConfigurationFileSearch
method to find the configuration file
Priority, in descending order, will start withclasspath
Look for three files under
- quest
- quest
- quest
Once it is found, it is returned directly and does not continue to look for it; we use the
without using the other two files, so the effective
Look back again.Background
The laxity inLogback 1.3.14
The loading of configuration files is similar to theLogback 1.1.7
It's basically the same, just less of reading; but then again, the
SLF4J
together withLogback
The binding process is still very much in flux, and everyone can talk to theUnderstanding slf4j bindings from the source code, and logback's loading of configuration files careful comparison
summarize
-
SLF4J 2. bindings with Logback 1. using theSPI machine
-
Logback 1. default profile priority
> >
Priority from highest to lowest Once one is read, this is used directly and does not continue down the list
the reason whySpringBoot 2.7 Overwhelming Logback 1.3 → not sweet but thirst quenching included in
The configuration file must be
Not rigorous enough, what else could it be, you should know? -
choose as far as possible
official post
Depend on the version, don't have a head iron, don't have a head iron, don't have a head iron, don't have a head iron!