在上一篇文章里,我们故意遗漏了一个重要的接口,AppenderAttachable:
public interface AppenderAttachable { public void addAppender(Appender newAppender); public Enumeration getAllAppenders(); public Appender getAppender(String name); public boolean isAttached(Appender appender); void removeAllAppenders(); void removeAppender(Appender appender); void removeAppender(String name); }
顾名思义,继承该接口的类可以attach Appenders, Category类继承了这个借口,因此也提供了相应的API。我们在配置文件里面设置的Appender属性会在配置类中被加载到Logger:Category对象中。
然而在Category类中,并没有真正的实现这些API,它将之代理到了其AppenderAttachableImpl变量中。回到第一篇文章中的类图,我们可以知道, AppenderAttachableImpl类同样也继承了AppenderAttachable接口。仔细一看,这里其实用了一个代理模式。
而在AppenderAttachableImpl中,维护了一个Appender类型列表,而Appender则是真正做事的人。。。
public int appendLoopOnAppenders(LoggingEvent event) { int size = 0; Appender appender; if(appenderList != null) { size = appenderList.size(); for(int i = 0; i < size; i++) { appender = (Appender) appenderList.elementAt(i); appender.doAppend(event); } } return size; }
所以,我们回来看第一章的序列图,并不完整,我们现在来将之补全:
后面我们会继续补全这张图片。
Appender的具体实现类并不直接继承Appender,而是继承于Appender的一个抽象实现:AppenderSkeleton,这个类维护了Filter以及Layout的实例,你可以在Log4j配置项中找到Filter以及Layout, 这里不再赘述。 我们常见的XMLAppender,或者HTMLAppender都是继承于该类。