log4j_slf4j源码分析(下)

本文详细解析了Log4j中Appender是如何在解析log4j.xml配置文件时被添加到RootLogger的过程。从LoggerFactory获取Logger实例开始,通过LogManager及LoggerRepository组件逐步深入,最终在DOMConfigurator中完成Appender的添加。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:
    针对于上篇文章 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(urlhierarchy)
 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中的






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恐龙弟旺仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值