Log4j解惑之一

Log4j這個東東,大家一直都在用,可是真正有多少人知道,爲什麼要那樣配列?或者說有多少不抄襲可以自己配一份log4j列?讀者可以問問自己能否辦到。我們本章就一些重要的環節結合源碼進行分析。


一、Log4j是在那個地方讀取配置文件的?

在回答這個問題前,首先想想我們在程序中是怎麼用Log4j來打印日誌的?

1.獲取Logger,如

private static Logger logger = Logger.getLogger(App.class);
2.在方法中調用logger方法打印日誌

logger.info("this is the main Method");

於是我們跟進getLogger()方法查看實現,發現該方法如下定下:

 static
  public
  Logger getLogger(Class clazz) {
    return LogManager.getLogger(clazz.getName());
  }
他是委託LogManager去實現的。於是我們再次跟進LogManager,通過看查該類的結構,發現有個靜態的static初始塊,我們一讀代碼,發現原來Log4j的配置文件就是在這裏讀取的,而且他是先查找log4j.xml,如果查找不到再去查找log4j.properteis。

     其實還有一個解決這個問題的辦法,就是將log4j的源碼,以項目的形式導入eclipse/idea中,然後全局搜索log4j.properties或是log4j.xml。爲什麼想到搜這2個文件名?因爲log4j默認配置文件名就是這2個,那麼他在程序中,肯定會有常量來定義這個2個文件名,就算沒人常量,也會有直接根據這2個文件名加載配置的地方。這是一個程序開發者正常的邏輯,和處理辦法。


二、我們在log4j.properties中,經常都會配置一個log4j.rootLogger?它的作用是什麼?

我們在配置文件中,定主了rootLogger,Appender,Layout, 爲什麼我們程序中log就會按照這些規格來輸出列? 難道我們自己定義的Logger跟這這個rootLogger有什麼關係?

    其實從命名,我們是不是猜測到rootLogger,是我們定義的其它Logger的超類列? 事實上也確實如此!我們一路踏實getLogger()方法,一直跟蹤到了Hierarchy.getLogger();

public
  Logger getLogger(String name, LoggerFactory factory) {
    //System.out.println("getInstance("+name+") called.");
    CategoryKey key = new CategoryKey(name);
    // Synchronize to prevent write conflicts. Read conflicts (in
    // getChainedLevel method) are possible only if variable
    // assignments are non-atomic.
    Logger logger;

    synchronized(ht) {
      Object o = ht.get(key);
      if(o == null) {
	logger = factory.makeNewLoggerInstance(name);
	logger.setHierarchy(this);
	ht.put(key, logger);
	updateParents(logger);
	return logger;
      } else if(o instanceof Logger) {
	return (Logger) o;
      } else if (o instanceof ProvisionNode) {
	//System.out.println("("+name+") ht.get(this) returned ProvisionNode");
	logger = factory.makeNewLoggerInstance(name);
	logger.setHierarchy(this);
	ht.put(key, logger);
	updateChildren((ProvisionNode) o, logger);
	updateParents(logger);
	return logger;
      }
      else {
	// It should be impossible to arrive here
	return null;  // but let's keep the compiler happy.
      }
    }
  }

其實我們創建的Logger,都會存放到一個 命名爲ht 的HashTable中。最關鍵的是updateParents(logger);這個方法,於是我們進一步跟蹤這個方法,發現,如果一個Looger找不到父Logger,那麼
  if(!parentFound)
      cat.parent = root;
會將它的parent設爲rootLogger。  這個方法的具體代碼,我就不貼了,大家可以自己去看。那麼rootLogger的東西(Appender,Layout),是不是他可以直接繼承過來用列?


那麼關於rootLogger的繼承體系和依賴關係 ,我畫了一張比較簡單的uml草圖

(~~~~~~~~~~~~~~~~~~~圖片佔位,CSDN上傳圖片又掛掉了~~~~~~~~~~~~~~~~~~~~~~~)

上傳圖片試了N次都是掛掉了,只能簡單描述一下吧,或者大家進去看一下類結構吧

RootLogger繼承Logger,而Logger又繼承至Category。

Category裏面有個變量 AppenderAttachableImpl aai;  這個類就是封裝了一個 protected Vector  appenderList;來存放Appender。

由此可以看出Logger和Appender是 1:N的關係 


至於Appender的繼承體系太比較我,不描述了,大家自己去看。說了這麼多,大家再回頭對照看下配置文件,是不是一下子明白了很多?


發佈了110 篇原創文章 · 獲贊 22 · 訪問量 63萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章