Résumé et analyse de l'avant - dernier cadre complet du Journal

Eaglelihh 2021-08-20 00:14:53 阅读数:996

sum et analyse avant dernier

Origine

J'ai entendu trop de cadres de log,Par exemple,log4jjcljclslf4jlogback……

Ces concepts ont été très confus avant,Je ne sais pas exactement ce qu'ils font,Et je ne sais pas quand je veux utiliser un cadre de journalisation,Comment introduire des dépendances connexes

Cet article rassemble les cadres de journalisation communs,Et l'utilisation et les principes connexes.

L'évolution du Journal

a. Dès le début,Tout le monde utiliseSystem.outEtSystem.errPour imprimer le journal;Non flexible et non configurable;Ou tout imprimer,Soit ils n'impriment pas tous;Il n'y a pas de niveau de journalisation uniforme

b. Et puisLog4jEt voilà.,C'est...Ceki Gülcü Ce grand homme a développé ,Et puisLog4jOui.Apache Un des projets de la Fondation

c. Et puisJava Il a également lancé son propre cadre de journalisation JUL(Java Util Logging),Inpackage java.util.loggingEn bas.

d. Apache L'interface log est de nouveau disponible Jakarta Commons Logging, C'est - à - dire la couche d'abstraction du Journal , Vous pourrez facilement Log4jEtJUL Basculer entre

e. Ceki Gülcü J'ai l'impression que JCLC'est pas bon., Mise au point d'un nouvel ensemble de portes d'accès aux journaux Slf4j(Simple Logging Facade for Java)、 Sa réalisation Logback Et quelques ponts :

jcl-over-slf4j.jar :jcl ——> slf4j
slf4j-jcl.jar :slf4j ——> jcl
log4j-over-slf4j :log4j ——> slf4j
slf4j-log4j12.jar :slf4j ——> log4j
jul-to-slf4j :jul ——> slf4j
slf4j-jdk14.jar :slf4j ——> jul

f. Et puisApache Lancement direct de nouveaux projets ,Non, pas du tout.Log4j1.xMise à jour, C'est un nouveau projet Log4j2,Parce queLog4j2 Est totalement incompatible Log4j1.xDe, Il a aussi conçu la séparation , Se différencier en log4j-apiEtlog4j-core,C'estlog4j-api C'est aussi l'interface log ,log4j-core C'est l'implémentation du Journal , Il y a aussi beaucoup de ponts. :

log4j-jcl :jcl ——> log4j2
log4j-1.2-api :log4j ——> log4j2
log4j-slf4j-impl :slf4j ——> log4j2
log4j-jul :jul ——> log4j2
log4j-to-slf4j :log4j2 ——> slf4j

Utilisation de base

log4j

Dépendance:
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
Profil:
log4j.properties
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
Catégorie d'essai:
import org.apache.log4j.Logger;
public class Main {
public static void main(String[] args) {
Logger logger = Logger.getLogger(Main.class);
logger.info("hello, world!");
}
}
Produits:
0 [main] INFO cn.eagleli.log.log4j.Main - hello, world!

jul

Catégorie d'essai:
import java.util.logging.Logger;
public class Main {
public static void main(String[] args) {
Logger logger = Logger.getLogger(Main.class.getName());
logger.info("hello, world!");
}
}
Produits:
Août 11, 2021 11:06:19 Après - midi cn.eagleli.log.jul.Main main
Information: hello, world!

jcl

Dépendance:
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
Catégorie d'essai:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Main {
public static void main(String[] args) {
Log log = LogFactory.getLog(Main.class);
log.info("hello, world!");
}
}
Produits:
Août 11, 2021 11:08:25 Après - midi cn.eagleli.log.jcl.Main main
Information: hello, world!

Comme le montre la sortie ci - dessus ,Par défautjul En tant que cadre de journalisation sous - jacent

Si on veut changer log4j En tant que cadre de journalisation sous - jacent ,Et alors?? Il suffit d'ajouter une dépendance ,Comme suit:

Dépendance:
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
Produits:
0 [main] INFO cn.eagleli.log.jcl.Main - hello, world!

Les résultats montrent que, Le cadre de journalisation sous - jacent a changé , J'ai aussi trouvé , Notre code n'a pas changé , J'ai juste ajouté une dépendance , Cela montre l'importance de l'interface .

slf4j

Dépendance:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
Catégorie d'essai:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(Main.class);
logger.info("hello, world!");
}
}
Produits:
23:14:30.893 [main] INFO cn.eagleli.log.slf4j.Main - hello, world!

Le cadre de journalisation sous - jacent ci - dessus utilise logback

Si on veut passer à jcl En tant que cadre de mise en œuvre sous - jacent ,Et alors?? Il suffit de changer une dépendance ,Comme suit:

Dépendance:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jcl</artifactId>
<version>1.7.30</version>
</dependency>
</dependencies>
Produits:
Août 11, 2021 11:18:27 Après - midi org.slf4j.impl.JCLLoggerAdapter info
Information: hello, world!

D'après les résultats ci - dessus , Le rez - de - chaussée a été coupé à jclC'est,EtjclLa valeur par défaut estjdkCadre de journalisation

cl-over-slf4jEtslf4j-jcl Ne peut pas être utilisé en même temps

Parce que l'utilisation précédente jcl API Pont vers slf4j, Ce dernier est utilisé slf4j API Pont vers jcl, Si une référence simultanée provoque un appel circulaire , Ce qui provoque un débordement de pile

log4j2

Dépendance:
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
</dependencies>
Catégorie d'essai:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Main {
public static void main(String[] args) {
Logger logger = LogManager.getLogger(Main.class);
logger.error("hello, world!");
}
}
Produits:
23:22:12.148 [main] ERROR cn.eagleli.log.log4j2.Main - hello, world!

Ce que nous avons adopté ci - dessus log4j2 En tant qu'implémentation sous - jacente , Nous voulons utiliser slf4j En tant qu'implémentation sous - jacente ,Et alors?? Il suffit d'ajouter une dépendance ,Comme suit:

Dépendance:
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.14.1</version>
</dependency>
</dependencies>
Produits:
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.

D'après les résultats , Notre cadre de journalisation sous - jacent a changé , Parce qu'il n'y a rien slf4j Cadre de classe de mise en oeuvre pour , Donc il n'y a pas de journal de sortie .

Comment se connecter sans couture

jcl Principes

jcl Le Code de base pour la commutation sans soudure est le suivant :

public abstract class LogFactory {
public static Log getLog(Class clazz)
throws LogConfigurationException {
return (getFactory().getInstance(clazz));
}
}
public class LogFactoryImpl extends LogFactory {
public Log getInstance(Class clazz) throws LogConfigurationException {
return (getInstance(clazz.getName()));
}
}

Obtenez d'abord un LogFactory, Il est personnalisable ,Encore.LogFactory Obtenir un LogCatégorie,Log Les classes peuvent également être personnalisées

LogFactory.getFactory() Pour obtenir un LogFactory, La logique de base est la suivante :

a. Obtenir à partir de la variable système
public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory";
String factoryClass = getSystemProperty(FACTORY_PROPERTY, null);
factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);
b. Obtenir à partir du fichier spécifié
protected static final String SERVICE_ID =
"META-INF/services/org.apache.commons.logging.LogFactory";
final InputStream is = getResourceAsStream(contextClassLoader, SERVICE_ID);
c. De la désignation propertiesAccès aux documents
public static final String FACTORY_PROPERTIES = "commons-logging.properties"
Properties props = getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES);
public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory";
String factoryClass = props.getProperty(FACTORY_PROPERTY);
factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);
d.Par défautLogFactoryRéalisation
public static final String FACTORY_DEFAULT = "org.apache.commons.logging.impl.LogFactoryImpl"
factory = newFactory(FACTORY_DEFAULT, thisClassLoader, contextClassLoader);

LogFactoryImpl.discoverLogImplementation() Pour obtenir un Log, La logique de base est la suivante :

a.DeLogFactoryDeattributes Obtenir dans la variable
public static final String LOG_PROPERTY = "org.apache.commons.logging.Log"
String specifiedClass = (String) getAttribute(LOG_PROPERTY);
public Object getAttribute(String name) {
return attributes.get(name);
}
b. Obtenir à partir des variables du système
public static final String LOG_PROPERTY = "org.apache.commons.logging.Log";
specifiedClass = getSystemProperty(LOG_PROPERTY, null);
c. Liste des tableaux par défaut
private static final String LOGGING_IMPL_LOG4J_LOGGER = "org.apache.commons.logging.impl.Log4JLogger";
private static final String[] classesToDiscover = {
LOGGING_IMPL_LOG4J_LOGGER,
"org.apache.commons.logging.impl.Jdk14Logger",
"org.apache.commons.logging.impl.Jdk13LumberjackLogger",
"org.apache.commons.logging.impl.SimpleLog"
};
for(int i=0; i<classesToDiscover.length && result == null; ++i) {
result = createLogFromClass(classesToDiscover[i], logCategory, true);
}
// Chargement de première classe , Puis créer une instance en utilisant la réflexion
public class LogFactoryImpl extends LogFactory {
private Log createLogFromClass(String logAdapterClassName,
String logCategory,
boolean affectState)
throws LogConfigurationException {
Class c = null;
try {
c = Class.forName(logAdapterClassName, true, currentCL);
} catch (ClassNotFoundException originalClassNotFoundException) {
}
constructor = c.getConstructor(logConstructorSignature);
Object o = constructor.newInstance(params);
}
}

Regarde un ou deux adaptateurs Logger

a.
import java.util.logging.Logger;
public class Jdk14Logger implements Log, Serializable {
public Jdk14Logger(String name) {
this.name = name;
logger = getLogger();
}
public Logger getLogger() {
if (logger == null) {
logger = Logger.getLogger(name);
}
return logger;
}
public void info(Object message) {
log(Level.INFO, String.valueOf(message), null);
}
private void log( Level level, String msg, Throwable ex ) {
Logger logger = getLogger();
if (logger.isLoggable(level)) {
// ...
}
}
}
b.
import org.apache.log4j.Logger;
public class Log4JLogger implements Log, Serializable {
public Log4JLogger(String name) {
this.name = name;
this.logger = getLogger();
}
public Logger getLogger() {
Logger result = logger;
if (result == null) {
synchronized(this) {
result = logger;
if (result == null) {
logger = result = Logger.getLogger(name);
}
}
}
return result;
}
public void info(Object message) {
getLogger().log(FQCN, Priority.INFO, message, null );
}
}

D'après le code ci - dessus , C'est un mode adaptateur typique ,Jdk14LoggerUtilisationjulDeLogger,EtLog4JLogger L'utilisation est log4jDeLogger.

slf4j Principes

slf4j Le Code de base pour la commutation sans soudure est le suivant :

public final class LoggerFactory {
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
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();
case NOP_FALLBACK_INITIALIZATION:
return NOP_FALLBACK_FACTORY;
case FAILED_INITIALIZATION:
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITIALIZATION:
// support re-entrant behavior.
// See also http://jira.qos.ch/browse/SLF4J-97
return SUBST_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
private final static void performInitialization() {
bind();
if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
versionSanityCheck();
}
}
private final static void bind() {
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);
} 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);
throw ncde;
}
} 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);
} finally {
postBindCleanUp();
}
}
}

En passant par le code ci - dessus , En fait, c'est surtout dans LoggerFactory.bind()Dans la méthode,Simple et grossier,Appel directStaticLoggerBinder.getSingleton();Regarde.org.slf4j.impl.StaticLoggerBinder Cette classe a - t - elle déjà classpathEn bas.

D'après l'image ci - dessus ,Nous pouvons voirlogbackEtslf4j-jcl Il y a cette classe ,Plus précisémentStaticLoggerBinder Le Code ne sera pas analysé , Tout le monde peut regarder par lui - même .

log4j2 Principes

log4j2 Le Code de base pour la commutation sans soudure est le suivant :

public class LogManager {
public static Logger getLogger(final Class<?> clazz) {
final Class<?> cls = callerClass(clazz);
return getContext(cls.getClassLoader(), false).getLogger(cls);
}
public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext) {
try {
return factory.getContext(FQCN, loader, null, currentContext);
} catch (final IllegalStateException ex) {
LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
return new SimpleLoggerContextFactory().getContext(FQCN, loader, null, currentContext);
}
}
/**
* Scans the classpath to find all logging implementation. Currently, only one will be used but this could be
* extended to allow multiple implementations to be used.
*/
static {
// Shortcut binding to force a specific logging implementation.
final PropertiesUtil managerProps = PropertiesUtil.getProperties();
final String factoryClassName = managerProps.getStringProperty(FACTORY_PROPERTY_NAME);
if (factoryClassName != null) {
try {
factory = LoaderUtil.newCheckedInstanceOf(factoryClassName, LoggerContextFactory.class);
} catch (final ClassNotFoundException cnfe) {
LOGGER.error("Unable to locate configured LoggerContextFactory {}", factoryClassName);
} catch (final Exception ex) {
LOGGER.error("Unable to create configured LoggerContextFactory {}", factoryClassName, ex);
}
}
if (factory == null) {
final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<>();
// note that the following initial call to ProviderUtil may block until a Provider has been installed when
// running in an OSGi environment
if (ProviderUtil.hasProviders()) {
for (final Provider provider : ProviderUtil.getProviders()) {
final Class<? extends LoggerContextFactory> factoryClass = provider.loadLoggerContextFactory();
if (factoryClass != null) {
try {
factories.put(provider.getPriority(), factoryClass.newInstance());
} catch (final Exception e) {
LOGGER.error("Unable to create class {} specified in provider URL {}", factoryClass.getName(), provider
.getUrl(), e);
}
}
}
if (factories.isEmpty()) {
LOGGER.error("Log4j2 could not find a logging implementation. "
+ "Please add log4j-core to the classpath. Using SimpleLogger to log to the console...");
factory = new SimpleLoggerContextFactory();
} else if (factories.size() == 1) {
factory = factories.get(factories.lastKey());
} else {
final StringBuilder sb = new StringBuilder("Multiple logging implementations found: \n");
for (final Map.Entry<Integer, LoggerContextFactory> entry : factories.entrySet()) {
sb.append("Factory: ").append(entry.getValue().getClass().getName());
sb.append(", Weighting: ").append(entry.getKey()).append('\n');
}
factory = factories.get(factories.lastKey());
sb.append("Using factory: ").append(factory.getClass().getName());
LOGGER.warn(sb.toString());
}
} else {
LOGGER.error("Log4j2 could not find a logging implementation. "
+ "Please add log4j-core to the classpath. Using SimpleLogger to log to the console...");
factory = new SimpleLoggerContextFactory();
}
LogManagerStatus.setInitialized(true);
}
}
}
public final class ProviderUtil {
public static Iterable<Provider> getProviders() {
lazyInit();
return PROVIDERS;
}
protected static void lazyInit() {
// noinspection DoubleCheckedLocking
if (instance == null) {
try {
STARTUP_LOCK.lockInterruptibly();
try {
if (instance == null) {
instance = new ProviderUtil();
}
} finally {
STARTUP_LOCK.unlock();
}
} catch (final InterruptedException e) {
LOGGER.fatal("Interrupted before Log4j Providers could be loaded.", e);
Thread.currentThread().interrupt();
}
}
}
private ProviderUtil() {
for (final ClassLoader classLoader : LoaderUtil.getClassLoaders()) {
try {
loadProviders(classLoader);
} catch (final Throwable ex) {
LOGGER.debug("Unable to retrieve provider from ClassLoader {}", classLoader, ex);
}
}
for (final LoaderUtil.UrlResource resource : LoaderUtil.findUrlResources(PROVIDER_RESOURCE)) {
loadProvider(resource.getUrl(), resource.getClassLoader());
}
}
protected static void loadProviders(final ClassLoader classLoader) {
final ServiceLoader<Provider> serviceLoader = ServiceLoader.load(Provider.class, classLoader);
for (final Provider provider : serviceLoader) {
if (validVersion(provider.getVersions()) && !PROVIDERS.contains(provider)) {
PROVIDERS.add(provider);
}
}
}
}

En fait, le Code de base ci - dessus est final ServiceLoader<Provider> serviceLoader = ServiceLoader.load(Provider.class, classLoader);,UtilisationSPI Obtenir un Provider

Comme le montre la figure ci - dessus,log4j-coreEtlog4j-to-slf4j Ils ont tous leurs propres ProviderCatégorie de mise en œuvre, Le code spécifique n'est pas analysé , Tout le monde peut regarder par lui - même .

Et enfin...SpringCadre de journalisation dans

Spring Le cadre de journalisation dans est spring-jcl, On va juste le voir ,Comme le montre la figure ci - dessous::

Le Code de base pour la commutation sans soudure est le suivant :

public abstract class LogFactory {
public static Log getLog(Class<?> clazz) {
return getLog(clazz.getName());
}
public static Log getLog(String name) {
return LogAdapter.createLog(name);
}
}
final class LogAdapter {
public static Log createLog(String name) {
switch (logApi) {
case LOG4J:
return Log4jAdapter.createLog(name);
case SLF4J_LAL:
return Slf4jAdapter.createLocationAwareLog(name);
case SLF4J:
return Slf4jAdapter.createLog(name);
default:
// Defensively use lazy-initializing adapter class here as well since the
// java.logging module is not present by default on JDK 9. We are requiring
// its presence if neither Log4j nor SLF4J is available; however, in the
// case of Log4j or SLF4J, we are trying to prevent early initialization
// of the JavaUtilLog adapter - e.g. by a JVM in debug mode - when eagerly
// trying to parse the bytecode for all the cases of this switch clause.
return JavaUtilAdapter.createLog(name);
}
}
private static final String LOG4J_SPI = "org.apache.logging.log4j.spi.ExtendedLogger";
private static final String LOG4J_SLF4J_PROVIDER = "org.apache.logging.slf4j.SLF4JProvider";
private static final String SLF4J_SPI = "org.slf4j.spi.LocationAwareLogger";
private static final String SLF4J_API = "org.slf4j.Logger";
private static final LogApi logApi;
static {
if (isPresent(LOG4J_SPI)) {
if (isPresent(LOG4J_SLF4J_PROVIDER) && isPresent(SLF4J_SPI)) {
// log4j-to-slf4j bridge -> we'll rather go with the SLF4J SPI;
// however, we still prefer Log4j over the plain SLF4J API since
// the latter does not have location awareness support.
logApi = LogApi.SLF4J_LAL;
}
else {
// Use Log4j 2.x directly, including location awareness support
logApi = LogApi.LOG4J;
}
}
else if (isPresent(SLF4J_SPI)) {
// Full SLF4J SPI including location awareness support
logApi = LogApi.SLF4J_LAL;
}
else if (isPresent(SLF4J_API)) {
// Minimal SLF4J API without location awareness support
logApi = LogApi.SLF4J;
}
else {
// java.util.logging as default
logApi = LogApi.JUL;
}
}
private static boolean isPresent(String className) {
try {
Class.forName(className, false, LogAdapter.class.getClassLoader());
return true;
}
catch (ClassNotFoundException ex) {
return false;
}
}
}

Comme le montre le code ci - dessus,,spring-jclC'est basé surClass.forName() Pour déterminer si les classes de base de chaque cadre de journalisation existent , Puis créer la correspondance Log Adaptateur .

Nos projets dépendent généralement de spring-boot-starter-web, Ça dépend encore spring-boot-starter, Encore une fois, ça dépend de spring-boot-starter-logging

On va voir spring-boot-starter-logging-2.5.1,Comme le montre la figure ci - dessous::

On a trouvé qu'il n'avait pas de code , Revenons voir pom Dépendances dans le fichier :

<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.14.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.30</version>
<scope>compile</scope>
</dependency>
</dependencies>

De cette dépendance nous pouvons voir que , Il cite logback-classic,C'est - à - direslf4j Cadre de mise en oeuvre pour

Parce quelog4j-to-slf4jEtjul-to-slf4j L'existence de la dépendance , Que vous utilisiez log4j2Toujoursjul, Ils finiront par slf4jAllez.

Pour qu'on puisse dire spring boot Le cadre de journalisation utilisé par défaut est logback.

Résumé

C'est tout ce qu'il a dit., Résumons comment ces cadres d'interface de journalisation peuvent être commutés de façon transparente :
jcl/spring-jcl: Mécanisme de chargement par classe :class.forname()
slf4j: En déterminant si la classe est classpathEn bas.
log4j2:AdoptionSPIForme

RÉFÉRENCES

https://segmentfault.com/a/1190000021121882
https://logging.apache.org/log4j/1.2/manual.html
https://commons.apache.org/proper/commons-logging/guide.html
https://blog.csdn.net/chengmaoning/article/details/78072670
http://www.slf4j.org/legacy.html
https://logging.apache.org/log4j/2.x/runtime-dependencies.html

Copyright:Cet article est[Eaglelihh]Établi,Veuillez apporter le lien original pour réimprimer,remercier。 https://fra.fheadline.com/2021/08/20210820001447197G.html