log4j 源码解析_log4j2源码解析(2)--LoggerContext
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相关推荐
- Spark之SQL解析(源码阅读十)
如何能更好的运用与监控sparkSQL?或许我们改更深层次的了解它深层次的原理是什么.之前总结的已经写了传统数据库与Spark的sql解析之间的差别.那么我们下来直切主题~ 如今的Spark已经支持多 ...
- wireshark协议解析器 源码分析 封装调用
源码分析 Wireshark启动时,所有解析器进行初始化和注册.要注册的信息包括协议名称.各个字段的信息.过滤用的关键字.要关联的下层协议与端口(handoff)等.在解析过程,每个解析器负责解析自己 ...
- 图解VC++版PE文件解析器源码分析
该源码下载自 http://download.csdn.net/download/witch_soya/4979587 1 Understand 分析的图表 2 PE结构解析的主要代码简要分析 首先看 ...
- Python源码剖析[16] —— Pyc文件解析
Python源码剖析[16] -- Pyc文件解析 2008-02-28 18:29:55| 分类: Python |举报 |字号 订阅 Python源码剖析 --Pyc文件解析 本文作者: Rob ...
- 深入解析Java字节码和字节码操作类库ASM源码解析
导语 在非黑即白的静态编译语言和动态脚本语言的分类方法中,java的立场显得很尴尬.首先java是静态强类型语言,所以java源代码是需要编译的.但是javac编译后的产出物并不是和传统的编译语言一样 ...
- linux源码文件名,Linux中文件名解析处理源码分析
Linux中文件名解析处理源码分析 前言 Linux中对一个文件进行操作的时候,一件很重要的事情是对文件名进行解析处理,并且找到对应文件的inode对象,然后创建表示文件的file对象.在此,对文件名 ...
- spring 源码分析(1)-xml文件解析
我们在最开始接触spring的时候,看到不少书spring入门的例子如下 ApplicationContext atx = new ClassPathXmlApplicationContext(&qu ...
- Spring 源码解析 -- SpringWeb请求映射解析
Spring 源码解析 – SpringWeb请求映射解析 简介 基于上篇请求路径初步探索,了解到了一个请求到具体处理方法的大致路径,本篇就继续探索,看下路径是如何匹配到处理方法的 概览 基于上篇:S ...
- Java定时任务(一) Timer及TimerTask的案例解析及源码分析
Java定时任务(一) Timer及TimerTask的案例解析及源码分析 一.概述: 定时任务这个概念在Java的学习以及项目的开发中并不陌生,应用场景也是多种多样.比如我们会注意到12306网站 ...
最新文章
- python字符串27种常见的方法
- Spring框架的事务管理之基于AspectJ的XML方式(重点掌握)
- Learning Deep Structured Semantic Models for Web Search using Clickthrough Data (DSSM)
- 那些年,我们追过的java8
- 【Leaflet】鼠标提取坐标
- Pipeline模式(netty源码死磕6)
- WPF ComboBox下拉绑定Treeview 功能的实现
- saltstack2 grains模块
- Mac OS X安装 ffmpeg
- 深入了解 Loader
- Wannafly挑战赛9: B. 数一数
- 【C语言编程】实现猜数字游戏
- 【毕业设计】基于大数据的抖音短视频数据分析与可视化 - python 大数据 可视化
- Sloth组件之NetRisc.Configuration
- 推荐一款制作精良、功能强大、毫秒精度、专业级的定时任务执行软件 —— 定时执行专家
- OpenMP求PI的四种方式
- about Red_Hat_Enterprise_Linux_7
- 找不到dns linux,linux – 服务器找不到XXX.in-addr.arpa:NXDOMAIN
- mysql8022安装教程,oracle8i for unixware安装说明-数据库专栏,ORACLE
- 计算机网络——标准化