log4j 源码解析

阅读: 评论:0

log4j 源码解析

log4j 源码解析

前言

在实际开发项目中,日志永远是一个绕不开的话题。本系列文章试图以slf4j和log4j2日志体系为例,从源码角度分析日志工作原理。

置加载过程为主线,描述其工作流程;影响不大的旁枝细节会忽略,有兴趣的读者可自行查阅源码。2.多图预警!用电脑查看效果更佳。3.尽量动手操作,以加深理解。 环境准备阅读源码前,请确保引入了sl

学习日志框架,首先要熟悉各类日志框架,这里推荐两篇文章,就不再赘述了。

我们会拿到一个AppClassLoader,LogManager会利用这个类加载器获取上下文。进入getContext看看:请注意:这里的factory是Log4jContextFactory,它是在

对于log4j2,配置文件有几类:properties、xml、json/jsn以及yaml/yml,平常我们用xml居多。

Factory:接下来,我们进入log4j2的getLogger环节。可以看到getLogger是个接口方法,并且有3个实现。还记得我们刚才获取到的Log4jLoggerFactory吗?Abstra

一般情况下,我们会创建l放到项目的/resources文件夹下。大部分使用maven管理依赖的项目也可能分环境配置,不同环境读取不同的log4j2文件,这时它一般在/profiles/${env}/文件夹下。

怎么初始化的?其实,在调用Context(cl,false);之前,LoggerManager中的静态代码块会提前被调用,我们看一下: 我们看89~100行代码即

大多数人,应该是“借鉴”其他项目,把配置复制过来,再修修补补。然而你是否思考过:

eAttr,intdefStyleRes)这个构造方法对比构造方法三就多了一个参数defStyleRes这个参数的作用就是再提供一个给View提供默认属性的手段。defStyleRes就是把一些我们想

为什么要写这个配置文件?不写的话会出什么问题?

这个配置文件的命名有什么规定吗?为什么我们平时见到的都是l,而不是其他名字?

这个配置文件是如何被加载的?

回答以上问题,就是本文的初衷。

度分析日志工作原理。学习日志框架,首先要熟悉各类日志框架,这里推荐两篇文章,就不再赘述了。.html

提示

1. 本文会用调试的方法,以log4j2配置加载过程为主线,描述其工作流程;影响不大的旁枝细节会忽略,有兴趣的读者可自行查阅源码。

这里使用饿汉方式实现了单例。41行实例化StaticLoggerBinder,会跳到53行,我们进去看看细节。可以看出Log4jLoggerFactory继承了AbstractLoggerAdapte

2. 多图预警!用电脑查看效果更佳。

法内部: 现在,url已经获取到了。它的值是"项目路径/target/l"。后面的事情就是从文件加载内容(517行,涉及到类加载器的知识,请自行查看)。再然

3. 尽量动手操作,以加深理解。

个Button类在调用这个构造函数的时候会给defStyleAttr赋予一个默认的值R.attr.buttonStyle这个值包含了Button的一些基本的风格(会在Theme中给出),比如:最小宽度

2.7

artifactId>2.7

明,可自行查看。接下来,进入getConfiguration方法:进入该方法:请注意,这里的getFactories已经很明显地告诉我们,这里有4个工厂(均继承自ConfigurationFactor

对应的生成xml中定义的View的时候调用的。剩下的两个构造方法,大家了解的就比较少了。一般在自定义View的时候都会不加思索的按照固定的写法。那么你有没有想探究一下里面的关系呢?构造方法View(C

/profiles/${env}/文件夹下。大多数人,应该是“借鉴”其他项目,把配置复制过来,再修修补补。然而你是否思考过:为什么要写这个配置文件?不写的话会出什么问题?这个配

用方式见上面button,主题中设置不同的类型,View的默认风格会发生改变。通过defStyleRes设置属性这种方式是直接在代码中指定一个默认的style,和Context的主题没有关系在Them

环境准备

阅读源码前,请确保引入了slf4j和log4j2依赖包,以及适配包。以maven为例,本文示例程序引入了:

建一个java文件,打断点开始调试。进入getLogger方法。可以看到,在LoggerFactory获取具体的Logger工厂。进入getILoggerFactory方法。这里的一堆逻辑先不要管,我

org.slf4j

slf4j-api

1.7.21

org.apache.logging.log4j

log4j-slf4j-impl

2.7

org.apache.logging.log4j

log4j-core

2.7

org.apache.logging.log4j

log4j-api

2.7

源码

首先,我们新建一个java文件,打断点开始调试。

条件拼接处配置文件的名字。 以最常见的l为例:上图中,我们已经得到了配置文件的名字&#l。同时可以看到,prefix为log4j2,suffix为文件后缀。

进入getLogger方法。可以看到,在LoggerFactory获取具体的Logger工厂。

l中使用CustomTextView第三步:运行程序,查看结果可以看到xml中定义的5个属性全部打印出来。因此AttributeSet对应的就是xml布局文件中定义的属性给View提供样式的方式直接通

进入getILoggerFactory方法。

行:这里尝试用不同的条件获取config,如果最终config为null,就会打印error日志,告诉你没有找到配置文件。由于目前我们还没有配置,就会走到466行。 现在,你可以在/reso

这里的一堆逻辑先不要管,我们最终会进入418行。

符合规范!构造方法View(Contextcontext,@NullableAttributeSetattrs)这个构造方法是我们最常用的,当我们在xml中定义了View然后在代码中使用这个View的

接下来进入真正的日志绑定环节。由于我们只引入了log4j2,这里会直接找到它,继而绑定。StaticLoggerBinder就在log4j2的包中。

工厂(均继承自ConfigurationFactory ),分别处理前文提到的四类配置文件类型:properties、xml、json/jsn以及yaml/yml。调用

程序走到61行,可以看到这里使用饿汉方式实现了单例。41行实例化StaticLoggerBinder,会跳到53行,我们进去看看细节。

lt;groupId>org.slf4jslf4j-api

可以看出Log4jLoggerFactory继承了AbstractLoggerAdapter这个抽象的日志适配器。这个抽象适配器中定义了若干方法,别急,马上会提及。

ore.impl.Log4jContextFactory。接着往下走:可以看到这里会用反射的方式实例化Log4jContextFactory对象,会调用Log4jContextFactory的无参构造

回到LoggerFactory,通过方法getLoggerFactory,我们会得到刚刚创建出来的Log4jLoggerFactory:

改变了原始的风格,是最优先于xml中的属性的。其实我们使用的很多系统View都是通过这种方式来,这里用Button来举个例子可以看到Button在使用第三个构造函数的时候,传入了com.android

接下来,我们进入log4j2的getLogger环节。

hor为"",因此会进入后面的语句。最终,我们会拿到一个AppClassLoader,LogManager会利用这个类加载器获取上下文。进入getContext看看:请注意:这里的factory是Lo

可以看到getLogger是个接口方法,并且有3个实现。

View对象是有默认的属性值的。第三个构造函数:这个构造函数就是相对于第二个构造函数,多提供了一种给View添加默认属性的方式,通过deftStyleAttr如果没有默认的值,就用0。这样做的好处就是

还记得我们刚才获取到的Log4jLoggerFactory吗?AbstractLoggerAdapter是它的父类,由此我们会走到AbstractLoggerAdapter的getLogger中。

同环境读取不同的log4j2文件,这时它一般在/profiles/${env}/文件夹下。大多数人,应该是“借鉴”其他项目,把配置复制过来,再修修补补。然而你是否思考过:为什么

getContext是AbstractLoggerAdapter的抽象方法,因此,我们下一步会走到Log4jLoggerFactory的getContext方法中。

可:进入方法Providers()内部查看:可以看到provider是使用懒汉方式实现的单例(你会发现89行代码中ProviderUtil.hasProviders()

这里用反射定位到我们的日志(anchor中文译为"锚",可以理解为类似文件句柄一类的东西),这里得出的anchor为"",因此会进入后面的语句。

wwwblogs/chanshuyi/p/something_about_java_log_framework.html对于log4j2,配置文件有几类:properties、xml、j

最终,我们会拿到一个AppClassLoader,LogManager会利用这个类加载器获取上下文。

后,就是读取xml文件的内容啦:走到这里,就开始读取xml文件了。这部分内容且待下回分解。  遗留问题:LoggerManager的factory及其内部的selector是怎么初

进入getContext看看:

,最大宽度等等基础风格。当然这些值我们都可以在xml中通过属性直接改变。构造方法View(Contextcontext,@NullableAttributeSetattrs,intdefStyleAt

请注意:这里的factory是Log4jContextFactory,它是在LogManager中的静态代码块中初始化的,具体细节后面会补充。

们最终会进入418行。接下来进入真正的日志绑定环节。由于我们只引入了log4j2,这里会直接找到它,继而绑定。StaticLoggerBinder就在log4j2的包中。程序走到61行,可以看到这里使

现在,我们先进入getContext看看:

其中prefix(505行)是写死在ConfigurationFactory中的:所以,我们配置时定义的文件名,需要遵循规范,而不能随意命名。 现在有了配置文件名,就可以加载了:进入方法内部

这里的getContext是ContextSelector接口中的方法,下一步会进入ClassLoaderContextSelector中的getContext中。至于slector是怎么初始化的,我们放在后面一起说。

过xml中的属性这种方式是最直接的,体现形式就是直接在布局中设置属性,在xml布局文件中使用style也属于这种方式通过deftStyleAttr设置属性这种方式主要是用来设置默认属性风格的,使用方式

下面几步都是上下文相关操作,不再贴出,最终会回到这里:

urces路径下增加一个log4j2文件,填写一下简单配置,就会在459行得到config了。我们来看看getConfiguration的细节:  可以看出,这里就是按照各种条件拼

然后走到152行的ctx.start方法,进去看下:

是这些属性的集合,包含了属性名和属性值。举例说明:第一步:定义CustomTextView可以看到,我在第二个构造函数中把AttributeSet的name和value都打印出来了。第二步:xml中使

到现在,终于要开始加载配置了!!!

SupportedTypes()方法即可获取到各类后缀。以xml为例:其他类型文件同理。好了,回到加载配置的方法,可以看到426行代码判断是否支持所有文件类型。其实最终的核心代码是453~467行:这

接下来几步比较直观,贴图示意:

ew的时候调用的,第二个构造方法使用最广泛,是对应的生成xml中定义的View的时候调用的。剩下的两个构造方法,大家了解的就比较少了。一般在自定义View的时候都会不加思索的按照固定的写法。那么你有没

在这里,先创建ConfigurationFactory的实例,然后获取配置。至于ConfigurationFactory的实例创建,这里不再说明,可自行查看。

ationFactory的实例创建,这里不再说明,可自行查看。接下来,进入getConfiguration方法:进入该方法:请注意,这里的getFactories已经很明显地告诉我们,这里有4个工厂(

接下来,进入getConfiguration方法:

4j2日志配置加载的主线(忽略了很多细节,比如可以配置path等等),后续的文章将会进一步描述配置文件的解析过程。 希望读者通过本文,能够对log4j2的配置加载过程有更为深入的理解。&nb

进入该方法:

slf4j-api1.7.21&

请注意,这里的getFactories已经很明显地告诉我们,这里有4个工厂(均继承自ConfigurationFactory ),分别处理前文提到的四类配置文件类型:properties、xml、json/jsn以及yaml/yml。调用SupportedTypes()方法即可获取到各类后缀。以xml为例:

ctory。接着往下走:可以看到这里会用反射的方式实例化Log4jContextFactory对象,会调用Log4jContextFactory的无参构造器:createContextSelector

其他类型文件同理。

载过程为主线,描述其工作流程;影响不大的旁枝细节会忽略,有兴趣的读者可自行查阅源码。2.多图预警!用电脑查看效果更佳。3.尽量动手操作,以加深理解。 环境准备阅读源码前,请确保引入了slf4

好了,回到加载配置的方法,可以看到426行代码判断是否支持所有文件类型。其实最终的核心代码是453~467行:

会拿到一个AppClassLoader,LogManager会利用这个类加载器获取上下文。进入getContext看看:请注意:这里的factory是Log4jContextFactory,它是在Lo

这里尝试用不同的条件获取config,如果最终config为null,就会打印error日志,告诉你没有找到配置文件。由于目前我们还没有配置,就会走到466行。

:这个构造函数就是相对于第二个构造函数,多提供了一种给View添加默认属性的方式,通过deftStyleAttr如果没有默认的值,就用0。这样做的好处就是,我们可以默认一个View的基础风格。比如可以

2.7

artifactId>2.7

明,可自行查看。接下来,进入getConfiguration方法:进入该方法:请注意,这里的getFactories已经很明显地告诉我们,这里有4个工厂(均继承自ConfigurationFactor

对应的生成xml中定义的View的时候调用的。剩下的两个构造方法,大家了解的就比较少了。一般在自定义View的时候都会不加思索的按照固定的写法。那么你有没有想探究一下里面的关系呢?构造方法View(C

/profiles/${env}/文件夹下。大多数人,应该是“借鉴”其他项目,把配置复制过来,再修修补补。然而你是否思考过:为什么要写这个配置文件?不写的话会出什么问题?这个配

用方式见上面button,主题中设置不同的类型,View的默认风格会发生改变。通过defStyleRes设置属性这种方式是直接在代码中指定一个默认的style,和Context的主题没有关系在Them

现在,你可以在/resources路径下增加一个log4j2文件,填写一下简单配置,就会在459行得到config了。我们来看看getConfiguration的细节:

我们会走到AbstractLoggerAdapter的getLogger中。getContext是AbstractLoggerAdapter的抽象方法,因此,我们下一步会走到Log4jLoggerFa

可以看出,这里就是按照各种条件拼接处配置文件的名字。

yle赋值给defStyleRes就可以了。四个构造函数总结第一个构造函数:这个构造函数就是在代码中直接newview的时候使用,这样出来的View默认是没有任何的属性值,需要后面自己手动set。第二

以最常见的l为例:

yi/p/something_about_java_log_framework.html对于log4j2,配置文件有几类:properties、xml、json/jsn以及yaml/yml,平常我们用

上图中,我们已经得到了配置文件的名字&#l。

始读取xml文件了。这部分内容且待下回分解。  遗留问题:LoggerManager的factory及其内部的selector是怎么初始化的?其实,在调用

同时可以看到,prefix为log4j2,suffix为文件后缀。

xml中通过属性直接改变。构造方法View(Contextcontext,@NullableAttributeSetattrs,intdefStyleAttr,intdefStyleRes)这个构造方

其中prefix(505行)是写死在ConfigurationFactory中的:

所以,我们配置时定义的文件名,需要遵循规范,而不能随意命名。

环节。由于我们只引入了log4j2,这里会直接找到它,继而绑定。StaticLoggerBinder就在log4j2的包中。程序走到61行,可以看到这里使用饿汉方式实现了单例。41行实例化Static

现在有了配置文件名,就可以加载了:

gurationFactory中的:所以,我们配置时定义的文件名,需要遵循规范,而不能随意命名。 现在有了配置文件名,就可以加载了:进入方法内部: 现在,url已经获取到了。它的值

进入方法内部:

现在,url已经获取到了。它的值是"项目路径/target/l"。

rtifactId>2.7源码首先,我们新建一个java文件,打断点开始调试。进入getLog

后面的事情就是从文件加载内容( 517行,涉及到类加载器的知识,请自行查看)。

一下简单配置,就会在459行得到config了。我们来看看getConfiguration的细节:  可以看出,这里就是按照各种条件拼接处配置文件的名字。 以最常见的lo

再然后,就是读取xml文件的内容啦:

规范!构造方法View(Contextcontext,@NullableAttributeSetattrs)这个构造方法是我们最常用的,当我们在xml中定义了View然后在代码中使用这个View的时候

走到这里,就开始读取xml文件了。这部分内容且待下回分解。

各类后缀。以xml为例:其他类型文件同理。好了,回到加载配置的方法,可以看到426行代码判断是否支持所有文件类型。其实最终的核心代码是453~467行:这里尝试用不同的条件获取config,如果最终c

2.7

artifactId>2.7

明,可自行查看。接下来,进入getConfiguration方法:进入该方法:请注意,这里的getFactories已经很明显地告诉我们,这里有4个工厂(均继承自ConfigurationFactor

对应的生成xml中定义的View的时候调用的。剩下的两个构造方法,大家了解的就比较少了。一般在自定义View的时候都会不加思索的按照固定的写法。那么你有没有想探究一下里面的关系呢?构造方法View(C

/profiles/${env}/文件夹下。大多数人,应该是“借鉴”其他项目,把配置复制过来,再修修补补。然而你是否思考过:为什么要写这个配置文件?不写的话会出什么问题?这个配

用方式见上面button,主题中设置不同的类型,View的默认风格会发生改变。通过defStyleRes设置属性这种方式是直接在代码中指定一个默认的style,和Context的主题没有关系在Them

遗留问题:LoggerManager的factory及其内部的selector是怎么初始化的?

其实,在调用Context(cl, false);之前,LoggerManager中的静态代码块会提前被调用,我们看一下:

yleRes,说白了就是多了一种提供View默认属性的一种方式。这种方式更加的简单,直接在代码中传入R.style.XX就可以了。如果没有默认值的话就为0。这个参数只有defStyleAttr为0的时

2.7

artifactId>2.7

明,可自行查看。接下来,进入getConfiguration方法:进入该方法:请注意,这里的getFactories已经很明显地告诉我们,这里有4个工厂(均继承自ConfigurationFactor

对应的生成xml中定义的View的时候调用的。剩下的两个构造方法,大家了解的就比较少了。一般在自定义View的时候都会不加思索的按照固定的写法。那么你有没有想探究一下里面的关系呢?构造方法View(C

/profiles/${env}/文件夹下。大多数人,应该是“借鉴”其他项目,把配置复制过来,再修修补补。然而你是否思考过:为什么要写这个配置文件?不写的话会出什么问题?这个配

用方式见上面button,主题中设置不同的类型,View的默认风格会发生改变。通过defStyleRes设置属性这种方式是直接在代码中指定一个默认的style,和Context的主题没有关系在Them

我们看89~100行代码即可:

可以配置path等等),后续的文章将会进一步描述配置文件的解析过程。 希望读者通过本文,能够对log4j2的配置加载过程有更为深入的理解。 最后,作者水平有限,难免错漏,欢迎指正及

进入方法Providers()内部查看:

ifactId>slf4j-api1.7.21

可以看到provider是使用懒汉方式实现的单例(你会发现89行代码中ProviderUtil.hasProviders()方法执行时已经创建过了,因此这里直接返回。注意创建过程有个细节,后面要用到),用于确定各个factory的优先级。

来,这里用Button来举个例子可以看到Button在使用第三个构造函数的时候,传入了com.android.internal.R.attr.buttonSyle这个属性,这个属性我们在属性定义文件a

我们重点看91行代码内部细节:

节会忽略,有兴趣的读者可自行查阅源码。2.多图预警!用电脑查看效果更佳。3.尽量动手操作,以加深理解。 环境准备阅读源码前,请确保引入了slf4j和log4j2依赖包,以及适配包。以mave

在96行,加载class,98行又将其转换为LoggerContextFactory的子类(也就是Log4jContextFactory)。

一种给View添加默认属性的方式,通过deftStyleAttr如果没有默认的值,就用0。这样做的好处就是,我们可以默认一个View的基础风格。比如可以在defSyleAttr中设置背景颜色,字体大小

那么问题来了,className是啥,为啥它指定了Log4jContextFactory?

数人,应该是“借鉴”其他项目,把配置复制过来,再修修补补。然而你是否思考过:为什么要写这个配置文件?不写的话会出什么问题?这个配置文件的命名有什么规定吗?为什么我们平时见到的都

其实,在前面创建Provider实例时,构造器中会读取log4j-core中的配置文件,其中就包含className对应的属性:

er的getLogger中。getContext是AbstractLoggerAdapter的抽象方法,因此,我们下一步会走到Log4jLoggerFactory的getContext方法中。这里用反

就这样,得到了className:org.apache.impl.Log4jContextFactory。

bsp; 遗留问题:LoggerManager的factory及其内部的selector是怎么初始化的?其实,在调用Context(cl,false);之前,Lo

接着往下走:

ntextcontext,@NullableAttributeSetattrs,intdefStyleAttr,intdefStyleRes)这个构造方法对比构造方法三就多了一个参数defStyleR

可以看到这里会用反射的方式实例化Log4jContextFactory对象,会调用Log4jContextFactory的无参构造器:

到它,继而绑定。StaticLoggerBinder就在log4j2的包中。程序走到61行,可以看到这里使用饿汉方式实现了单例。41行实例化StaticLoggerBinder,会跳到53行,我们进去

createContextSelector方法,就会初始化selector啦:

提供了默认的defStyleAttr用于指定基本的属性。也就是允许View有自己基础的风格。例如:一个Button类在调用这个构造函数的时候会给defStyleAttr赋予一个默认的值R.attr.b

后续的初始化细节就不再展开啦。

>2.7源码首先,我们新建一个java文件,打断点开始调试。进入getLogger方法。可以看到,在LoggerFactor

最后会走到这里:

我们来看看getConfiguration的细节:  可以看出,这里就是按照各种条件拼接处配置文件的名字。 以最常见的l为例:上图中,我们已经得到了配置

至此,factory创建完毕。

看到,我在第二个构造函数中把AttributeSet的name和value都打印出来了。第二步:xml中使用CustomTextView第三步:运行程序,查看结果可以看到xml中定义的5个属性全部打印

2.7

artifactId>2.7

明,可自行查看。接下来,进入getConfiguration方法:进入该方法:请注意,这里的getFactories已经很明显地告诉我们,这里有4个工厂(均继承自ConfigurationFactor

对应的生成xml中定义的View的时候调用的。剩下的两个构造方法,大家了解的就比较少了。一般在自定义View的时候都会不加思索的按照固定的写法。那么你有没有想探究一下里面的关系呢?构造方法View(C

/profiles/${env}/文件夹下。大多数人,应该是“借鉴”其他项目,把配置复制过来,再修修补补。然而你是否思考过:为什么要写这个配置文件?不写的话会出什么问题?这个配

用方式见上面button,主题中设置不同的类型,View的默认风格会发生改变。通过defStyleRes设置属性这种方式是直接在代码中指定一个默认的style,和Context的主题没有关系在Them

现在,你应该可以回答文首的三个问题了吧?

总结

本文通过调试,描述了log4j2日志配置加载的主线(忽略了很多细节,比如可以配置path等等),后续的文章将会进一步描述配置文件的解析过程。

下的两个构造方法,大家了解的就比较少了。一般在自定义View的时候都会不加思索的按照固定的写法。那么你有没有想探究一下里面的关系呢?构造方法View(Contextcontext)最简单的构造方法,当

希望读者通过本文,能够对log4j2的配置加载过程有更为深入的理解。

属性的一种方式。这种方式更加的简单,直接在代码中传入R.style.XX就可以了。如果没有默认值的话就为0。这个参数只有defStyleAttr为0的时候才会生效。关于AttributeSet我们在x

2.7

artifactId>2.7

明,可自行查看。接下来,进入getConfiguration方法:进入该方法:请注意,这里的getFactories已经很明显地告诉我们,这里有4个工厂(均继承自ConfigurationFactor

对应的生成xml中定义的View的时候调用的。剩下的两个构造方法,大家了解的就比较少了。一般在自定义View的时候都会不加思索的按照固定的写法。那么你有没有想探究一下里面的关系呢?构造方法View(C

/profiles/${env}/文件夹下。大多数人,应该是“借鉴”其他项目,把配置复制过来,再修修补补。然而你是否思考过:为什么要写这个配置文件?不写的话会出什么问题?这个配

用方式见上面button,主题中设置不同的类型,View的默认风格会发生改变。通过defStyleRes设置属性这种方式是直接在代码中指定一个默认的style,和Context的主题没有关系在Them

最后,作者水平有限,难免错漏,欢迎指正及交流,共同进步。

ration方法:进入该方法:请注意,这里的getFactories已经很明显地告诉我们,这里有4个工厂(均继承自ConfigurationFactory ),分别处理前文提到的四类配置文件

本文发布于:2024-02-01 16:09:10,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170677495137835.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:源码   log4j
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23