前言:
针对于上篇文章 log4j_slf4j源码分析(上),有一个遗留问题,Logger类中域
AppenderAttachableImpl中的Appender集合是什么时候被添加进去的呢?
下面就跟随笔者一起来看看吧
从LoggerFactory获取Logger的地方开始分析,由前文可知,
Log4jLoggerFactory为其实现类
1.Log4jLoggerFactory.getLogger(String name)
public Logger getLogger(String name) {
Logger slf4jLogger = loggerMap.get(name);
if (slf4jLogger != null) {
return slf4jLogger;
} else {
org.apache.log4j.Logger log4jLogger;
if (name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))
log4jLogger = LogManager.getRootLogger();
else
// 从LogManager中获取Logger
log4jLogger = LogManager.getLogger(name);
Logger newInstance = new Log4jLoggerAdapter(log4jLogger);
Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
return oldInstance == null ? newInstance : oldInstance;
}
}
2.LogManager.getLogger(String name)
public static Logger getLogger(final String name) {
// Delegate the actual manufacturing of the logger to the logger repository.
return getLoggerRepository().getLogger(name);
}
static public LoggerRepository getLoggerRepository() {
// repositorySelector在static中有默认实现
if (repositorySelector == null) {
repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
guard = null;
Exception ex = new IllegalStateException("Class invariant violation");
String msg =
"log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload.";
if (isLikelySafeScenario(ex)) {
LogLog.debug(msg, ex);
} else {
LogLog.error(msg, ex);
}
}
return repositorySelector.getLoggerRepository();
}
static代码块实现
static private RepositorySelector repositorySelector;
static {
// 1.可知repositorySelector默认实现为DefaultRepositorySelector,而repositorySelector中的LoggerRepository repository域默认实现为Hierarchy
Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
repositorySelector = new DefaultRepositorySelector(h);
...
URL url = null;
if(configurationOptionStr == null) {
// 2.默认查找类路径下 log4j.xml文件
url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
if(url == null) {
url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
}
...
if(url != null) {
LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
try {
// 3.对log4j.xml的真正解析在此,而对RootLogger中的AppenderAttachableImpl aai域的封装也是在此
OptionConverter.selectAndConfigure(url, configuratorClassName,
LogManager.getLoggerRepository());
...
}
3.OptionConverter.selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy)
static public void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {
Configurator configurator = null;
String filename = url.getFile();
if(clazz == null && filename != null && filename.endsWith(".xml")) {
clazz = "org.apache.log4j.xml.DOMConfigurator";
}
if(clazz != null) {
LogLog.debug("Preferred configurator class: " + clazz);
// 1.获取真正的解析器,由上代码可知,默认解析器为DOMConfigurator
configurator = (Configurator) instantiateByClassName(clazz,
Configurator.class,
null);
if(configurator == null) {
LogLog.error("Could not instantiate configurator ["+clazz+"].");
return;
}
} else {
configurator = new PropertyConfigurator();
}
// 2.执行真正的解析,读者需注意,hierarchy一直存在于入参中,下面需要获取hierarchy的RootLogger,并添加Appender
configurator.doConfigure(url, hierarchy);
}
4.
DOMConfigurator.
doConfigure(
url
,
hierarchy
)
public void doConfigure(final URL url, LoggerRepository repository) {
ParseAction action = new ParseAction() {
public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
URLConnection uConn = url.openConnection();
uConn.setUseCaches(false);
InputStream stream = uConn.getInputStream();
try {
InputSource src = new InputSource(stream);
src.setSystemId(url.toString());
return parser.parse(src);
} finally {
stream.close();
}
}
public String toString() {
return "url [" + url.toString() + "]";
}
};
doConfigure(action, repository);
}
private final void doConfigure(final ParseAction action, final LoggerRepository repository)
throws FactoryConfigurationError {
DocumentBuilderFactory dbf = null;
// 1.将Hierarchy赋值到当前repository
this.repository = repository;
...
try {
// 2.以下都是DOM解析的准备工作
dbf.setValidating(true);
DocumentBuilder docBuilder = dbf.newDocumentBuilder();
docBuilder.setErrorHandler(new SAXErrorHandler());
docBuilder.setEntityResolver(new Log4jEntityResolver());
// 3.回调上个ParseAction方法进行解析,返回Document
Document doc = action.parse(docBuilder);
// 4.解析Document并封装参数
parse(doc.getDocumentElement());
} catch (Exception e) {
if (e instanceof InterruptedException || e instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
// I know this is miserable...
LogLog.error("Could not parse "+ action.toString() + ".", e);
}
}
5.parse(doc.getDocumentElement())
protected void parse(Element element) {
...
String tagName = null;
Element currentElement = null;
Node currentNode = null;
NodeList children = element.getChildNodes();
final int length = children.getLength();
for (int loop = 0; loop < length; loop++) {
currentNode = children.item(loop);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
currentElement = (Element) currentNode;
tagName = currentElement.getTagName();
if (tagName.equals(CATEGORY_FACTORY_TAG) || tagName.equals(LOGGER_FACTORY_TAG)) {
parseCategoryFactory(currentElement);
}
}
}
for (int loop = 0; loop < length; loop++) {
currentNode = children.item(loop);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
currentElement = (Element) currentNode;
tagName = currentElement.getTagName();
// 1.解析category和logger标签
if (tagName.equals(CATEGORY) || tagName.equals(LOGGER)) {
parseCategory(currentElement);
// 2.解析root标签(在这里将Appender对象添加到AppenderAttachableImpl的集合中)
} else if (tagName.equals(ROOT_TAG)) {
parseRoot(currentElement);
// 3.解析renderer标签
} else if(tagName.equals(RENDERER_TAG)) {
parseRenderer(currentElement);
} else if(tagName.equals(THROWABLE_RENDERER_TAG)) {
if (repository instanceof ThrowableRendererSupport) {
ThrowableRenderer tr = parseThrowableRenderer(currentElement);
if (tr != null) {
((ThrowableRendererSupport) repository).setThrowableRenderer(tr);
}
}
// 4.解析appender、categoryFactory、loggerFactory
} else if (!(tagName.equals(APPENDER_TAG)
|| tagName.equals(CATEGORY_FACTORY_TAG)
|| tagName.equals(LOGGER_FACTORY_TAG))) {
// 在这里产生Appender对象
quietParseUnrecognizedElement(repository, currentElement, props);
}
}
}
}
6.parseRoot (Element rootElement)在这里了解如何将Appender添加到集合中
protected void parseRoot (Element rootElement) {
// 获取Hierarchy中的RootLogger
Logger root = repository.getRootLogger();
// 将RootLogger做为入参,以便于Appender添加
synchronized(root) {
parseChildrenOfLoggerElement(rootElement, root, true);
}
}
protected void parseChildrenOfLoggerElement(Element catElement,
Logger cat, boolean isRoot) {
PropertySetter propSetter = new PropertySetter(cat);
// Remove all existing appenders from cat. They will be
// reconstructed if need be.
cat.removeAllAppenders();
NodeList children = catElement.getChildNodes();
final int length = children.getLength();
for (int loop = 0; loop < length; loop++) {
Node currentNode = children.item(loop);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
Element currentElement = (Element) currentNode;
String tagName = currentElement.getTagName();
// 1.当解析到appender-ref标签时
if (tagName.equals(APPENDER_REF_TAG)) {
Element appenderRef = (Element) currentNode;
// 2.解析出Appender对象
Appender appender = findAppenderByReference(appenderRef);
String refName = subst(appenderRef.getAttribute(REF_ATTR));
if(appender != null)
LogLog.debug("Adding appender named ["+ refName+
"] to category ["+cat.getName()+"].");
else
LogLog.debug("Appender named ["+ refName + "] not found.");
// 3.将Appender加入到cat中,cat即RootLogger,addAppender(Appender newAppender)方法如下所示
cat.addAppender(appender);
} else if(tagName.equals(LEVEL_TAG)) {
parseLevel(currentElement, cat, isRoot);
} else if(tagName.equals(PRIORITY_TAG)) {
parseLevel(currentElement, cat, isRoot);
} else if(tagName.equals(PARAM_TAG)) {
setParameter(currentElement, propSetter);
} else {
quietParseUnrecognizedElement(cat, currentElement, props);
}
}
}
propSetter.activate();
}
cat.addAppender(appender)代码如下所示:
synchronized
public
void addAppender(Appender newAppender) {
if(aai == null) {
aai = new AppenderAttachableImpl();
}
aai.addAppender(newAppender);
repository.fireAddAppenderEvent(this, newAppender);
}
由以上代码可知,Appender是在解析log4j.xml的时候被添加到RootLogger中的