源码基于logback 1.1.2

logback.xml文件内容如下

<?xml version="1.0"?>
<configuration scan="true" scanPeriod="30 seconds">
    <property name="fileDir" value="/export/log/ingoreTest"/>
    <appender name="debugFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${fileDir}/debug.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${fileDir}/debug.%d{yyyy-MM-dd}.log</FileNamePattern>
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>NEUTRAL</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <filter class="com.example.IgnoreFilter">
            <ignorePolicy class="com.example.IgnorePolicy">
                <methodPrefix class="com.example.MethodPrefix">
                    <array class="com.example.Array">
                        <value>1</value>
                        <value>2</value>
                        <value>3</value>
                    </array>
                </methodPrefix>
            </ignorePolicy>
        </filter>

        <encoder>
            <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
        </encoder>
    </appender>

    <root>
        <level value="DEBUG"/>
        <appender-ref ref="debugFile"/>
    </root>
</configuration>

下面分析loaback是如何解析appender的:

1.当解析到appender标签的时候,触发appender的startEvent,最终调用[configuration][appender]对应的AppenderAction 的begin方法: 

public void begin(InterpretationContext ec, String localName,
      Attributes attributes) throws ActionException {
    // We are just beginning, reset variables
    appender = null;
    inError = false;
    //获取appender的类型,比如ch.qos.logback.core.rolling.RollingFileAppender
    String className = attributes.getValue(CLASS_ATTRIBUTE);
    if (OptionHelper.isEmpty(className)) {
      addError("Missing class name for appender. Near [" + localName
          + "] line " + getLineNumber(ec));
      inError = true;
      return;
    }

    try {
      addInfo("About to instantiate appender of type [" + className + "]");
      //根据appender的className初始化appender实例
      appender = (Appender<E>) OptionHelper.instantiateByClassName(className,
          ch.qos.logback.core.Appender.class, context);

      appender.setContext(context);
       //获取appender标签name属性
      String appenderName = ec.subst(attributes.getValue(NAME_ATTRIBUTE));

      if (OptionHelper.isEmpty(appenderName)) {
        addWarn("No appender name given for appender of type " + className
            + "].");
      } else {
        //设置appender实例的name变量
        appender.setName(appenderName);
        addInfo("Naming appender as [" + appenderName + "]");
      }

      // The execution context contains a bag which contains the appenders
      // created thus far.
      //创建的appender实例后期都维护在ec的objectMap的appenderBag中
      HashMap<String, Appender<E>> appenderBag = (HashMap<String, Appender<E>>) ec.getObjectMap().get(
          ActionConst.APPENDER_BAG);

      // add the appender just created to the appender bag.
      appenderBag.put(appenderName, appender);
      //将appender实例推入ec的objectStack中
      ec.pushObject(appender);
    } catch (Exception oops) {
      inError = true;
      addError("Could not create an Appender of type [" + className + "].",
          oops);
      throw new ActionException(oops);
    }
  }

2.[configuration][appender]startEvent过后,便是[configuration][appender][file]的startEvent,但是[configuration][appender][file]没有对应的action,根据之前的规则,file没有内嵌元素,使用隐式action:NestedBasicPropertyIA。但是NestedBasicPropertyIA的begin为空,即不做任何处理。 
3.[configuration][appender][file]的startEvent过后,应该是[configuration][appender][file]的bodyEvent,最终会调用NestedBasicPropertyIA的body方法: 

public void body(InterpretationContext ec, String body) {
    //获取file的body 即${fileDir}/debug.log
    String finalBody = ec.subst(body);
    // get the action data object pushed in isApplicable() method call
    //actionData维护三个属性:
    //1.parentBean:父级元素实例相关属性,这里file父级是appender实例
    //2.aggregationType:该element path的action类型,[configuration][appender][file]的action属于
      AS_BASIC_PROPERTY类型
    //3.propertyName:作为父级实例属性的名称或者可转化成setXX形式的名称,这里是file,appender实例有一个叫file的属性
      或者setFile的方法
    //这个action data是在查找对应的action时候,判定映射的action为隐式action时推入actionDataStack的
    IADataForBasicProperty actionData = (IADataForBasicProperty) actionDataStack.peek();
    switch (actionData.aggregationType) {
    case AS_BASIC_PROPERTY:
      //利用反射设置父级标签实例的属性值,这边是通过调用appender实例的setFile方法设置了fileName
      actionData.parentBean.setProperty(actionData.propertyName, finalBody);
      break;
    case AS_BASIC_PROPERTY_COLLECTION:
      actionData.parentBean
          .addBasicProperty(actionData.propertyName, finalBody);
    }

4.[configuration][appender][file]的bodyEvent过后,就是[configuration][appender][file]的endEvent,最终会调用NestedBasicPropertyIA的end方法: 

public void end(InterpretationContext ec, String tagName) {
    // pop the action data object pushed in isApplicable() method call
    //上面的注释很清楚,弹出在查找对应action时候推入的action data
    actionDataStack.pop();
  }

5.[configuration][appender][file]的endEvent过后,就是[configuration][appender][rollingPolicy]的startEvent。[configuration][appender][rollingPolicy]对应的action是NestedComplexPropertyIA,下面看NestedComplexPropertyIA的begin方法

public void begin(InterpretationContext ec, String localName,
      Attributes attributes) {
    // LogLog.debug("in NestComponentIA begin method");
    // get the action data object pushed in isApplicable() method call
    //actionData主要维护四个属性:
    //1.parentBean:父级元素实例相关属性,这里rollingPolicy父级是appender实例
    //2.aggregationType:该element path的action类型,[configuration][appender][rollingPolicy]的action属
      于AS_COMPLEX_PROPERTY类型
    //3.propertyName:作为父级实例属性的名称,这里是rollingPolicy,appender实例有一个叫rollingPolicy的属性
    //4.nestedComplexProperty:根据class属性实例化的对象,这里是TimeBasedRollingPolicy实例对象
    IADataForComplexProperty actionData = (IADataForComplexProperty) actionDataStack
        .peek();
    //获取class属性值,这里是ch.qos.logback.core.rolling.TimeBasedRollingPolicy
    String className = attributes.getValue(CLASS_ATTRIBUTE);
    // perform variable name substitution
    className = ec.subst(className);

    Class<?> componentClass = null;
    try {

      if (!OptionHelper.isEmpty(className)) {
        //实例化TimeBasedRollingPolicy
        componentClass = Loader.loadClass(className, context);
      } else {
        // guess class name via implicit rules
        PropertySetter parentBean = actionData.parentBean;
        componentClass = parentBean.getClassNameViaImplicitRules(actionData
            .getComplexPropertyName(), actionData.getAggregationType(), ec
            .getDefaultNestedComponentRegistry());
      }

      if (componentClass == null) {
        actionData.inError = true;
        String errMsg = "Could not find an appropriate class for property ["
            + localName + "]";
        addError(errMsg);
        return;
      }

      if (OptionHelper.isEmpty(className)) {
        addInfo("Assuming default type [" + componentClass.getName()
            + "] for [" + localName + "] property");
      }
      //将TimeBasedRollingPolicy实例对象存入到actionData的nestedComplexProperty属性里
      actionData.setNestedComplexProperty(componentClass.newInstance());

      // pass along the repository
      if (actionData.getNestedComplexProperty() instanceof ContextAware) {
        ((ContextAware) actionData.getNestedComplexProperty())
            .setContext(this.context);
      }
      //addInfo("Pushing component [" + localName
      //    + "] on top of the object stack.");
      //将TimeBasedRollingPolicy实例对象推入到ec的objectStack,
      ec.pushObject(actionData.getNestedComplexProperty());

    } catch (Exception oops) {
      actionData.inError = true;
      String msg = "Could not create component [" + localName + "] of type ["
          + className + "]";
      addError(msg, oops);
    }

  }

6.[configuration][appender][rollingPolicy]的startEvent过后,就是[configuration][appender][rollingPolicy][fileNamePattern]的startEvent,最终会调用NestedBasicPropertyIA的begin方法,此方法为空。 
7.[configuration][appender][rollingPolicy][fileNamePattern]的startEvent过后,就是[configuration][appender][rollingPolicy][fileNamePattern]的bodyEvent,最终会调用NestedBasicPropertyIA的body方法。根据前面的步骤3知道,NestedBasicPropertyIA的body方法作用主要是取出当前元素的值设置到父级元素的一个属性中,当前元素名称fileNamePattern,父级元素是rollingPolicy,利用反射调用父级元素的实例的setFileNamePattern,传入fileNamePattern的值。 
8.[configuration][appender][rollingPolicy][fileNamePattern]的bodyEvent过后,就是[configuration][appender][rollingPolicy][fileNamePattern]的endEvent,最终会调用NestedBasicPropertyIA的end方法,该方法只是弹出该element path对应的actionData。 
9.接下来就是[configuration][appender][rollingPolicy][maxHistory],逻辑基本与fileNamePattern的一样,读者可以自行debug看下。 
10.[configuration][appender][rollingPolicy]的内嵌元素处理完之后就是触发其endEvent方法了,最终会调用NestedComplexPropertyIA的end方法: 

 public void end(InterpretationContext ec, String tagName) {

    // pop the action data object pushed in isApplicable() method call
    // we assume that each this begin
    IADataForComplexProperty actionData = (IADataForComplexProperty) actionDataStack
        .pop();

    if (actionData.inError) {
      return;
    }
    //构建rollingPolicy的nestedBean
    PropertySetter nestedBean = new PropertySetter(actionData
        .getNestedComplexProperty());
    nestedBean.setContext(context);

    // have the nested element point to its parent if possible
    //如果该内嵌元素实例内部有属性指向其父级元素,则需要该内嵌元素对应的实例的parent的属性设置成父级元素的实例
    //这里内嵌元素实例是TimeBasedRollingPolicy,设置TimeBasedRollingPolicy的parent值为RollingFileAppender
      实例
    if (nestedBean.computeAggregationType("parent") == AggregationType.AS_COMPLEX_PROPERTY) {
      nestedBean.setComplexProperty("parent", actionData.parentBean.getObj());
    }

    // start the nested complex property if it implements LifeCycle and is not
    // marked with a @NoAutoStart annotation
    //从actionData中获取TimeBasedRollingPolicy的实例,并调用其start方法
    Object nestedComplexProperty = actionData.getNestedComplexProperty();
    if (nestedComplexProperty instanceof LifeCycle
        && NoAutoStartUtil.notMarkedWithNoAutoStart(nestedComplexProperty)) {
      ((LifeCycle) nestedComplexProperty).start();
    }

    Object o = ec.peekObject();

    if (o != actionData.getNestedComplexProperty()) {
      addError("The object on the top the of the stack is not the component pushed earlier.");
    } else {
      ec.popObject();
      // Now let us attach the component
      switch (actionData.aggregationType) {
      case AS_COMPLEX_PROPERTY:
        //调用该元素的父级元素实例的set${TagName}方法将当前元素对应的实例存入到父级元素实例中
        //这里是RollingFileAppender实例调用setRollingPolicy方法传入TimeBasedRollingPolicy实例
        actionData.parentBean.setComplexProperty(tagName, actionData
            .getNestedComplexProperty());

        break;
      case AS_COMPLEX_PROPERTY_COLLECTION:
        actionData.parentBean.addComplexProperty(tagName, actionData
            .getNestedComplexProperty());

        break;
      }
    }
  }

11.[configuration][appender][rollingPolicy]结束后就是[configuration][appender][filter] 的第一个过滤器LevelFilter,此element没有指定的action,经过判断为NestedComplexPropertyIA,处理方法和前面的rollingPolicy 一致

12.LevelFilter解析完成之后,就是[configuration][appender][filter] IgnoreFilter,此element没有指定的action,最终会调用NestedComplexPropertyIA的begin方法 

13.解析[configuration][appender][filter][IgnorePolicy],此element没有指定的action,最终会调用NestedComplexPropertyIA的begin方法 

14.解析[configuration][appender][filter][IgnorePolicy][methodPrefix],此element没有指定的action,最终会调用NestedComplexPropertyIA的begin方法

14.解析[configuration][appender][filter][IgnorePolicy][methodPrefix][array],此element没有指定的action,最终会调用NestedComplexPropertyIA的begin方法 

15.解析[configuration][appender][filter][IgnorePolicy][methodPrefix][array][value],此element没有指定的action,最终会调用NestedBasicPropertyIA的body方法,并按照aggregationType为AS_BASIC_PROPERTY_COLLECTION

public void body(InterpretationContext ec, String body) {

    String finalBody = ec.subst(body);
    // get the action data object pushed in isApplicable() method call
    IADataForBasicProperty actionData = (IADataForBasicProperty) actionDataStack.peek();
    switch (actionData.aggregationType) {
    case AS_BASIC_PROPERTY:
      actionData.parentBean.setProperty(actionData.propertyName, finalBody);
      break;
    //当遇到多个值时进入
    case AS_BASIC_PROPERTY_COLLECTION:
      actionData.parentBean
          .addBasicProperty(actionData.propertyName, finalBody);
    }
  }

这里如何判断aggregationType类型?要从NestedBasicPropertyIA的isApplicable方法看起

public boolean isApplicable(ElementPath elementPath, Attributes attributes,
      InterpretationContext ec) {
    // System.out.println("in NestedSimplePropertyIA.isApplicable [" + pattern +
    // "]");
    String nestedElementTagName = elementPath.peekLast();

    // no point in attempting if there is no parent object
    if (ec.isEmpty()) {
      return false;
    }

    Object o = ec.peekObject();
    PropertySetter parentBean = new PropertySetter(o);
    parentBean.setContext(context);
    //计算aggregationType
    AggregationType aggregationType = parentBean
        .computeAggregationType(nestedElementTagName);

    switch (aggregationType) {
    case NOT_FOUND:
    case AS_COMPLEX_PROPERTY:
    case AS_COMPLEX_PROPERTY_COLLECTION:
      return false;

    case AS_BASIC_PROPERTY:
    case AS_BASIC_PROPERTY_COLLECTION:
      IADataForBasicProperty ad = new IADataForBasicProperty(parentBean,
          aggregationType, nestedElementTagName);
      actionDataStack.push(ad);
      // addInfo("NestedSimplePropertyIA deemed applicable [" + pattern + "]");
      return true;
    default:
      addError("PropertySetter.canContainComponent returned " + aggregationType);
      return false;
    }
  }

computeAggregationType()就是计算aggregationType ,

其中的parentBean 即为上级元素 <array class="com.example.Array"></array>的类com.example.Array

16.依次解析完[configuration][appender][filter][IgnorePolicy][methodPrefix][array][value]、[configuration][appender][filter][IgnorePolicy][methodPrefix][array]、[configuration][appender][filter][IgnorePolicy][methodPrefix]、[configuration][appender][filter][IgnorePolicy]和[configuration][appender][filter]

17.[configuration][appender][filter]结束后就是[configuration][appender][encoder],主要是设置日志输出格式。

18.最后就是[configuration][appender]的endEvent了,最终会调用AppenderAction的end方法: 
 

  /**
   * Once the children elements are also parsed, now is the time to activate the
   * appender options.
   */
  //当子元素都被解析过后就该激活appender的end操作了
  public void end(InterpretationContext ec, String name) {
    if (inError) {
      return;
    }

    if (appender instanceof LifeCycle) {
      //触发appender的start方法:打开输出日志文件的outputStream,并设置到encoder中,后期日志记录委托给encoder处理
      ((LifeCycle) appender).start();
    }
    //先取出ec中objectStack的appender实例,判断是否过早弹出后就真正的弹出了
    Object o = ec.peekObject();

    if (o != appender) {
      addWarn("The object at the of the stack is not the appender named ["
          + appender.getName() + "] pushed earlier.");
    } else {
      ec.popObject();
    }
  }
11-23 10:38