分享
 
 
 

Log4j源代码阅读—Logger创建

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

一、Log4j中Logger的层次结构

Log4j中的Logger是以一个双向树的结构来组织的,但是Log4j却不是用通常使用的叶子结点和树枝结点来组织的。Log4j中使用了虚拟结点(ProvisionNode)和Logger(Logger)结点两种组织树的结构。

用户真正创建的Logger结点用真正的Logger结点表示,而Logger结点的祖先却可能不是真正的Logger,为了提升Log4j的效率这里用一个简单的Vector来代替。

ProvisionNode继承至Vector,并提供了一个接受一个Logger的构造方法。在Log4j的层次结构中仅仅是一个站位符。注意:ProvisionNode保存所有子Logger的实例。

如果一个Logger的父Logger为虚拟结点(ProvisionNode),则其父Logger为RootLogger。

二、Log4j中层次结构的作用

1、使每一个层次中确定的结点只有一个Logger实例,减少Logger的内存消耗。

2、使层次底层的Logger可以基层其祖先的等级。不用每个Logger都设置等级,并在底层Logger没有设置等级的情况下,可以一次性从祖先Logger中直接将Logger关闭(将祖先Logger的等级设为OFF)。

实现方法:从自己开始向祖先方法访问各Logger的等级,直到访问到一个不为空的。如果父Logger为虚拟结点(ProvisionNode),则其父Logger为RootLogger。

3、使层次底层的Logger可以基层其祖先的Appender。不用每个Logger都设置Appender,并在底层Logger没有设置Appender的情况下,可以一次性从祖先Logger中直接将更换Logger的Appender。

实现方法:从自己开始向祖先方法访问各Logger的Appenders。如果继承属性(additive)为false,则在调用了自己所有的Appender后,就直接跳出循环。

4、

三、Log4j中Logger的创建

1、所有Logger的创建最总都会发送到接口LoggerRepository的getLogger()方法中。Log4j中对此接口的实现是Hierarchy。Hierarchy中提供的创建过程如下:

2、判断在Logger容器中是否已经存在此名称的Logger。可能有如下三种情况

1)、不存在,已用工厂方法创建一个新Logger,设置Logger的repository属性,将Logger放入Logger容器中,调用updateParents()方法更新Logger的层次结构。

2)、存在且类型为Logger,直接返回该Logger。

3)、存在且类型为ProvisionNode,设置Logger的repository属性,将Logger放入Logger容器中,调用updateChildren()方法和updateParents()方法更新Logger的层次结构。

3、updateParents(Logger)方法。更新父Logger的层次结构。

尝试取得祖先Logger的实例,可能存在如下情况

1)、如果父Logger存在,且类型为Logger,则设置为本Logger的父Logger。跳出循环。

2)、如果父Logger存在,且类型为ProvisionNode,则将本Logger添加到ProvisionNode中,然后继续循环。

3)、如果父Logger不存在,就创建相应的ProvisionNode,则将本Logger添加到ProvisionNode中,然后继续循环。

注意:当时2、3情况时继续循环非常重要,这是维系Logger等级的一个重要方法。这样的结果是“ProvisionNode保存所有子Logger的实例。”

4、updateChildren(ProvisionNode,Logger)方法。

遍历ProvisionNode中所有的Logger,将所有没有正常连接到自己真正的父Logger上的Logger的父Logger设置为新建的用以替代ProvisionNode的Logger。

5、

四、Log4j中Log层次总揽

1、如果一个Logger的所有父Logger类型为Logger:本Logger的父Logger直接指向父Logger。

2、如果一个Logger的所有父Logger类型为ProvisionNode:本Logger的父Logger指向RootLogger。

3、如果一个Logger的父Logger类型为ProvisionNode,但是祖先Logger中存在Logger。本Logger的父Logger指向所有祖先中最近的一个Logger。

五、Log4j中Log的打印过程

以Info()方法解析Log的打印过程。使用ConsoleAppender和PatternLayout。

1、首先调用LoggerRepository接口的isDisabled()方法,通过和设置的Threshold等级比较,判断本层次的Log等级(在Info()方法中是Level.INFO_INT)能否打印。如果不可以就直接退出。

2、调用getEffectiveLevel()方法遍历Logger的等级结构,找出本Logger的等级。并和本层次的Log等级(在Info()方法中是Level.INFO)比较,判断本Logger能否打印这个层次的Log。如果可以打印就调用forcedLog()方法。forcedLog()方法通过传入得参数生成一个LoggingEvent实例,然后调用callAppenders()方法。

3、callAppenders(LoggingEvent)方法通过AppenderAttachableImpl类,先遍历本Logger中所有的Appender并调用相应的doAppend()方法。如果本Logger关闭了继承开关,就直接退出循环,否则依次遍历所有祖先的Appender。最后判断写Log的次数,如果等于0就打印没有Appender错误履历。

4、AppenderAttachableImlp类实现了AppenderAttachable接口,并提供了一个Appender的聚集,和遍历聚集的方法appendLoopOnAppenders(LoggingEvent)。通过调用该方法可以以LoggingEvent为参数调用聚集中所有的Appender的doAppend方法打印履历。

5、ConsoleAppender的doAppend()方法的实现在其祖先类AppenderSkeleton上,在doAppend()方法中,首先判断Appender是否已经关闭,如果已经关闭就打印一条错误履历并返回。然后比较Appender的Threshold等级,如果不通过就直接返回。调用Filter对象进行Log过滤。如果不通过就直接放回。然后调用append()方法。

6、append()方法在ConsoleAppender的父类WriterAppender类中实现,它调用了本地的两个方法,checkEntryCoditions()判断Appender是否关闭,是否有Layout,输出的字符串是否为空。subAppned()方法实现真正的打印。

7、subAppend()方法首先调用Layout格式化输出字符串,然后输出。在判断Layout是否忽略Throwable,如果不忽略掉用event.getThrowableStrRep()方法获取堆栈信息,然后答应。最后判断Appender是否要立即刷新输入,如果是就刷新输出。

8、Over,结束一次完整的Log打印过程。不过怎么少了解释器的调用????

9、原来,还有Layout没有看。在PatternLayout类的format()方法中,PatternLayout类会将LoggingEvent交给PatternConverter抽象类的format()方法来处理。这个抽象类的format方法中,调用了抽象方法convert(),这个方法最简单的实现时在PatternParser.java的BasicPatternConverter类中。在BasicPatternConverter的convert方法的末尾调用了LoggingEvent的getRenderedMessage()方法,看名字就知道了,在这里进行对象的解释。

10、在LoggingEvent.getRenderedMessage()方法中,首先判断message是否是个字符串,如果是就直接返回String,如果不是就判断Logger的容器是否实现了RendererSupport接口。如果Logger容器实现了RendererSupport接口,就调用接口的getRendererMap()方法获取Renderer的一个聚集RendererMap,并调用他的findAndRender()方法。

11、RendererMap中的findAndRender()方法中,用message的class对象去掉用get()方法,以获取也这个类对应的Renderer。get()方法会从下向上依次查找RendererMap中是否有对应的Renderer,如果有就直接退出,否则返回defaultRenderer实例(调用对象的toString()方法)。

12、获取Renderer实例后,根据“面对抽象编程,而不面对实现编程。”显然我们使用ObjectRenderer接口,调用方法doRender(),解析对象,并返回一个String对象。

13、over!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有