log4j2源码解析(2)--LoggerContext

栏目: Java · 发布时间: 6年前

内容简介:LoggerContext作用及初始化流程根据我们在Log4j初识中的实例可以看出,在不适用日志门面插件slf4j的情况下,获取logger的方式一般为可以看到,通常情况下,我们会使用LogManager的静态方法getLogger方法获取logger,下面我们就简要看一下这个方法的流程。

LoggerContext作用及初始化流程

根据我们在Log4j初识中的实例可以看出,在不适用日志门面插件slf4j的情况下,获取logger的方式一般为

Logger logger = logManager.getLogger(xx.class)

可以看到,通常情况下,我们会使用LogManager的静态方法getLogger方法获取logger,下面我们就简要看一下这个方法的流程。

public static Logger getLogger(final Class<?> clazz) {
    final Class<?> cls = callerClass(clazz);
    return getContext(cls.getClassLoader(), false).getLogger(toLoggerName(cls));
}

这个方法返回了一个链式调用后的结果,而首先是先调用了getContext,这个方法返回的是一个LoggerContext对象,该方法定义如下:

public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext) {
    try {
        return factory.getContext(FQCN, loader, null, currentContext);
    } catch (final IllegalStateException ex) {
        LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
        return new SimpleLoggerContextFactory().getContext(FQCN, loader, null,currentContext);
    }
}

这个方法中的LoggerContext是通过LoggerFactory的getContext方法,默认情况下,对应的子类是Log4jLoggerFactory。对应的方法如下:

public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext, final boolean currentContext) {
     //获得LoggerContex实例
    final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext);
    if (externalContext != null && ctx.getExternalContext() == null) {
        ctx.setExternalContext(externalContext);
    }
    //启动LoggerContext
    if (ctx.getState() == LifeCycle.State.INITIALIZED) {
        ctx.start();
    }
    return ctx;
}

其中里面的主要逻辑是返回一个启动的LoggerContext实例,其中LoggerContext实例是通过Log4jLoggerFactory中的ContextSelector获取的,默认情况下使用的是ClassLoaderContextSelector,在Log4jLoggerFactory的构造方法中进行初始化。

完成初始化后,就是LoggerContext的启动,如果当前的context实例的状态为初始化状态,则调用start函数,其中的流程是

LogContext.start()—>LogContext.reconfigure()—>LogContext.reconfigure(URI)

其中主要做的事情就是根据配置文件的位置,读取相应的log4j2配置文件,解析配置文件,最终解析为各种Appender以及Logger的 Java 对象,下面我们来看大致的流程

首先会获取ConfigurationFactory的实例,然后获取Configuration,分别看这两步

1、获取ConfigurationFactory实例

public static ConfigurationFactory getInstance() {
    // volatile works in Java 1.6+, so double-checked locking also works properly
    //noinspection DoubleCheckedLocking
    if (factories == null) {
        LOCK.lock();
        try {
            if (factories == null) {
                final List<ConfigurationFactory> list = new ArrayList<>();
                final String factoryClass = PropertiesUtil.getProperties().getStringProperty(CONFIGURATION_FACTORY_PROPERTY);
                if (factoryClass != null) {
                    addFactory(list, factoryClass);
                }
                final PluginManager manager = new PluginManager(CATEGORY);
                manager.collectPlugins();
                final Map<String, PluginType<?>> plugins = manager.getPlugins();
                final List<Class<? extends ConfigurationFactory>> ordered = new ArrayList<>(plugins.size());
                for (final PluginType<?> type : plugins.values()) {
                    try {
                        ordered.add(type.getPluginClass().asSubclass(ConfigurationFactory.class));
                    } catch (final Exception ex) {
                        LOGGER.warn("Unable to add class {}", type.getPluginClass(), ex);
                    }
                }
                Collections.sort(ordered, OrderComparator.getInstance());
                for (final Class<? extends ConfigurationFactory> clazz : ordered) {
                    addFactory(list, clazz);
                }
                // see above comments about double-checked locking
                //noinspection NonThreadSafeLazyInitialization
                factories = Collections.unmodifiableList(list);
            }
        } finally {
            LOCK.unlock();
        }
    }

    LOGGER.debug("Using configurationFactory {}", configFactory);
    return configFactory;

这是一个典型的单例模式,使用了双重检查锁的方式获取实例,这个方法里面有一个操作步骤我们要重点介绍,就是PluginManager实例的创建,PluginManager主要用于管理Log4J中的插件,这些Plugin主要是一些对应不同格式的配置文件的解析器,PluginManager中使用category对不同类型的插件进行缓存。

获取到ConfigurationFactory的实例之后,就是获取Configuration的过程,主要流程是根据配置的格式,从遍历上面提到列表中的factory,加载到对应的ConfigurationFactory,随后通过这个Factory去解析配置文件最终获取到Configuration。代码流程如下:

public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation, final ClassLoader loader) {
    if (!isActive()) {
        return null;
    }
    if (loader == null) {
        return getConfiguration(loggerContext, name, configLocation);
    }
    if (isClassLoaderUri(configLocation)) {
        final String path = extractClassLoaderUriPath(configLocation);
        final ConfigurationSource source = ConfigurationSource.fromResource(path,loader);
        if (source != null) {
            final Configuration configuration = getConfiguration(loggerContext,source);
            if (configuration != null) {
                return configuration;
            }
        }
    }
    return getConfiguration(loggerContext, name, configLocation);
}

注意这里的getConfiguration(loggerContext,source);是一个多态方法,会根据不同类型的配置发文件,调用相应的ConfigureFactory的方法,将配置文件中的tag变为java对象。下一篇文章中,我会以xml类型的文件详细介绍将tag变化为Java对象的过程。

谢谢你请我吃糖果


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java Servlet & JSP Cookbook

Java Servlet & JSP Cookbook

Bruce W. Perry / O'Reilly Media / 2003-12-1 / USD 49.99

With literally hundreds of examples and thousands of lines of code, the Java Servlet and JSP Cookbook yields tips and techniques that any Java web developer who uses JavaServer Pages or servlets will ......一起来看看 《Java Servlet & JSP Cookbook》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具