1.思考
容器是什么?
水壺是容器,水壺中存放著水,等我們需要水了,直接用
Spring中的ApplicationContext是容器,里面存放著各種Bean,等我們需要了直接用,并且可以創(chuàng)建管理Bean
Hierarchy是Log4j的容器,它里面存放著各種Logger? 用來管理各種Logger?
Hierarchy是什么?
從字面上看:
n. 層級(jí);等級(jí)制度。
log4j的文檔說明:
This class is specialized in retrieving loggers by name and also maintaining the logger hierarchy
用來根據(jù)名稱獲取Logger并維持logger等級(jí)??磥硎俏覀兿胂氲哪菢?,存放著各種Logger并管理,等我們需要的時(shí)候還可以從中獲取。
2.Hierarchy 容器
Hierarchy既然是容器,談到容器,就如上面所說的水壺、Spring中的ApplicationContext以及Java中的集合類。他們的核心功能就是存和取。

簡(jiǎn)單認(rèn)識(shí)下Hierarchy字段

2.1 存儲(chǔ)數(shù)據(jù)結(jié)構(gòu)
容器存的是Logger,每個(gè)Logger都有全局唯一的名稱,也可以說每個(gè)名稱只對(duì)應(yīng)一個(gè)Logger實(shí)例,所有Logger均?以名稱為key存儲(chǔ)在HashTable中,并且還根據(jù)名稱組裝成以RootLogger為根的一棵樹,樹的層次由Logger的name決定,以"."分隔。如下圖所示,HashTable和Logger中的parent維護(hù)了以RootLogger為根節(jié)點(diǎn)的樹。

由于Log4j允許先存放子節(jié)點(diǎn),然后再存放父節(jié)點(diǎn),這里就會(huì)涉及到子節(jié)點(diǎn)的父節(jié)點(diǎn)更細(xì)問題,?下面會(huì)分先存放父節(jié)點(diǎn)和子節(jié)點(diǎn)兩種情況進(jìn)行分析,在開始之前先來認(rèn)識(shí)下ProvisionNode.
ProvisionNode:
Provision類實(shí)際上就是一個(gè)Vector(通過繼承Vector實(shí)現(xiàn))。當(dāng)ChildLogger先建立,未能找到parent的時(shí)候,log4j會(huì)預(yù)先建立一個(gè)ProvisionNode,并將ChildLogger添加到ProvisionNode中,當(dāng)實(shí)際的ParentLogger創(chuàng)建時(shí),再將所有的ChildLogger從ProvisionNode轉(zhuǎn)移到Parent中.
2.1.1 先存放父節(jié)點(diǎn),再存放子節(jié)點(diǎn)
- 先存放RootLogger

- 再存放Logger(x),在HashTable中沒有找到對(duì)應(yīng)的Logger;調(diào)用LoggerFactory得到Logger(x),x的parent是Root

- 再存放Logger(x.y),在HashTable中沒有找到對(duì)應(yīng)的Logger;調(diào)用LoggerFactory得到Logger(x.y),x.y的parent有x、root,在HashTable中能找到x對(duì)應(yīng)的Logger,設(shè)置Logger(x.y)的parent為L(zhǎng)ogger(x)

-
再存放Logger(x.y.z),在HashTable中沒有找到對(duì)應(yīng)的Logger,調(diào)用LoggerFactory得到Logger(x.y.z);x.y.z的parent有x.y、x、root,在HashTable中能找到x.y對(duì)應(yīng)的Logger,設(shè)置Logger(x.y.z)的parent為L(zhǎng)ogger(x.y)
依次類推...
2.1.2 先存放子節(jié)點(diǎn),再存放父節(jié)點(diǎn)
- 先存放RootLogger

-
存放Logger(x.y.z)
查詢HashTable中不存在,Logger(x.y.z),創(chuàng)建Logger(x.y.z)
遍歷父節(jié)點(diǎn)x.y/x,不存在Logger(x.y)和Logger(x),創(chuàng)建P(x.y)和P(x),并添加Logger(x.y.z)到vector容器中,并存儲(chǔ)在HashTable中
沒有找到父節(jié)點(diǎn)對(duì)應(yīng)的Logger,設(shè)置Root為父節(jié)點(diǎn)

-
存放Logger(x.y)
查詢HashTable,得到P(x.y),創(chuàng)建Logger(x.y)
遍歷P(x.y)的Vector(存放子節(jié)點(diǎn))更新其parent
?遍歷Logger(x.y)父節(jié)點(diǎn)x,不存在Logger(x),則把Logger(x,y)添加到P(x)對(duì)應(yīng)的vector中
沒有找到Logger(x.y)父節(jié)點(diǎn)對(duì)應(yīng)的Logger,設(shè)置RootLogger為其父節(jié)點(diǎn)

-
存放Logger(x)
以此類推...
從上面的案例可以看出相同的名稱得到的Logger實(shí)例一定是相同,而且每個(gè)Logger都有一個(gè)Parent,根節(jié)點(diǎn)是RootLogger。
2.2 獲取Logger
我們常常用下面的代碼獲得Logger,相信通過上面的講解,你已經(jīng)知道怎么獲取的了。其實(shí)就是根據(jù)Class的完全限定名,去HashTable中獲取,如果不存在則創(chuàng)建,然后更新parent以及child.
private static Logger logger = Logger.getLogger(Test.Class);
參考