LoggerContext作用及初始化流程

根据我们在Log4j初识中的实例可以看出,在不适用日志门面插件slf4j的情况下,获取logger的方式一般为

Logger logger = logManager.getLogger(xx.class)

可以看到,通常情况下,我们会使用LogManager的静态方法getLogger方法获取logger,下面我们就简要看一下这个方法的流程。

public static Logger getLogger(final Class> clazz) {

final Class> cls = callerClass(clazz);

return getContext(cls.getClassLoader(), false).getLogger(toLoggerName(cls));

}

这个方法返回了一个链式调用后的结果,而首先是先调用了getContext,这个方法返回的是一个LoggerContext对象,该方法定义如下:

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);

}

}

这个方法中的LoggerContext是通过LoggerFactory的getContext方法,默认情况下,对应的子类是Log4jLoggerFactory。对应的方法如下:

public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, final boolean currentContext) {

//获得LoggerContex实例

final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext);

if (externalContext != null && ctx.getExternalContext() == null) {

ctx.setExternalContext(externalContext);

}

//启动LoggerContext

if (ctx.getState() == LifeCycle.State.INITIALIZED) {

ctx.start();

}

return ctx;

}

其中里面的主要逻辑是返回一个启动的LoggerContext实例,其中LoggerContext实例是通过Log4jLoggerFactory中的ContextSelector获取的,默认情况下使用的是ClassLoaderContextSelector,在Log4jLoggerFactory的构造方法中进行初始化。

完成初始化后,就是LoggerContext的启动,如果当前的context实例的状态为初始化状态,则调用start函数,其中的流程是

LogContext.start()—>LogContext.reconfigure()—>LogContext.reconfigure(URI)

其中主要做的事情就是根据配置文件的位置,读取相应的log4j2配置文件,解析配置文件,最终解析为各种Appender以及Logger的 Java 对象,下面我们来看大致的流程

首先会获取ConfigurationFactory的实例,然后获取Configuration,分别看这两步

1、获取ConfigurationFactory实例

public static ConfigurationFactory getInstance() {

// volatile works in Java 1.6+, so double-checked locking also works properly

//noinspection DoubleCheckedLocking

if (factories == null) {

LOCK.lock();

try {

if (factories == null) {

final List list = new ArrayList<>();

final String factoryClass = PropertiesUtil.getProperties().getStringProperty(CONFIGURATION_FACTORY_PROPERTY);

if (factoryClass != null) {

addFactory(list, factoryClass);

}

final PluginManager manager = new PluginManager(CATEGORY);

manager.collectPlugins();

final Map> plugins = manager.getPlugins();

final List> ordered = new ArrayList<>(plugins.size());

for (final PluginType> type : plugins.values()) {

try {

ordered.add(type.getPluginClass().asSubclass(ConfigurationFactory.class));

} catch (final Exception ex) {

LOGGER.warn("Unable to add class {}", type.getPluginClass(), ex);

}

}

Collections.sort(ordered, OrderComparator.getInstance());

for (final Class extends ConfigurationFactory> clazz : ordered) {

addFactory(list, clazz);

}

// see above comments about double-checked locking

//noinspection NonThreadSafeLazyInitialization

factories = Collections.unmodifiableList(list);

}

} finally {

LOCK.unlock();

}

}

LOGGER.debug("Using configurationFactory {}", configFactory);

return configFactory;

这是一个典型的单例模式,使用了双重检查锁的方式获取实例,这个方法里面有一个操作步骤我们要重点介绍,就是PluginManager实例的创建,PluginManager主要用于管理Log4J中的插件,这些Plugin主要是一些对应不同格式的配置文件的解析器,PluginManager中使用category对不同类型的插件进行缓存。

获取到ConfigurationFactory的实例之后,就是获取Configuration的过程,主要流程是根据配置的格式,从遍历上面提到列表中的factory,加载到对应的ConfigurationFactory,随后通过这个Factory去解析配置文件最终获取到Configuration。代码流程如下:

public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation, final ClassLoader loader) {

if (!isActive()) {

return null;

}

if (loader == null) {

return getConfiguration(loggerContext, name, configLocation);

}

if (isClassLoaderUri(configLocation)) {

final String path = extractClassLoaderUriPath(configLocation);

final ConfigurationSource source = ConfigurationSource.fromResource(path,loader);

if (source != null) {

final Configuration configuration = getConfiguration(loggerContext,source);

if (configuration != null) {

return configuration;

}

}

}

return getConfiguration(loggerContext, name, configLocation);

}

注意这里的getConfiguration(loggerContext,source);是一个多态方法,会根据不同类型的配置发文件,调用相应的ConfigureFactory的方法,将配置文件中的tag变为java对象。下一篇文章中,我会以 xml 类型的文件详细介绍将tag变化为Java对象的过程。

谢谢你请我吃糖果

log4j 源码解析_log4j2源码解析(2)--LoggerContext相关推荐

  1. Spark之SQL解析(源码阅读十)

    如何能更好的运用与监控sparkSQL?或许我们改更深层次的了解它深层次的原理是什么.之前总结的已经写了传统数据库与Spark的sql解析之间的差别.那么我们下来直切主题~ 如今的Spark已经支持多 ...

  2. wireshark协议解析器 源码分析 封装调用

    源码分析 Wireshark启动时,所有解析器进行初始化和注册.要注册的信息包括协议名称.各个字段的信息.过滤用的关键字.要关联的下层协议与端口(handoff)等.在解析过程,每个解析器负责解析自己 ...

  3. 图解VC++版PE文件解析器源码分析

    该源码下载自 http://download.csdn.net/download/witch_soya/4979587 1 Understand 分析的图表 2 PE结构解析的主要代码简要分析 首先看 ...

  4. Python源码剖析[16] —— Pyc文件解析

    Python源码剖析[16] -- Pyc文件解析 2008-02-28 18:29:55|  分类: Python |举报 |字号 订阅 Python源码剖析 --Pyc文件解析 本文作者: Rob ...

  5. 深入解析Java字节码和字节码操作类库ASM源码解析

    导语 在非黑即白的静态编译语言和动态脚本语言的分类方法中,java的立场显得很尴尬.首先java是静态强类型语言,所以java源代码是需要编译的.但是javac编译后的产出物并不是和传统的编译语言一样 ...

  6. linux源码文件名,Linux中文件名解析处理源码分析

    Linux中文件名解析处理源码分析 前言 Linux中对一个文件进行操作的时候,一件很重要的事情是对文件名进行解析处理,并且找到对应文件的inode对象,然后创建表示文件的file对象.在此,对文件名 ...

  7. spring 源码分析(1)-xml文件解析

    我们在最开始接触spring的时候,看到不少书spring入门的例子如下 ApplicationContext atx = new ClassPathXmlApplicationContext(&qu ...

  8. Spring 源码解析 -- SpringWeb请求映射解析

    Spring 源码解析 – SpringWeb请求映射解析 简介 基于上篇请求路径初步探索,了解到了一个请求到具体处理方法的大致路径,本篇就继续探索,看下路径是如何匹配到处理方法的 概览 基于上篇:S ...

  9. Java定时任务(一) Timer及TimerTask的案例解析及源码分析

    Java定时任务(一)  Timer及TimerTask的案例解析及源码分析 一.概述: 定时任务这个概念在Java的学习以及项目的开发中并不陌生,应用场景也是多种多样.比如我们会注意到12306网站 ...

最新文章

  1. python字符串27种常见的方法
  2. Spring框架的事务管理之基于AspectJ的XML方式(重点掌握)
  3. Learning Deep Structured Semantic Models for Web Search using Clickthrough Data (DSSM)
  4. 那些年,我们追过的java8
  5. 【Leaflet】鼠标提取坐标
  6. Pipeline模式(netty源码死磕6)
  7. WPF ComboBox下拉绑定Treeview 功能的实现
  8. saltstack2 grains模块
  9. Mac OS X安装 ffmpeg
  10. 深入了解 Loader
  11. Wannafly挑战赛9: B. 数一数
  12. 【C语言编程】实现猜数字游戏
  13. 【毕业设计】基于大数据的抖音短视频数据分析与可视化 - python 大数据 可视化
  14. Sloth组件之NetRisc.Configuration
  15. 推荐一款制作精良、功能强大、毫秒精度、专业级的定时任务执行软件 —— 定时执行专家
  16. OpenMP求PI的四种方式
  17. about Red_Hat_Enterprise_Linux_7
  18. 找不到dns linux,linux – 服务器找不到XXX.in-addr.arpa:NXDOMAIN
  19. mysql8022安装教程,oracle8i for unixware安装说明-数据库专栏,ORACLE
  20. 计算机网络——标准化

热门文章

  1. 《软件需求》阅读笔记之一
  2. 台式机也颤抖!ROG Strix S5AS性能强悍到底
  3. mac升级10.12后,安全和隐私中没有了安装任何来源的选项的解决办法
  4. 在日本做开发的日子(工作篇 序)
  5. 做网管这么久了,每个月只是拿1000元的工资
  6. 删除VS.NET起始页上项目名称的方法.
  7. OJ1059: 最高分(C语言)
  8. php flash 图片上传,Flash教程:flash+php实现图片上传
  9. java 判断 框架类型_第10章-验证框架 --- 验证器类型
  10. 175. 组合两个表