slf4j-logback日志框架源码探究

slf4j - Simple Logging Facade for Java

<dependency>
    <groupId>ch.qos.logbackgroupId>
    <artifactId>logback-classicartifactId>
    <version>1.4.8version>
dependency>
<dependency>
    <groupId>org.slf4jgroupId>
    <artifactId>slf4j-apiartifactId>
    <version>2.0.7version>
dependency>
23:28:04,608 |-INFO in ch.qos.logback.classic.LoggerContext[LOGBACK] - This is logback-classic version 1.4.8
23:28:04,631 |-INFO in ch.qos.logback.classic.LoggerContext[LOGBACK] - Could NOT find resource [logback-test.xml]
23:28:04,637 |-INFO in ch.qos.logback.classic.LoggerContext[LOGBACK] - Found resource [logback.xml] at [file:/D:/Code/IdeaProjects/logback-demo/target/classes/logback.xml]
23:28:04,738 |-INFO in ch.qos.logback.classic.model.processor.ContextNameModelHandler - Setting logger context name as [LOGBACK]
23:28:04,738 |-INFO in ch.qos.logback.core.model.processor.TimestampModelHandler - Using current interpretation time, i.e. now, as time reference.
23:28:04,763 |-INFO in ch.qos.logback.core.model.processor.TimestampModelHandler - Adding property to the context with key="bySecond" and value="20230907T232804" to the LOCAL scope
23:31:05,485 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - Processing appender named [STDOUT]
23:31:05,487 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
23:31:05,620 |-INFO in ch.qos.logback.core.model.processor.ImplicitModelHandler - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
23:31:12,891 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - Processing appender named [FILE]
23:31:12,891 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - About to instantiate appender of type [ch.qos.logback.core.FileAppender]
23:31:12,901 |-INFO in ch.qos.logback.core.model.processor.ImplicitModelHandler - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
23:31:12,903 |-INFO in ch.qos.logback.core.FileAppender[FILE] - File property is set to [log-20230907T232804.txt]
23:31:13,781 |-WARN in ch.qos.logback.core.model.processor.AppenderModelHandler - Appender named [FILE_ROLLING] not referenced. Skipping further processing.
23:31:14,885 |-INFO in ch.qos.logback.classic.model.processor.RootLoggerModelHandler - Setting level of ROOT logger to DEBUG
23:31:14,922 |-INFO in ch.qos.logback.core.model.processor.AppenderRefModelHandler - Attaching appender named [STDOUT] to Logger[ROOT]
23:31:14,924 |-INFO in ch.qos.logback.core.model.processor.AppenderRefModelHandler - Attaching appender named [FILE] to Logger[ROOT]
23:31:32,051 |-INFO in ch.qos.logback.core.model.processor.DefaultProcessor@61001b64 - End of configuration.
23:32:01,939 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@4310d43 - Registering current configuration as safe fallback point

从getLogger这个洞口进去

public final class LoggerFactory {
	public static Logger getLogger(Class<?> clazz) {
        Logger logger = getLogger(clazz.getName());
        if (DETECT_LOGGER_NAME_MISMATCH) {
            Class<?> autoComputedCallingClass = Util.getCallingClass();
            if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
                Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(),
                                autoComputedCallingClass.getName()));
                Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
            }
        }
        return logger;
    }

	 public static Logger getLogger(String name) {
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }

	public static ILoggerFactory getILoggerFactory() {
        return getProvider().getLoggerFactory();
    }

	static SLF4JServiceProvider getProvider() {
        if (INITIALIZATION_STATE == UNINITIALIZED) {
            synchronized (LoggerFactory.class) {
                if (INITIALIZATION_STATE == UNINITIALIZED) {
                    INITIALIZATION_STATE = ONGOING_INITIALIZATION;
                    performInitialization();
                }
            }
        }
        switch (INITIALIZATION_STATE) {
        case SUCCESSFUL_INITIALIZATION:
            return PROVIDER;
        case NOP_FALLBACK_INITIALIZATION:
            return NOP_FALLBACK_SERVICE_PROVIDER;
        case FAILED_INITIALIZATION:
            throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
        case ONGOING_INITIALIZATION:
            // support re-entrant behavior.
            // See also http://jira.qos.ch/browse/SLF4J-97
            return SUBST_PROVIDER;
        }
        throw new IllegalStateException("Unreachable code");
    }

	private final static void performInitialization() {
        bind();
        if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
            versionSanityCheck();
        }
    }
	
	
}

找到引路灯 - bind() 方法

/**
* 先通过 ServiceLoader 的方式去查找 SLF4JServiceProvider 的实现类,并取第一个实现类, 当前版本 logback 则是通过这种方式来加载 ch.qos.logback.classic.spi.LogbackServiceProvider 类
* 若第一种方式没找到实现类,则通过类加载加载类资源的方式加载 org/slf4j/impl/StaticLoggerBinder.class, log4j则是用过这种方式来加载
*/
private final static void bind() {
    try {
        List<SLF4JServiceProvider> providersList = findServiceProviders();
        reportMultipleBindingAmbiguity(providersList);
        if (providersList != null && !providersList.isEmpty()) {
            PROVIDER = providersList.get(0);
            // SLF4JServiceProvider.initialize() is intended to be called here and nowhere else.
            PROVIDER.initialize();
            INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
            reportActualBinding(providersList);
        } else {
            INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
            Util.report("No SLF4J providers were found.");
            Util.report("Defaulting to no-operation (NOP) logger implementation");
            Util.report("See " + NO_PROVIDERS_URL + " for further details.");

            Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
            reportIgnoredStaticLoggerBinders(staticLoggerBinderPathSet);
        }
        postBindCleanUp();
    } catch (Exception e) {
        failedBinding(e);
        throw new IllegalStateException("Unexpected initialization failure", e);
    }
}

绑定实现类

findServiceProviders

// Package access for tests
static List<SLF4JServiceProvider> findServiceProviders() {
    // retain behaviour similar to that of 1.7 series and earlier. More specifically, use the class loader that
    // loaded the present class to search for services
    final ClassLoader classLoaderOfLoggerFactory = LoggerFactory.class.getClassLoader();
    ServiceLoader<SLF4JServiceProvider> serviceLoader = getServiceLoader(classLoaderOfLoggerFactory);
    List<SLF4JServiceProvider> providerList = new ArrayList<>();
    Iterator<SLF4JServiceProvider> iterator = serviceLoader.iterator();
    while (iterator.hasNext()) {
        safelyInstantiate(providerList, iterator);
    }
    return providerList;
}

private static ServiceLoader<SLF4JServiceProvider> getServiceLoader(final ClassLoader classLoaderOfLoggerFactory) {
    ServiceLoader<SLF4JServiceProvider> serviceLoader;
    SecurityManager securityManager = System.getSecurityManager();
    if(securityManager == null) {
        serviceLoader = ServiceLoader.load(SLF4JServiceProvider.class, classLoaderOfLoggerFactory);
    } else {
        final PrivilegedAction<ServiceLoader<SLF4JServiceProvider>> action = () -> ServiceLoader.load(SLF4JServiceProvider.class, classLoaderOfLoggerFactory);
        serviceLoader = AccessController.doPrivileged(action);
    }
    return serviceLoader;
}

findPossibleStaticLoggerBinderPathSet

// We need to use the name of the StaticLoggerBinder class, but we can't
// reference the class itself.
private static final String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";

static Set<URL> findPossibleStaticLoggerBinderPathSet() {
    // use Set instead of list in order to deal with bug #138
    // LinkedHashSet appropriate here because it preserves insertion order
    // during iteration
    Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<>();
    try {
        ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
        Enumeration<URL> paths;
        if (loggerFactoryClassLoader == null) {
            paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
        } else {
            paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
        }
        while (paths.hasMoreElements()) {
            URL path = paths.nextElement();
            staticLoggerBinderPathSet.add(path);
        }
    } catch (IOException ioe) {
        Util.report("Error getting resources from path", ioe);
    }
    return staticLoggerBinderPathSet;
}

初始化

LogbackServiceProvider

public class LogbackServiceProvider implements SLF4JServiceProvider {
@Override
    public void initialize() {
        defaultLoggerContext = new LoggerContext();
        defaultLoggerContext.setName(CoreConstants.DEFAULT_CONTEXT_NAME);
        initializeLoggerContext();
        defaultLoggerContext.start();
        markerFactory = new BasicMarkerFactory();
        mdcAdapter = new LogbackMDCAdapter();
        // set the MDCAdapter for the defaultLoggerContext immediately
        defaultLoggerContext.setMDCAdapter(mdcAdapter);
    }

	private void initializeLoggerContext() {
        try {
            try {
                new ContextInitializer(defaultLoggerContext).autoConfig();
            } catch (JoranException je) {
                Util.report("Failed to auto configure default logger context", je);
            }
            // LOGBACK-292
            if (!StatusUtil.contextHasStatusListener(defaultLoggerContext)) {
                StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext);
            }
            // contextSelectorBinder.init(defaultLoggerContext, KEY);

        } catch (Exception t) { // see LOGBACK-1159
            Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", t);
        }
    }

	private void initializeLoggerContext() {
        try {
            try {
                new ContextInitializer(defaultLoggerContext).autoConfig();
            } catch (JoranException je) {
                Util.report("Failed to auto configure default logger context", je);
            }
            // LOGBACK-292
            if (!StatusUtil.contextHasStatusListener(defaultLoggerContext)) {
                StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext);
            }
            // contextSelectorBinder.init(defaultLoggerContext, KEY);

        } catch (Exception t) { // see LOGBACK-1159
            Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", t);
        }
    }
}

ContextInitializer

public class ContextInitializer {

	public void autoConfig() throws JoranException {
        autoConfig(Configurator.class.getClassLoader());
    }

    public void autoConfig(ClassLoader classLoader) throws JoranException {
        String versionStr = EnvUtil.logbackVersion();
        if (versionStr == null) {
            versionStr = CoreConstants.NA;
        }
        loggerContext.getStatusManager().add(new InfoStatus(CoreConstants.LOGBACK_CLASSIC_VERSION_MESSAGE + versionStr, loggerContext));
        StatusListenerConfigHelper.installIfAsked(loggerContext);
        List<Configurator> configuratorList = ClassicEnvUtil.loadFromServiceLoader(Configurator.class, classLoader);
        sortByPriority(configuratorList);

        // this should never happen as we do have DefaultJoranConfigurator shipping with logback-classic
        if (configuratorList == null) {
            fallbackOnToBasicConfigurator();
            return;
        }
        for (Configurator c : configuratorList) {
            try {
                c.setContext(loggerContext);
                Configurator.ExecutionStatus status = c.configure(loggerContext);
                if (status == Configurator.ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY) {
                    return;
                }
            } catch (Exception e) {
                throw new LogbackException(
                        String.format("Failed to initialize Configurator: %s using ServiceLoader",
                                c != null ? c.getClass().getCanonicalName() : "null"),
                        e);
            }
        }
        // at this stage invoke basicConfigurator
        fallbackOnToBasicConfigurator();

    }
}
loadFromServiceLoader() 绑定配置类
DefaultJoranConfigurator 加载配置
public class DefaultJoranConfigurator extends ContextAwareBase implements Configurator {

	final public static String AUTOCONFIG_FILE = "logback.xml";
    final public static String TEST_AUTOCONFIG_FILE = "logback-test.xml";

	/**
	* 1. 获取配置文件 url
	* 2. 
	*/
	@Override
    public ExecutionStatus configure(LoggerContext loggerContext) {
        URL url = findURLOfDefaultConfigurationFile(true);
        if (url != null) {
            try {
                configureByResource(url);
            } catch (JoranException e) {
                e.printStackTrace();
            }
            // we tried and that counts Mary.
            return ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY;
        } else {
            return ExecutionStatus.INVOKE_NEXT_IF_ANY;
        }
    }
}
  1. 获取配置文件 url

    public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
        ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
        URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }
    
        url = getResource(TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }
    
        return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus);
    }
    
    private URL getResource(String filename, ClassLoader myClassLoader, boolean updateStatus) {
        URL url = Loader.getResource(filename, myClassLoader);
        if (updateStatus) {
            statusOnResourceSearch(filename, myClassLoader, url);
        }
        return url;
    }
    
  2. 根据配置文件进行配置

    public void configureByResource(URL url) throws JoranException {
        if (url == null) {
            throw new IllegalArgumentException("URL argument cannot be null");
        }
        final String urlString = url.toString();
        if (urlString.endsWith("xml")) {
            JoranConfigurator configurator = new JoranConfigurator();
            configurator.setContext(context);
            configurator.doConfigure(url);
        } else {
            throw new LogbackException(
                    "Unexpected filename extension of file [" + url.toString() + "]. Should be .xml");
        }
    }
    
GenericXMLConfigurator

slf4j-logback日志框架源码探究_第1张图片

public abstract class GenericXMLConfigurator extends ContextAwareBase {
	public final void doConfigure(URL url) throws JoranException {
        InputStream in = null;
        try {
            informContextOfURLUsedForConfiguration(getContext(), url);
            URLConnection urlConnection = url.openConnection();
            // per http://jira.qos.ch/browse/LBCORE-105
            // per http://jira.qos.ch/browse/LBCORE-127
            urlConnection.setUseCaches(false);

            in = urlConnection.getInputStream();
            doConfigure(in, url.toExternalForm());
        } catch (IOException ioe) {
            String errMsg = "Could not open URL [" + url + "].";
            addError(errMsg, ioe);
            throw new JoranException(errMsg, ioe);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ioe) {
                    String errMsg = "Could not close input stream";
                    addError(errMsg, ioe);
                    throw new JoranException(errMsg, ioe);
                }
            }
        }
    }

	public final void doConfigure(InputStream inputStream, String systemId) throws JoranException {
        InputSource inputSource = new InputSource(inputStream);
        inputSource.setSystemId(systemId);
        doConfigure(inputSource);
    }

	// this is the most inner form of doConfigure whereto other doConfigure
    // methods ultimately delegate
    public final void doConfigure(final InputSource inputSource) throws JoranException {

        context.fireConfigurationEvent(newConfigurationStartedEvent(this));
        long threshold = System.currentTimeMillis();

		// 利用 sax(Simple api for XML)逐行解析配置文件
        SaxEventRecorder recorder = populateSaxEventRecorder(inputSource);
        List<SaxEvent> saxEvents = recorder.getSaxEventList();
        if (saxEvents.isEmpty()) {
            addWarn("Empty sax event list");
            return;
        }
        // 将解析到的xml配置封装成 各种元素的Model
        Model top = buildModelFromSaxEventList(recorder.getSaxEventList());
        if (top == null) {
            addError(ErrorCodes.EMPTY_MODEL_STACK);
            return;
        }
        sanityCheck(top);
        // 处理 Model
        processModel(top);

        // no exceptions at this level
        StatusUtil statusUtil = new StatusUtil(context);
        if (statusUtil.noXMLParsingErrorsOccurred(threshold)) {
            addInfo("Registering current configuration as safe fallback point");
            registerSafeConfiguration(top);
        }
        context.fireConfigurationEvent(newConfigurationEndedEvent(this));

    }

	public void processModel(Model model) {
        buildModelInterpretationContext();
        DefaultProcessor defaultProcessor = new DefaultProcessor(context, this.modelInterpretationContext);
        addModelHandlerAssociations(defaultProcessor);

        // disallow simultaneous configurations of the same context
        synchronized (context.getConfigurationLock()) {
            defaultProcessor.process(model);
        }
    }
}
JoranConfigurator

添加各种ModelHandler用于处理Model

public class JoranConfigurator extends JoranConfiguratorBase<ILoggingEvent> {
@Override
    protected void addModelHandlerAssociations(DefaultProcessor defaultProcessor) {
        super.addModelHandlerAssociations(defaultProcessor);
        defaultProcessor.addHandler(ConfigurationModel.class, ConfigurationModelHandler::makeInstance);
        defaultProcessor.addHandler(ContextNameModel.class, ContextNameModelHandler::makeInstance);
        defaultProcessor.addHandler(LoggerContextListenerModel.class, LoggerContextListenerModelHandler::makeInstance);

        defaultProcessor.addHandler(InsertFromJNDIModel.class, InsertFromJNDIModelHandler::makeInstance);

        defaultProcessor.addHandler(AppenderModel.class, AppenderModelHandler::makeInstance);
        defaultProcessor.addHandler(AppenderRefModel.class, AppenderRefModelHandler::makeInstance);
        defaultProcessor.addHandler(RootLoggerModel.class, RootLoggerModelHandler::makeInstance);
        defaultProcessor.addHandler(LoggerModel.class, LoggerModelHandler::makeInstance);
        defaultProcessor.addHandler(LevelModel.class, LevelModelHandler::makeInstance);

        defaultProcessor.addAnalyser(LoggerModel.class, 
                () -> new RefContainerDependencyAnalyser(context, LoggerModel.class));

        defaultProcessor.addAnalyser(RootLoggerModel.class,
                () -> new RefContainerDependencyAnalyser(context, RootLoggerModel.class));

        defaultProcessor.addAnalyser(AppenderModel.class,
                () -> new RefContainerDependencyAnalyser(context, AppenderModel.class));

        defaultProcessor.addAnalyser(AppenderRefModel.class, 
                () -> new AppenderRefDependencyAnalyser(context));

        sealModelFilters(defaultProcessor);
    }
}

这里可以看到并不是直接实例化一个 ModelHandler 然后添加进去,而是放入了一个 ModelHandlerFactoryMethod。ModelHandlerFactoryMethod 是一个 @FunctionalInterface,专门用于实例化对应的 ModelHandler

@FunctionalInterface
public interface ModelHandlerFactoryMethod {

    public ModelHandlerBase make(Context context, ModelInterpretationContext ic);
}

这里体现了一个懒加载的思想,当需要处理某种 Model 时,才去实例化对应的 ModelHandler,每个 ModelHandler 都有一个实例化的方法,如 AppenderModelHandler

public class AppenderModelHandler<E> extends ModelHandlerBase {
	static public ModelHandlerBase makeInstance(Context context, ModelInterpretationContext mic) {
        return new AppenderModelHandler(context);
    }
}

父类 JoranConfiguratorBase 添加 ModelHandler

abstract public class JoranConfiguratorBase<E> extends GenericXMLConfigurator {
@Override
    protected void addModelHandlerAssociations(DefaultProcessor defaultProcessor) {
        defaultProcessor.addHandler(ImportModel.class, ImportModelHandler::makeInstance);

        defaultProcessor.addHandler(ShutdownHookModel.class, ShutdownHookModelHandler::makeInstance);
        defaultProcessor.addHandler(SequenceNumberGeneratorModel.class, SequenceNumberGeneratorModelHandler::makeInstance);

        defaultProcessor.addHandler(EventEvaluatorModel.class, EventEvaluatorModelHandler::makeInstance);
        defaultProcessor.addHandler(DefineModel.class, DefineModelHandler::makeInstance);
        defaultProcessor.addHandler(IncludeModel.class, NOPModelHandler::makeInstance);

        
        defaultProcessor.addHandler(ParamModel.class, ParamModelHandler::makeInstance);
        defaultProcessor.addHandler(PropertyModel.class, PropertyModelHandler::makeInstance);
        defaultProcessor.addHandler(TimestampModel.class, TimestampModelHandler::makeInstance);
        defaultProcessor.addHandler(StatusListenerModel.class, StatusListenerModelHandler::makeInstance);
        defaultProcessor.addHandler(ImplicitModel.class, ImplicitModelHandler::makeInstance);
        
        defaultProcessor.addHandler(IfModel.class, IfModelHandler::makeInstance);
        defaultProcessor.addHandler(ThenModel.class, ThenModelHandler::makeInstance);
        defaultProcessor.addHandler(ElseModel.class, ElseModelHandler::makeInstance);
        
        defaultProcessor.addHandler(SiftModel.class, SiftModelHandler::makeInstance);
        
    }
}

添加后的结果
phaseOneFilter 一共有 21 个 ModelFilter

  1. ImportModel.class
  2. ShutdownHookModel.class
  3. SequenceNumberGeneratorModel.class
  4. EventEvaluatorModel.class
  5. DefineModel.class
  6. IncludeModel.class
  7. ParamModel.class
  8. PropertyModel.class
  9. TimestampModel.class
  10. StatusListenerModel.class
  11. ImplicitModel.class
  12. IfModel.class
  13. ThenModel.class
  14. ElseModel.class
  15. SiftModel.class
  16. ConfigurationModel.class
  17. ContextNameModel.class
  18. LoggerContextListenerModel.class
  19. InsertFromJNDIModel.class
  20. LevelModel.class
  21. DenyAllModelFilter

phaseTwoFilter 一个5个

  1. LoggerModel
  2. RootLoggerModel
  3. AppenderModel
  4. AppenderRefModel
  5. AllowAllModelFilter
DefaultProcessor

addHandler()

  1. 将 ModelHandlerFactoryMethod 添加到 modelClassToHandlerMap
  2. 将 AllowModelFilter 添加到两条过滤器链 ChainedModelFilter 中,分别是 phaseOneFilter 和 phaseTwoFilter。每个 AllowModelFilter 都有一个 allowedModelType 来表示允许处理的 Model
    在这里插入图片描述
    public class AllowModelFilter implements ModelFilter {
    
        final Class<? extends Model> allowedModelType;
    
        AllowModelFilter(Class<? extends Model> allowedType) {
            this.allowedModelType = allowedType;
        }
    
        @Override
        public FilterReply decide(Model model) {
    
            if (model.getClass() == allowedModelType) {
                return FilterReply.ACCEPT;
            }
    
            return FilterReply.NEUTRAL;
        }
    
    }
    

determineProcessingPhase()
Model 上的 @PhaseIndicator 注解标注了该 Model 是属于第几阶段处理的,没标注的默认为第一阶段。其中,LoggerModel, RootLoggerModel, AppenderModel, AppenderRefModel 这四个属于第二条过滤器链

addAnalyser()
将 ModelHandler 添加到 modelClassToDependencyAnalyserMap,这些 ModelHandler 专门用于解析依赖

process()
主处理流程

mainTraverse()

  1. 调用阶段一的过滤器链 ChainedModelFilter 进行筛选
  2. 实例化 ModelHandler
  3. 处理 Model
  4. 执行 ModelHandler 的后置处理方法
public class DefaultProcessor extends ContextAwareBase {

	final protected ModelInterpretationContext mic;
    final HashMap<Class<? extends Model>, ModelHandlerFactoryMethod> modelClassToHandlerMap = new HashMap<>();
    final HashMap<Class<? extends Model>, Supplier<ModelHandlerBase>> modelClassToDependencyAnalyserMap = new HashMap<>();

    ChainedModelFilter phaseOneFilter = new ChainedModelFilter();
    ChainedModelFilter phaseTwoFilter = new ChainedModelFilter();

	public void addHandler(Class<? extends Model> modelClass, ModelHandlerFactoryMethod modelFactoryMethod) {

        modelClassToHandlerMap.put(modelClass, modelFactoryMethod);

        ProcessingPhase phase = determineProcessingPhase(modelClass);
        switch (phase) {
            case FIRST:
                getPhaseOneFilter().allow(modelClass);
                break;
            case SECOND:
                getPhaseTwoFilter().allow(modelClass);
                break;
            default:
                throw new IllegalArgumentException("unexpected value " + phase + " for model class " + modelClass.getName());
        }
    }

	private ProcessingPhase determineProcessingPhase(Class<? extends Model> modelClass) {

        PhaseIndicator phaseIndicator = modelClass.getAnnotation(PhaseIndicator.class);
        if (phaseIndicator == null) {
            return ProcessingPhase.FIRST;
        }

        ProcessingPhase phase = phaseIndicator.phase();
        return phase;
    }

    public void addAnalyser(Class<? extends Model> modelClass, Supplier<ModelHandlerBase> analyserSupplier) {
        modelClassToDependencyAnalyserMap.put(modelClass, analyserSupplier);
    }

	public void process(Model model) {

        if (model == null) {
            addError("Expecting non null model to process");
            return;
        }
        initialObjectPush();

        mainTraverse(model, getPhaseOneFilter());
        analyseDependencies(model);
        traversalLoop(this::secondPhaseTraverse, model, getPhaseTwoFilter(), "phase 2");

        addInfo("End of configuration.");
        finalObjectPop();
    }

	// 递归处理树形结构的xml配置文件
	protected int mainTraverse(Model model, ModelFilter modelFiler) {

        FilterReply filterReply = modelFiler.decide(model);
        if (filterReply == FilterReply.DENY)
            return DENIED;

        int count = 0;

        try {
            ModelHandlerBase handler = null;
            boolean unhandled = model.isUnhandled();

            if (unhandled) {
                handler = createHandler(model);
                if (handler != null) {
                    handler.handle(mic, model);
                    model.markAsHandled();
                    count++;
                }
            }
            // recurse into submodels handled or not
            if (!model.isSkipped()) {
                for (Model m : model.getSubModels()) {
                    count += mainTraverse(m, modelFiler);
                }
            }

            if (unhandled && handler != null) {
                handler.postHandle(mic, model);
            }
        } catch (ModelHandlerException e) {
            addError("Failed to traverse model " + model.getTag(), e);
        }
        return count;
    }

	private void traversalLoop(TraverseMethod traverseMethod, Model model, ModelFilter modelfFilter, String phaseName) {
        int LIMIT = 3;
        for (int i = 0; i < LIMIT; i++) {
            int handledModelCount = traverseMethod.traverse(model, modelfFilter);
            if (handledModelCount == 0)
                break;
        }
    }

	protected int secondPhaseTraverse(Model model, ModelFilter modelFilter) {

        FilterReply filterReply = modelFilter.decide(model);
        if (filterReply == FilterReply.DENY) {
            return 0;
        }

        int count = 0;

        try {

            boolean allDependenciesStarted = allDependenciesStarted(model);

            ModelHandlerBase handler = null;
            if (model.isUnhandled() && allDependenciesStarted) {
                handler = createHandler(model);
                if (handler != null) {
                    handler.handle(mic, model);
                    model.markAsHandled();
                    count++;
                }
            }

            if (!allDependenciesStarted && !dependencyIsADirectSubmodel(model)) {
                return count;
            }

            if (!model.isSkipped()) {
                for (Model m : model.getSubModels()) {
                    count += secondPhaseTraverse(m, modelFilter);
                }
            }
            if (handler != null) {
                handler.postHandle(mic, model);
            }
        } catch (ModelHandlerException e) {
            addError("Failed to traverse model " + model.getTag(), e);
        }
        return count;
    }
}

Model

配置元素的抽象表示
slf4j-logback日志框架源码探究_第2张图片
带有@PhaseIndicator的Model,标明了为第二阶段解析
slf4j-logback日志框架源码探究_第3张图片

ModelHandlerBase

slf4j-logback日志框架源码探究_第4张图片

slf4j-logback日志框架源码探究_第5张图片

你可能感兴趣的:(java,logback)