日志框架学习

本文深入解析了commonslogging的源码,详细介绍了其通过多种方式获取LogFactory实现类的过程,包括系统属性、环境变量、配置文件及默认实现,并阐述了如何通过LogFactory获取具体日志实现类。

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

1.commons logging 源码分析

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
private Log loger = LogFactory.getLog(this.getClass());

1.1getLog()方法的实现如下:

  /**
 * Convenience method to return a named logger, without the application
 * having to care about factories.
 *
 * @param clazz Class from which a log name will be derived
 * @throws LogConfigurationException if a suitable <code>Log</code>
 *  instance cannot be returned
 */
public static Log getLog(Class clazz) throws LogConfigurationException {
    return getFactory().getInstance(clazz);
}

commons logging 是通过getFactory方法获取对应的实现类,继而获取示例

1.2getFactory的具体实现(方法较长,简述下流程)
1.2.1首先获取缓存的数据

 LogFactory factory = getCachedFactory(contextClassLoader);

1.2.2缓存数据未获取到时,获取系统环境变量为org.apache.commons.logging.LogFactory的配置实现

   /**
     * The name (<code>org.apache.commons.logging.LogFactory</code>) of the property
     * used to identify the LogFactory implementation
     * class name. This can be used as a system property, or as an entry in a
     * configuration properties file.
     */
    public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory";

String factoryClass = getSystemProperty(FACTORY_PROPERTY, null);
factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);

1.2.3环境变量未获取到时获取META-INF/services/org.apache.commons.logging.LogFactory目录下配置获取实现类(jcl-over-slf4j 就是在包中增加了该文件)

   /**
     * JDK1.3+ <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider">
     * 'Service Provider' specification</a>.
     */
    protected static final String SERVICE_ID =
        "META-INF/services/org.apache.commons.logging.LogFactory";

final InputStream is = getResourceAsStream(contextClassLoader, SERVICE_ID);

1.2.4获取commons-logging.properties文件配置org.apache.commons.logging.LogFactory的实例

 public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory";

String factoryClass = props.getProperty(FACTORY_PROPERTY);
factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);

1.2.5 获取默认实现类org.apache.commons.logging.impl.LogFactoryImpl

1.2.6 将获取到的实现类放入缓存

至此获取工厂实现类就结束了,获取到工厂后就要获取具体的log实现类(比如你想用这边就可以使用配置org.apache.commons.logging.impl.SLF4JLogFactory来获取到SLF4JLogFactory)进一步获取对应的具体日志实现类

1.3获取日志实现类getInstance

public Log getInstance(Class clazz) throws LogConfigurationException {
    return getInstance(clazz.getName());
}
public Log getInstance(String name) throws LogConfigurationException {
        Log instance = (Log) instances.get(name);
        if (instance == null) {
            instance = newInstance(name);
            instances.put(name, instance);
        }
        return instance;

}

newInstance实现方法

protected Log newInstance(String name) throws LogConfigurationException {
        Log instance;
        try {
            if (logConstructor == null) {
                instance = discoverLogImplementation(name);
            }
            else {
                Object params[] = { name };
                instance = (Log) logConstructor.newInstance(params);
            }
            if (logMethod != null) {
                Object params[] = { this };
                logMethod.invoke(instance, params);
            }
            return instance;
        } catch (LogConfigurationException lce) {
            throw lce;
        } catch (InvocationTargetException e) {
            Throwable c = e.getTargetException();
            throw new LogConfigurationException(c == null ? e : c);
        } catch (Throwable t) {
            handleThrowable(t); 
            throw new LogConfigurationException(t);
        }
    }
logConstructor 存在时直接使用进行创建实例 不存在时使用discoverLogImplementation方法创建
private Log discoverLogImplementation(String logCategory)
        throws LogConfigurationException {
        if (isDiagnosticsEnabled()) {
            logDiagnostic("Discovering a Log implementation...");
        }
        initConfiguration();
        Log result = null;
        // See if the user specified the Log implementation to use
        String specifiedLogClassName = findUserSpecifiedLogClassName();
        if (specifiedLogClassName != null) {
            if (isDiagnosticsEnabled()) {
                logDiagnostic("Attempting to load user-specified log class '" +
                    specifiedLogClassName + "'...");
            }
            result = createLogFromClass(specifiedLogClassName,
                                        logCategory,
                                        true);
            if (result == null) {
                StringBuffer messageBuffer =  new StringBuffer("User-specified log class '");
                messageBuffer.append(specifiedLogClassName);
                messageBuffer.append("' cannot be found or is not useable.");
                // Mistyping or misspelling names is a common fault.
                // Construct a good error message, if we can
                informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LOG4J_LOGGER);
                informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_JDK14_LOGGER);
                informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LUMBERJACK_LOGGER);
                informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_SIMPLE_LOGGER);
                throw new LogConfigurationException(messageBuffer.toString());
            }
            return result;
        }
        if (isDiagnosticsEnabled()) {
            logDiagnostic(
                "No user-specified Log implementation; performing discovery" +
                " using the standard supported logging implementations...");
        }
        for(int i=0; i<classesToDiscover.length && result == null; ++i) {
            result = createLogFromClass(classesToDiscover[i], logCategory, true);
        }
        if (result == null) {
            throw new LogConfigurationException
                        ("No suitable Log implementation");
        }
        return result;
    }

1.initConfiguration方法初始化配置
2.findUserSpecifiedLogClassName在配置文件系统环境变量查找指定的配置
3.创建指定的配置并设置logConstructor 和logMethod
4.未指定实现类时根据顺序依次创建实现类

private static final String[] classesToDiscover = {
        LOGGING_IMPL_LOG4J_LOGGER,
        "org.apache.commons.logging.impl.Jdk14Logger",
        "org.apache.commons.logging.impl.Jdk13LumberjackLogger",
        "org.apache.commons.logging.impl.SimpleLog"
};
总结如下:
获取当前线程的classLoader,根据classLoader从缓存中获取LogFactroy,使用的缓存是WeakHashTable对象;如果缓存中存在,则返回,没有则进入下面流程;
读取classpath下的commons-logging.properties文件,判断其中是否设置了use_tccl属性,如果不为空则判断,该属性的值是否为false,若为false,则将baseClassLoader替换为当前类的classLoader;
接着,继续获取LogFactory对象,此步骤分为4中方式:
     (1)在系统属性中查找“org.apache.commons.logging.LogFactory”属性的值,根据值生成LogFactory对象;
     (2)通过资源“META-INF/services/org.apache.commons.logging.LogFactory”文件,获取的值生成LogFactory对象;
     (3)通过配置文件commons-logging.properties,获取以“org.apache.commons.logging.LogFactory”为key的值,根据值生成logFactory;
     (4)如果以上均不成功,则创建系统默认的日志工厂:org.apache.commons.logging.impl.LogFactoryImpl
成功获取日志工厂后,根据类名获取日志对象;
主要逻辑在discoverLogImplementation方法中:
     (1)检查commons-logging.properties文件中是否存在“org.apache.commons.logging.Log”属性,若存在则创建具体的日志对象;若不存在,进行下面逻辑;
     (2)遍历classesToDiscover数组,该数组存有日志具体实现类的全限定类名:org.apache.commons.logging.impl.Log4JLogger、org.apache.commons.logging.impl.Jdk14Logger、org.apache.commons.logging.impl.Jdk13LumberjackLogger、org.apache.commons.logging.impl.SimpleLog;
     (3)根据数组中存着的全限定类名,按照顺序依次加载Class文件,进行实例化操作,最后返回Log实例,默认为Jdk14Logger;

参考自:https://blog.youkuaiyun.com/u011794238/article/details/50749260
如果又不正确的请批评指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值