log4j_slf4j源码分析(上)

前言:
    对slf4j和log4j、logback的关系不太了解的少年们可以先看下这篇文章   https://blog.csdn.net/qq_26323323/article/details/80883760 
    具体来说,slf4j是一系列的接口规范定义,而Log4j、logback则是其具体实现,在写法上,我们可以直接针对接口编程,底层实现可任意切换

1.基于log4j的日志功能实现
    1)maven导入依赖
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.25</version>
		</dependency>
        
    2)log4j.xml配置(直接配置在src/main/resources下)
<?xml version="1.0"  encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration>

    <!--若干个appender的定义-->
    <!--org.apache.log4j.ConsoleAppender 输出到控制台-->
    <appender name="myConsole" class="org.apache.log4j.ConsoleAppender">
        <!--输出格式-->
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                   value="%-d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n"/>
        </layout>
    </appender>


    <!-- 根logger的设置-->
    <root>
        <!--优先级设置,假设设置为“info”,则无法输出debug级别的日志-->
        <priority value="debug"/>

        <!--添加刚才设置的appender-->
        <appender-ref ref="myConsole"/>
    </root>
</log4j:configuration>
    3)测试类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestLog4j {

	private static final Logger logger = LoggerFactory.getLogger(TestLog4j.class);
	
	public static void main(String[] args) {
		logger.debug("debug msg");
		logger.info("info msg");
		logger.error("error msg");
	}
}
    4)测试结果
2018-07-02 14:11:04,298 [log4j.TestLog4j]-[DEBUG] debug msg
2018-07-02 14:11:04,299 [log4j.TestLog4j]-[INFO] info msg
2018-07-02 14:11:04,299 [log4j.TestLog4j]-[ERROR] error msg
2.获取Logger源码分析
    可以看到上过程3)中,测试类TestLog4j所引入的Logger和LoggerFactory都属于slf4j包下,真正的实现都在log4j包下,下面请跟着笔者看下源码的流程

     1)分析LoggerFactory.getLogger(TestLog4j.class)
   public static Logger getLogger(String name) {
        // 获取ILoggerFactory接口
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        // 获取Logger,都是面向接口的方式
        return iLoggerFactory.getLogger(name);
    }

    // 获取ILoggerFactory
    public static ILoggerFactory getILoggerFactory() {
        // 由代码    static volatile int INITIALIZATION_STATE = UNINITIALIZED;可知,INITIALIZATION_STATE的默认状态是UNINITIALIZED,
        // 故默认会先实现该if功能,而且是串行实现的
        if (INITIALIZATION_STATE == UNINITIALIZED) {
            synchronized (LoggerFactory.class) {
                if (INITIALIZATION_STATE == UNINITIALIZED) {
                    // 更改状态为正在执行
                    INITIALIZATION_STATE = ONGOING_INITIALIZATION;
                    // 初始化信息
                    performInitialization();
                }
            }
        }
        switch (INITIALIZATION_STATE) {
        // 当performInitialization()成功执行完成后,INITIALIZATION_STATE的状态为SUCCESSFUL_INITIALIZATION,故可从此获取LoggerFactory的具体实现
        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");
    }
    2)初始化信息performInitialization()方法
    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()) {
                // 获取 org/slf4j/impl/StaticLoggerBinder.class 资源
                staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
                reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
            }
            // 参考getSingleton()方法,可看到StaticLoggerBinder默认初始化一个SINGLETON为new StaticLoggerBinder()
            StaticLoggerBinder.getSingleton();
            INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
            reportActualBinding(staticLoggerBinderPathSet);
            fixSubstituteLoggers();
            replayEvents();
            // release all resources in SUBST_FACTORY
            SUBST_FACTORY.clear();
        }catch{...}
    }

    3)StaticLoggerBinder.getSingleton()
    可以看到在slf4j-log4j12-1.7.25.jar下的StaticLoggerBinder类实现了ILoggerFactory接口
public class StaticLoggerBinder implements LoggerFactoryBinder {

    private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();

    public static final StaticLoggerBinder getSingleton() {
        return SINGLETON;
    }
    
    private final ILoggerFactory loggerFactory;

    private StaticLoggerBinder() {
        // 构造的时候,直接实现了LoggerFactory,默认为Log4jLoggerFactory
        loggerFactory = new Log4jLoggerFactory();
        try {
            @SuppressWarnings("unused")
            Level level = Level.TRACE;
        } catch (NoSuchFieldError nsfe) {
            Util.report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version");
        }
    }
    4)返回ILoggerFactory
    public static ILoggerFactory getILoggerFactory() {
        ...
        switch (INITIALIZATION_STATE) {
        case SUCCESSFUL_INITIALIZATION:
            // 直接从单例中获取在构造时实现的LoggerFactory,即Log4jLoggerFactory
            return StaticLoggerBinder.getSingleton().getLoggerFactory();
        ...
    }
    上述即是获取ILoggerFactory具体实现的过程,下面看如何获取Logger

    5)ILoggerFactory.getLogger()
    目前可知,默认工厂实现是Log4jLoggerFactory,所以直接定位到该类的getLogger(String name)方法
    public Log4jLoggerFactory() {
        loggerMap = new ConcurrentHashMap<String, Logger>();
        // 初始化实现RootLogger
        org.apache.log4j.LogManager.getRootLogger();
    }

    public Logger getLogger(String name) {
        Logger slf4jLogger = loggerMap.get(name);
        if (slf4jLogger != null) {
            return slf4jLogger;
        } else {
            org.apache.log4j.Logger log4jLogger;
            // 如果是ROOT,则默认返回RootLogger
            if (name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))
                log4jLogger = LogManager.getRootLogger();
            else
            // 通过LogManager创建新的Logger,关键在这里
                log4jLogger = LogManager.getLogger(name);
            // 封装一层,再返回
            Logger newInstance = new Log4jLoggerAdapter(log4jLogger);
            Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
            return oldInstance == null ? newInstance : oldInstance;
        }
    }
    6)LogManager.getLogger(String name)
  public static Logger getLogger(final String name) {
     // Delegate the actual manufacturing of the logger to the logger repository.
    return getLoggerRepository().getLogger(name);
  }

  // 获取LoggerRepository
  public static LoggerRepository getLoggerRepository() {
    // 初始化的时候repositorySelector不会为null,由LogManager的static模块代码可知,代码块代码如下所示
    if (repositorySelector == null) {
        repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
        guard = null;
        Exception ex = new IllegalStateException("Class invariant violation");
        String msg =
                "log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload.";
        if (isLikelySafeScenario(ex)) {
            LogLog.debug(msg, ex);
        } else {
            LogLog.error(msg, ex);
        }
    }
    return repositorySelector.getLoggerRepository();
  }
     LogManager的static代码块
  static {
    // 由该代码可知,LoggerRepository默认为Hierarchy
    Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
    // repositorySelector的默认实现为DefaultRepositorySelector
    repositorySelector = new DefaultRepositorySelector(h);
    ...
  }
    7)LoggerRepository.getLogger(String name)
    默认的LoggerRepository可知是由Hierarchy实现的,故直接定位到Hierarchy.getLogger(String name)方法
  public Logger getLogger(String name) {
    return getLogger(name, defaultFactory);
  }

  
  public Logger getLogger(String name, LoggerFactory factory) {
    // 1.根据name封装一层对象,name相同即CategoryKey相同
    CategoryKey key = new CategoryKey(name);
    // Synchronize to prevent write conflicts. Read conflicts (in
    // getChainedLevel method) are possible only if variable
    // assignments are non-atomic.
    Logger logger;

    synchronized(ht) {
      Object o = ht.get(key);
      // 2.第一次创建时,为null,需新建
      if(o == null) {
      // 3.直接进行new Logger(name)操作
	logger = factory.makeNewLoggerInstance(name);
      // 设置Hierarchy,并放入HashTable,更新parent
	logger.setHierarchy(this);
	ht.put(key, logger);
	updateParents(logger);
	return logger;
     ...
      }
    }
  }
    由此可知,新创建的Logger由DefaultCategoryFactory创建,并封装一系列参数,并添加到HashTable中去

2.Logger.debug(Object message)源码分析
    由上述分析可知,本例中的Logger默认实现为org.apache.log4j.Logger

    1)logger.debug(Object message)
     org.apache.log4j.Logger继承了Category,主要实现都在org.apache.log4j.Category中,直接定位到Category.debug(Object message)中
  public void debug(Object message) {
    if(repository.isDisabled(Level.DEBUG_INT))
      return;    
    // 判断当前日志级别是否低于DEBUG,如果低于,则打印日志
    if(Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) {
      forcedLog(FQCN, Level.DEBUG, message, null);
    }
  }

  protected void forcedLog(String fqcn, Priority level, Object message, Throwable t) {
    callAppenders(new LoggingEvent(fqcn, this, level, message, t));
  }

  // 正在实现是这个方法
  public void callAppenders(LoggingEvent event) {
    int writes = 0;

    // 1.依次遍历当前Logger到其父Logger,一直到null为止
    for(Category c = this; c != null; c=c.parent) {
      synchronized(c) {
	if(c.aai != null) {
      // 2.c.aai为AppenderAttachableImpl aai ,一个Appender的集合类
      // 主要为了获取Appender集合后,依次执行doAppend方法
	  writes += c.aai.appendLoopOnAppenders(event);
	}
	if(!c.additive) {
	  break;
	}
      }
    }

    if(writes == 0) {
      repository.emitNoAppenderWarning(this);
    }
  }
    2)AppenderAttachableImpl.appendLoopOnAppenders(LoggingEvent event)
  public int appendLoopOnAppenders(LoggingEvent event) {
    int size = 0;
    Appender appender;

    if(appenderList != null) {
      size = appenderList.size();
      for(int i = 0; i < size; i++) {
        // 依次遍历获取Appender,然后执行相应的doAppend方法
	    appender = (Appender) appenderList.elementAt(i);
	    appender.doAppend(event);
      }
    }    
    return size;
  }
   
    3)Appender.doAppend(LoggingEvent event)
    由该例的log4j.xml可知,我们只定义了一个ConsoleAppender,故直接定位到ConsoleAppender.doAppend()方法
    ConsoleAppender多层次继承,可知,真正实 现的是 AppenderSkeleton类
 public synchronized void doAppend(LoggingEvent event) {
    ...
    // 抽象方法,实现类为其父类,WriterAppender
    this.append(event);    
  }

  // WriterAppender默认实现
  public void append(LoggingEvent event) {
    if(!checkEntryConditions()) {
      return;
    }
    subAppend(event);
   }

  
  protected void subAppend(LoggingEvent event) {
    // 真正实现在这 QuietWriter qw ,默认为一个FilterWriter
    // class QuietWriter extends FilterWriter
    // 在输出之前进行了layout包装
    this.qw.write(this.layout.format(event));

    if(layout.ignoresThrowable()) {
      String[] s = event.getThrowableStrRep();
      if (s != null) {
	int len = s.length;
	for(int i = 0; i < len; i++) {
	  this.qw.write(s[i]);
	  this.qw.write(Layout.LINE_SEP);
	}
      }
    }

    if(shouldFlush(event)) {
      this.qw.flush();
    }
  }
    由上可知,最终是使用了Writer来进行写操作
   
3.遗留问题
    通过代码分析,我们知道,所有的writer操作都是通过Appender进行的,Logger的Appender集合都存放在AppenderAttachableImpl中,那么AppenderAttachableImpl中的Appender集合是什么时候被放进去的呢?
    读者可先自行分析
    笔者将在下一篇博客中分析该问题。















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恐龙弟旺仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值