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
如果又不正确的请批评指正