Commons-log + log4j 这黄金搭档一直以来都让我们很省心,很好的完成了日志的需求。但是随着技术的变更和对性能的追求,slf4j 和 logback 这对后起之秀的到来好像打破了原本很平静的日志系统,频繁的出现包冲突...
和平的日子不在了,让我们一起来看看究竟发生了什么...
首先看看这些个包,特别是slf4j引入后就引入了一大堆包之后就有点懵了。
为什么commons-logging和jcl-over-slf4j会有冲突呢?看一下它们的类结构
很清晰的可以看到jcl-over-slf4j 重写了 commons-logging...
还有slf4j-api的实现呢,同样看类:
其实就这么简单,往往看了代码之后才发现错误是这么显而易见。。。
顺着研究,继续看一下slf4j的源码及流程
1.测试类
- package com.taobao.wuzhong.log;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.junit.Test;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- /**
- * DESC:
- *
- * Copyright: Copyright 2011 m.taobao.com
- *
- * @author wuzhong@taobao.com
- * @time 2011-4-6 下午03:42:11
- * @version 1.0
- **/
- public class LogTest {
- // Logback tries to find a file called logback.groovy in the classpath.
- // If no such file is found, logback tries to find a file called
- // logback-test.xml in the classpath.
- // If no such file is found, it checks for the file logback.xml in the
- // classpath..
- // If neither file is found, logback configures itself automatically using
- // the BasicConfigurator which will cause logging output to be directed to
- // the console.
- @Test
- public void test() {
- //commons-logging的方式获取
- Log log = LogFactory.getLog(LogTest.class);
- //slf4j直接的方式获取,推荐用这个
- Logger log2 = LoggerFactory.getLogger(LogTest.class);
- log.debug("eeeeee {} {} {}");
- log2.debug("{} {} {}", new String[] { "a", "b", "c" });
- }
- }
logFactory.getLog 会调用内部静态变量 Slf4jLogFactory.getInstance方法,如下:
public Log getInstance(String name) throws LogConfigurationException {
- Log instance = null;
- // protect against concurrent access of loggerMap
- synchronized (this) {
- instance = (Log) loggerMap.get(name);
- if (instance == null) {
- Logger logger = LoggerFactory.getLogger(name); //slf4j的方式,代理过去了
- if(logger instanceof LocationAwareLogger) {
- instance = new SLF4JLocationAwareLog((LocationAwareLogger) logger); //包装了一层,做适配
- } else {
- instance = new SLF4JLog(logger);
- }
- loggerMap.put(name, instance);
- }
- }
- return (instance);
loggerFactory 会调用getILoggerFactory().getlOgger()
- LoggerFactory.java
- public static ILoggerFactory getILoggerFactory() {
- if (INITIALIZATION_STATE == UNINITIALIZED) {
- INITIALIZATION_STATE = ONGOING_INITILIZATION;
- performInitialization();
- }
- switch (INITIALIZATION_STATE) {
- case SUCCESSFUL_INITILIZATION:
- return getSingleton().getLoggerFactory();
- case FAILED_INITILIZATION:
- throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
- case ONGOING_INITILIZATION:
- // support re-entrant behavior.
- // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
- return TEMP_FACTORY;
- }
- throw new IllegalStateException("Unreachable code");
- }
- private final static void performInitialization() {
- bind();
- versionSanityCheck();
- singleImplementationSanityCheck();
- }
这里的bind很关键,这里动态的绑定了slf4j-api的实现机制
- static {
- SINGLETON.init();
- }
- /**
- * Package access for testing purposes.
- */
- void init() {
- try {
- try {
- new ContextInitializer(defaultLoggerContext).autoConfig();
- } catch (JoranException je) {
- Util.reportFailure("Failed to auto configure default logger context",
- je);
- }
- StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext);
- contextSelectorBinder.init(defaultLoggerContext, KEY);
- initialized = true;
- } catch (Throwable t) {
- // we should never get here
- Util.reportFailure("Failed to instantiate ["
- + LoggerContext.class.getName() + "]", t);
- }
- }
获取配置信息初始化
- autoConfig ….
- public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
- ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
- URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
- if (url != null) {
- return url;
- }
- url = Loader.getResource(TEST_AUTOCONFIG_FILE, myClassLoader);
- if (updateStatus) {
- statusOnResourceSearch(TEST_AUTOCONFIG_FILE, myClassLoader, url);
- }
- if (url != null) {
- return url;
- }
- url = Loader.getResource(AUTOCONFIG_FILE, myClassLoader);
- if (updateStatus) {
- statusOnResourceSearch(AUTOCONFIG_FILE, myClassLoader, url);
- }
- return url;
- }
- public void autoConfig() throws JoranException {
- StatusListenerConfigHelper.installIfAsked(loggerContext);
- URL url = findURLOfDefaultConfigurationFile(true);
- if (url != null) {
- configureByResource(url);
- } else {
- BasicConfigurator.configure(loggerContext);
- }
- }
最后画张流程图总结下,^_^
总结: log框架应该很好的诠释了 facade , adapter , 实现上还是比较简单的,很好的做到了接口和实现的分离,对今后的代码组织有一定的启发
相关推荐
5. **源码**:描述中提到的"源码"可能是指SLF4J和Log4j的源代码,这对于开发者理解内部工作原理,调试问题,甚至进行定制化开发非常有用。通过查看源代码,开发者可以学习到日志框架的设计思路,以及如何实现日志...
SLF4J(Simple Logging Facade for Java)是Java中的一种日志门面(Logging Facade),它为各种日志框架提供了一个简单的统一接口,如Log4j、Java Util Logging、Logback等。通过SLF4J,开发者可以在运行时绑定任意...
SLF4J(Simple Logging Facade for Java)与Log4j12的结合:slf4j-log4j12-1.5.0.jar SLF4J 是一个Java日志API的抽象层,它提供了一个简单的统一的接口,允许用户在运行时绑定具体的日志实现。SLF4J的主要目标是使...
SLF4J(Simple Logging Facade for Java)是Java日志框架的一个接口层,它为各种日志实现提供了一个统一的API,使得开发者能够在不修改代码的情况下切换不同的日志实现。这个“slf4j-1.6.1”版本是SLF4J的1.6.1稳定...
SLF4J(Simple Logging Facade for Java)是一个日志抽象层,它为各种日志框架,如Log4j、java.util.logging、Logback等,提供了一个统一的接口。这样,开发者可以在不修改代码的情况下切换不同的日志实现,提高了...
`slf4j-1.5.6.tar.gz`是一个进一步压缩的归档文件,通常包含SLF4J库的JAR文件、源代码、文档和其他资源。解压此文件后,用户可以获取到SLF4J的详细内容,包括API文档、示例代码和可能的绑定实现。而`Readme-说明....
SLF4J提供了一个抽象层,允许开发者选择自己喜欢的日志框架,如Logback、Log4j等。而Log4j则是Apache的一个经典日志组件,提供了丰富的日志记录功能。 在这个“slf4j-all-log4j12-1.4.3.jar.zip”压缩包中,包含的...
SLF4J(Simple Logging Facade for Java)是一个用于各种日志框架的简单抽象,例如java.util.logging,Logback和Log4j。它的主要目的是为应用程序提供一个可以在部署时插拔的日志API,允许最终用户在部署时选择所需...
SLF4J(Simple Logging Facade for Java)是Java中一个重要的日志抽象层,它为各种日志框架,如Logback、Log4j等,提供了一个统一的接口。SLF4J的主要目的是使得应用程序可以在部署时选择合适的日志实现,而无需在...
SLF4J(Simple Logging Facade for Java)是Java中的一种日志门面(Logging Facade),它为各种日志框架提供一个简单的统一接口,使得最终用户能够在部署时插入所需的日志实现。SLF4J的主要目标是允许最终用户在部署...
使用SLF4J的关键在于,通过在项目中引入`slf4j-api.jar`,然后根据实际需求选择合适的日志实现(如logback或log4j),并通过相应的适配器(如`slf4j-log4j12.jar`)桥接SLF4J接口与具体日志框架。这样,如果将来需要...
SLF4J(Simple Logging Facade for Java)是Java中一个广泛应用的日志抽象层,它为各种日志框架,如Log4j、java.util.logging、Logback等提供了一个统一的接口。"slf4j-nop-1.5.8-sources.jar.zip" 文件是一个包含...
4. **配置文件处理**:除了源代码,Migrator还可能处理与特定日志框架相关的配置文件,例如Log4j的log4j.properties或log4j.xml,将其转换为适合SLF4J的配置格式。 **SLF4J的主要优点:** 1. **灵活性**:SLF4J允许...
SLF4J的目的是简化日志库的使用,使开发人员能够在运行时绑定到任何兼容的日志框架,如Logback、Log4j或Java内置的日志系统。 `slf4j-1.5.10.zip`是一个包含SLF4J 1.5.10版本的压缩包。这个版本的SLF4J发布于某个...
在提供的`slf4jDemo`中,可能包含了创建简单日志示例的Java源代码,以及相应的Log4j配置文件。通过运行这个示例,你可以直观地了解SLF4J和Log4j如何协同工作,以及如何配置和使用它们来满足项目的需求。通过实践,你...
SLF4J(Simple Logging Facade for Java)是Java中的一种日志门面(Logging Facade),它为各种日志框架提供了一个简单的统一接口,如Log4j、Java Util Logging、Logback等。这个"slf4j-1.7.2.zip"压缩包包含了SLF4J...
SLF4J(Simple Logging Facade for Java)是Java日志记录的一个接口层,它为各种日志框架,如Log4j、Java Util Logging、Logback等,提供了一个统一的API。`slf4j-api-1.7.12.jar`是SLF4J API的1.7.12版本的实现库,...
SLF4J通过提供一组抽象的日志记录接口,使得开发者可以在不依赖具体日志实现的情况下编写代码,从而在不同的日志框架之间切换,如Log4j、Logback等。 SLF4J的"jdk14"模块是特别针对Java 1.4引入的,因为Java 1.4及...
SLF4J(Simple Logging Facade for Java)是Java中的一种日志抽象层,它为各种日志框架,如Log4j、Logback等提供了一个简单的接口。SLF4J的主要目的是使应用程序能够在其开发阶段选择任何日志框架,而无需在部署时...
SLF4J(Simple Logging Facade for Java)是Java日志框架的一个接口层,它为各种日志实现提供了一个统一的API,使得开发者能够在不修改代码的情况下切换不同的日志实现,如Log4j、Logback等。SLF4J的设计理念是通过...