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的继承体系太比较我,不描述了,大家自己去看。说了这么多,大家再回头对照看下配置文件,是不是一下子明白了很多?


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值