欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Log4J源码分析(二)

程序员文章站 2022-07-05 09:57:46
...
转载:http://jmut.bokee.com/

接着来。
昨天说过,Category实现了AppenderAttachable接口,可以视为是Appender的容器,但是它又有私有域aai,且aai才是真正的Appender容器在,所以Category的容器方法是对aai上方法的包装,Category把对Appender的管理委托给了aai。
来看Category的addAppender方法:

/**
Add newAppender to the list of appenders of this
Category instance.
If newAppender is already in the list of
appenders, then it won't be added again.

*/
synchronized
public
void addAppender(Appender newAppender) {
 if(aai == null) {
  aai = new AppenderAttachableImpl();
 }
 aai.addAppender(newAppender);
 repository.fireAddAppenderEvent(this, newAppender);
}
明显,Category确实是委托了对Appender的管理给aai,但是
repository.fireAddAppenderEvent(this, newAppender);
在做什么呢?repository是什么?仓库,听起来像是个工厂,看看它的代码。repository是LoggerRepository接口类型,而LoggerRepository接口的注释说:
/**
A LoggerRepository is used to create and retrieve
Loggers. The relation between loggers in a repository
depends on the repository but typically loggers are arranged in a
named hierarchy.
In addition to the creational methods, a
LoggerRepository can be queried for existing loggers,
can act as a point of registry for events related to loggers.

@author Ceki Gülcü
@since 1.2 */
再由接口中的方法,可以看出这个接口也可以看作是一种容器,在这里面的Appender是有标识的,由方法:
public
abstract
void fireAddAppenderEvent(Category logger, Appender appender);
的签名可以看出这个标识是Category。
到这里,可以说在Category中至少有两个容器在管理Appender存储,aai上没有组织,repository里的Appender是有组织的。
猜想,aai是局部的容器,repository是全局的容器。
接下来分析Category的方法callAppenders:
/**
Call the appenders in the hierrachy starting at
this. If no appenders could be found, emit a
warning.
This method calls all the appenders inherited from the
hierarchy circumventing any evaluation of whether to log or not
to log the particular log request.

@param event the event to log. */
public
void callAppenders(LoggingEvent event) {
int writes = 0;

for(Category c = this; c != null; c=c.parent) {
 // Protected against simultaneous call to addAppender, removeAppender,...
 synchronized(c) {
  if(c.aai != null) {
   writes += c.aai.appendLoopOnAppenders(event);
  }
  if(!c.additive) {
   break;
  }
 }
}

if(writes == 0) {
repository.emitNoAppenderWarning(this);
}
}
这里面有几点要说。
第一,由c.aai.appendLoopOnAppenders(event)看出aai的确是做为局部容器在用,它只管理当前Category的Appender。
第二,additive决定是否要回溯,它控制是否要使用父类的Appender。
第三,对Category进行同步访问,因为Category是可以在多线程环境中使用的。
Category的方法:
/**
Starting from this category, search the category hierarchy for a
non-null level and return it. Otherwise, return the level of the
root category.
The Category class is designed so that this method executes as
quickly as possible.

*/
public
Level getEffectiveLevel() {
for(Category c = this; c != null; c=c.parent) {
if(c.level != null)
return c.level;
}
return null; // If reached will cause an NullPointerException.
}
从当前Category开始,向上寻找第一个有效的Level。
Category的使用入口是getInstance:
/**
* @deprecated Make sure to use {@link Logger#getLogger(String)} instead.
*/
public
static
Category getInstance(String name) {
return LogManager.getLogger(name);
}

/**
* @deprecated Please make sure to use {@link Logger#getLogger(Class)}
* instead.
*/
public
static
Category getInstance(Class clazz) {
return LogManager.getLogger(clazz);
}
它们把工作交给了LogManger类。