目录
maven 引用
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
基本使用
新建类 Main ,内容如下
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Main {
public static void main(String[] args) {
Log logger = LogFactory.getLog(Main.class);
logger.info("message");
}
}
新建配置文件: commons-logging.properties
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
就是这么简单,他的使用到这里就已经结束了,没有更多内容了。
运行后控制台输出内容:
[INFO] Main - message
内部初始化
初始化
static {
// note: it's safe to call methods before initDiagnostics (though
// diagnostic output gets discarded).
// 获取 ClassLoader,如果启用了java安全机制无法获取ClassLoader时抛出异常
thisClassLoader = getClassLoader(LogFactory.class);
// 初始化日志信息
initDiagnostics();
// 载入环境变量
logClassLoaderEnvironment(LogFactory.class);
// 创建工厂仓库
factories = createFactoryStore();
//是否启用诊断
if (isDiagnosticsEnabled()) {
// 引导完成
logDiagnostic("BOOTSTRAP COMPLETED");
}
}
初始化日志信息
private static void initDiagnostics() {
String dest;
try {
// public static final String DIAGNOSTICS_DEST_PROPERTY = "org.apache.commons.logging.diagnostics.dest";
//获取系统环境变量 org.apache.commons.logging.diagnostics.dest 的值
dest = getSystemProperty(DIAGNOSTICS_DEST_PROPERTY, null);
if (dest == null) {
return;
}
} catch(SecurityException ex) {
// We must be running in some very secure environment.
// We just have to assume output is not wanted..
return;
}
//System.out输出
if (dest.equals("STDOUT")) {
diagnosticsStream = System.out;
//System.err输出
} else if (dest.equals("STDERR")) {
diagnosticsStream = System.err;
} else {
//自定义文件路径,例如: d:/test.log
try {
// open the file in append mode
FileOutputStream fos = new FileOutputStream(dest, true);
diagnosticsStream = new PrintStream(fos);
} catch(IOException ex) {
// We should report this to the user - but how?
return;
}
}
// In order to avoid confusion where multiple instances of JCL are
// being used via different classloaders within the same app, we
// ensure each logged message has a prefix of form
// [LogFactory from classloader OID]
//
// Note that this prefix should be kept consistent with that
// in LogFactoryImpl. However here we don't need to output info
// about the actual *instance* of LogFactory, as all methods that
// output diagnostics from this class are static.
String classLoaderName;
try {
ClassLoader classLoader = thisClassLoader;
if (thisClassLoader == null) {
classLoaderName = "BOOTLOADER";
} else {
classLoaderName = objectId(classLoader);
}
} catch(SecurityException e) {
classLoaderName = "UNKNOWN";
}
diagnosticPrefix = "[LogFactory from " + classLoaderName + "] ";
}
创建工厂仓库
环境变量是否指定了org.apache.commons.logging.LogFactory.HashtableImpl 的实现
没有就用默认的实现: org.apache.commons.logging.impl.WeakHashtable
默认实现创建失败时,使用jdk的 Hashtable
private static final Hashtable createFactoryStore() {
Hashtable result = null;
String storeImplementationClass;
try {
// public static final String HASHTABLE_IMPLEMENTATION_PROPERTY = "org.apache.commons.logging.LogFactory.HashtableImpl";
storeImplementationClass = getSystemProperty(HASHTABLE_IMPLEMENTATION_PROPERTY, null);
} catch(SecurityException ex) {
// Permissions don't allow this to be accessed. Default to the "modern"
// weak hashtable implementation if it is available.
storeImplementationClass = null;
}
if (storeImplementationClass == null) {
// private static final String WEAK_HASHTABLE_CLASSNAME =
"org.apache.commons.logging.impl.WeakHashtable";
storeImplementationClass = WEAK_HASHTABLE_CLASSNAME;
}
try {
Class implementationClass = Class.forName(storeImplementationClass);
result = (Hashtable) implementationClass.newInstance();
} catch (Throwable t) {
// ignore
if (!WEAK_HASHTABLE_CLASSNAME.equals(storeImplementationClass)) {
// if the user's trying to set up a custom implementation, give a clue
if (isDiagnosticsEnabled()) {
// use internal logging to issue the warning
logDiagnostic("[ERROR] LogFactory: Load of custom hashtable failed");
} else {
// we *really* want this output, even if diagnostics weren't
// explicitly enabled by the user.
System.err.println("[ERROR] LogFactory: Load of custom hashtable failed");
}
}
}
if (result == null) {
result = new Hashtable();
}
return result;
}
这个时候重新运行项目 加入jvm options : -Dorg.apache.commons.logging.diagnostics.dest=STDOUT
然后可以看到isDiagnosticsEnabled() 是否启用诊断信息为真:
控制台输出BOOTSTRAP COMPLETED
获取Log对象
现在开始真正进入获取Log对象的内部
public static Log getLog(Class clazz)
throws LogConfigurationException {
return (getFactory().getInstance(clazz));
}
里面的内容分为两部分:
1. getFactory
2. getInstance
getFactory 获取工厂
获取工厂的方法比较长,配上时序图不难理解
- 从缓存工厂获取LogFactory,获取到就直接返回
- 获取系统环境变量 org.apache.commons.logging.LogFactory 的值,成功就创建并返回
- 获取文件META-INF/services/org.apache.commons.logging.LogFactory 的内容
- 查找属性文件: commons-logging.properties 的key 为org.apache.commons.logging.LogFactory 的值
- 创建默认实现 org.apache.commons.logging.impl.LogFactoryImpl
- 将工厂加入到缓存,设置properties的内容到工厂的attributes属性中
说明: 通常不用设置 LogFactory 的值,就让他创建默认值就可以
public static LogFactory getFactory() throws LogConfigurationException {
// Identify the class loader we will be using
ClassLoader contextClassLoader = getContextClassLoaderInternal();
if (contextClassLoader == null) {
// This is an odd enough situation to report about. This
// output will be a nuisance on JDK1.1, as the system
// classloader is null in that environment.
if (isDiagnosticsEnabled()) {
logDiagnostic("Context classloader is null.");
}
}
// Return any previously registered factory for this class loader
// 从缓存工厂中获取内容,第一次初始化时返回null值
LogFactory factory = getCachedFactory(contextClassLoader);
if (factory != null) {
return factory;
}
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] LogFactory implementation requested for the first time for context classloader "
+ objectId(contextClassLoader));
logHierarchy("[LOOKUP] ", contextClassLoader);
}
// Load properties file.
//
// If the properties file exists, then its contents are used as
// "attributes" on the LogFactory implementation class. One particular
// property may also control which LogFactory concrete subclass is
// used, but only if other discovery mechanisms fail..
//
// As the properties file (if it exists) will be used one way or
// another in the end we may as well look for it first.
// public static final String FACTORY_PROPERTIES = "commons-logging.properties";
// 获取 commons-logging.properties 的内容读取为Properties 对象
Properties props = getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES);
// 当前例子中没有可以通过use_tccl = false 让baseClassLoader = thisClassLoader;
//然而没有意义,因为只有一个classLoader
// Determine whether we will be using the thread context class loader to
// load logging classes or not by checking the loaded properties file (if any).
ClassLoader baseClassLoader = contextClassLoader;
if (props != null) {
// public static final String TCCL_KEY = "use_tccl";
String useTCCLStr = props.getProperty(TCCL_KEY);
if (useTCCLStr != null) {
// The Boolean.valueOf(useTCCLStr).booleanValue() formulation
// is required for Java 1.2 compatability.
if (Boolean.valueOf(useTCCLStr).booleanValue() == false) {
// Don't use current context classloader when locating any
// LogFactory or Log classes, just use the class that loaded
// this abstract class. When this class is deployed in a shared
// classpath of a container, it means webapps cannot deploy their
// own logging implementations. It also means that it is up to the
// implementation whether to load library-specific config files
// from the TCCL or not.
baseClassLoader = thisClassLoader;
}
}
}
// Determine which concrete LogFactory subclass to use.
// First, try a global system property
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] Looking for system property [" + FACTORY_PROPERTY
+ "] to define the LogFactory subclass to use...");
}
// 获取系统环境变量 org.apache.commons.logging.LogFactory 的值
try {
String factoryClass = getSystemProperty(FACTORY_PROPERTY, null);
if (factoryClass != null) {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] Creating an instance of LogFactory class '" + factoryClass
+ "' as specified by system property " + FACTORY_PROPERTY);
}
factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);
} else {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] No system property [" + FACTORY_PROPERTY
+ "] defined.");
}
}
} catch (SecurityException e) {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] A security exception occurred while trying to create an"
+ " instance of the custom factory class"
+ ": [" + trim(e.getMessage())
+ "]. Trying alternative implementations...");
}
; // ignore
} catch(RuntimeException e) {
// This is not consistent with the behaviour when a bad LogFactory class is
// specified in a services file.
//
// One possible exception that can occur here is a ClassCastException when
// the specified class wasn't castable to this LogFactory type.
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] An exception occurred while trying to create an"
+ " instance of the custom factory class"
+ ": [" + trim(e.getMessage())
+ "] as specified by a system property.");
}
throw e;
}
// Second, try to find a service by using the JDK1.3 class
// discovery mechanism, which involves putting a file with the name
// of an interface class in the META-INF/services directory, where the
// contents of the file is a single line specifying a concrete class
// that implements the desired interface.
//查找文件META-INF/services/org.apache.commons.logging.LogFactory 的内容
if (factory == null) {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] Looking for a resource file of name [" + SERVICE_ID
+ "] to define the LogFactory subclass to use...");
}
try {
// protected static final String SERVICE_ID = "META-INF/services/org.apache.commons.logging.LogFactory";
InputStream is = getResourceAsStream(contextClassLoader,
SERVICE_ID);
if( is != null ) {
// This code is needed by EBCDIC and other strange systems.
// It's a fix for bugs reported in xerces
BufferedReader rd;
try {
rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
} catch (java.io.UnsupportedEncodingException e) {
rd = new BufferedReader(new InputStreamReader(is));
}
String factoryClassName = rd.readLine();
rd.close();
if (factoryClassName != null &&
! "".equals(factoryClassName)) {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] Creating an instance of LogFactory class " + factoryClassName
+ " as specified by file '" + SERVICE_ID
+ "' which was present in the path of the context"
+ " classloader.");
}
factory = newFactory(factoryClassName, baseClassLoader, contextClassLoader );
}
} else {
// is == null
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] No resource file with name '" + SERVICE_ID
+ "' found.");
}
}
} catch( Exception ex ) {
// note: if the specified LogFactory class wasn't compatible with LogFactory
// for some reason, a ClassCastException will be caught here, and attempts will
// continue to find a compatible class.
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] A security exception occurred while trying to create an"
+ " instance of the custom factory class"
+ ": [" + trim(ex.getMessage())
+ "]. Trying alternative implementations...");
}
; // ignore
}
}
// Third try looking into the properties file read earlier (if found)
// 查找属性文件: commons-logging.properties 的key 为org.apache.commons.logging.LogFactory 的值
if (factory == null) {
if (props != null) {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] Looking in properties file for entry with key '"
+ FACTORY_PROPERTY
+ "' to define the LogFactory subclass to use...");
}
String factoryClass = props.getProperty(FACTORY_PROPERTY);
if (factoryClass != null) {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] Properties file specifies LogFactory subclass '"
+ factoryClass + "'");
}
factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);
// TODO: think about whether we need to handle exceptions from newFactory
} else {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] Properties file has no entry specifying LogFactory subclass.");
}
}
} else {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] No properties file available to determine"
+ " LogFactory subclass from..");
}
}
}
// Fourth, try the fallback implementation class
// 创建默认实现
// public static final String FACTORY_DEFAULT ="org.apache.commons.logging.impl.LogFactoryImpl";
if (factory == null) {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[LOOKUP] Loading the default LogFactory implementation '" + FACTORY_DEFAULT
+ "' via the same classloader that loaded this LogFactory"
+ " class (ie not looking in the context classloader).");
}
// Note: unlike the above code which can try to load custom LogFactory
// implementations via the TCCL, we don't try to load the default LogFactory
// implementation via the context classloader because:
// * that can cause problems (see comments in newFactory method)
// * no-one should be customising the code of the default class
// Yes, we do give up the ability for the child to ship a newer
// version of the LogFactoryImpl class and have it used dynamically
// by an old LogFactory class in the parent, but that isn't
// necessarily a good idea anyway.
factory = newFactory(FACTORY_DEFAULT, thisClassLoader, contextClassLoader);
}
if (factory != null) {
/**
* Always cache using context class loader.
*/
// 加入工厂到缓存
cacheFactory(contextClassLoader, factory);
// 设置工厂的attributes
if( props!=null ) {
Enumeration names = props.propertyNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
String value = props.getProperty(name);
factory.setAttribute(name, value);
}
}
}
return factory;
}
获得Log对象
org.apache.commons.logging.impl.LogFactoryImpl
public Log getInstance(Class clazz) throws LogConfigurationException {
//通过类的全限定名去获取Log对象
return (getInstance(clazz.getName()));
}
通过类的全限定名去获取Log对象
public Log getInstance(String name) throws LogConfigurationException {
//Log 对象实例池instances(Hashtable),实例变量,线程安全
Log instance = (Log) instances.get(name);
if (instance == null) {
// 创建对象
instance = newInstance(name);
// 加入到实例池
instances.put(name, instance);
}
return (instance);
}
创建实例:newInstance
这段内容的分析就只有一个地方: discoverLogImplementation
protected Log newInstance(String name) throws LogConfigurationException {
Log instance = null;
try {
// 日志构造对象
if (logConstructor == null) {
// 创建实例
instance = discoverLogImplementation(name);
}
else {
Object params[] = { name };
instance = (Log) logConstructor.newInstance(params);
}
// 当配置的类实现了setFactory的时候,就会执行 logMethod
if (logMethod != null) {
Object params[] = { this };
logMethod.invoke(instance, params);
}
return (instance);
} catch (LogConfigurationException lce) {
throw (LogConfigurationException) lce;
} catch (InvocationTargetException e) {
Throwable c = e.getTargetException();
if (c != null) {
throw new LogConfigurationException(c);
} else {
throw new LogConfigurationException(e);
}
} catch (Throwable t) {
throw new LogConfigurationException(t);
}
}
跟进:discoverLogImplementation
- 初始化配置 (initConfiguration)
- 获取配置 org.apache.commons.logging.Log (findUserSpecifiedLogClassName)
- 创建日志对象 (createLogFromClass)
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
// 获取用户指定的日志类名 **重点**
// 获取到 commons-logging.properties 里面的配置里面 org.apache.commons.logging.Log的值
// specifiedLogClassName = org.apache.commons.logging.impl.SimpleLog
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
if (specifiedLogClassName != null) {
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;
}
initConfiguration 分析
private void initConfiguration() {
allowFlawedContext = getBooleanConfiguration(ALLOW_FLAWED_CONTEXT_PROPERTY, true);
allowFlawedDiscovery = getBooleanConfiguration(ALLOW_FLAWED_DISCOVERY_PROPERTY, true);
allowFlawedHierarchy = getBooleanConfiguration(ALLOW_FLAWED_HIERARCHY_PROPERTY, true);
}
获取配置的值,如果配置不存在就用默认值
//key 键
//dflt默认值
private boolean getBooleanConfiguration(String key, boolean dflt) {
//获取配置的值
String val = getConfigurationValue(key);
// 返回为null时,用默认值
if (val == null)
return dflt;
return Boolean.valueOf(val).booleanValue();
}
获取配置的值
- 从 LogFactoryImpl的attributes中获取,获取到就返回
- 从 系统环境变量中获取,获取到就返回
- 返回null
private String getConfigurationValue(String property) {
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] Trying to get configuration for item " + property);
}
1. 从 LogFactoryImpl的attributes中获取,获取到就返回
Object valueObj = getAttribute(property);
if (valueObj != null) {
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] Found LogFactory attribute [" + valueObj + "] for " + property);
}
return valueObj.toString();
}
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] No LogFactory attribute found for " + property);
}
2. 从 系统环境变量中获取,获取到就返回
try {
String value = getSystemProperty(property, null);
if (value != null) {
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] Found system property [" + value + "] for " + property);
}
return value;
}
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] No system property found for property " + property);
}
} catch (SecurityException e) {
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] Security prevented reading system property " + property);
}
}
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] No configuration defined for item " + property);
}
3. 返回null
return null;
}
获取用户指定的日志配置 findUserSpecifiedLogClassName
获取 org.apache.commons.logging.Log的值
1. 从attributes中获取 LOG_PROPERTY
2. 从attributes中获取 LOG_PROPERTY_OLD
3. 从系统环境变量中获取
去除先后空格trim
private String findUserSpecifiedLogClassName()
{
// public static final String LOG_PROPERTY = "org.apache.commons.logging.Log";
// protected static final String LOG_PROPERTY_OLD = "org.apache.commons.logging.log";
if (isDiagnosticsEnabled()) {
logDiagnostic("Trying to get log class from attribute '" + LOG_PROPERTY + "'");
}
//获取到org.apache.commons.logging.Log的值
String specifiedClass = (String) getAttribute(LOG_PROPERTY);
if (specifiedClass == null) { // @deprecated
if (isDiagnosticsEnabled()) {
logDiagnostic("Trying to get log class from attribute '" +
LOG_PROPERTY_OLD + "'");
}
specifiedClass = (String) getAttribute(LOG_PROPERTY_OLD);
}
if (specifiedClass == null) {
if (isDiagnosticsEnabled()) {
logDiagnostic("Trying to get log class from system property '" +
LOG_PROPERTY + "'");
}
try {
specifiedClass = getSystemProperty(LOG_PROPERTY, null);
} catch (SecurityException e) {
if (isDiagnosticsEnabled()) {
logDiagnostic("No access allowed to system property '" +
LOG_PROPERTY + "' - " + e.getMessage());
}
}
}
if (specifiedClass == null) { // @deprecated
if (isDiagnosticsEnabled()) {
logDiagnostic("Trying to get log class from system property '" +
LOG_PROPERTY_OLD + "'");
}
try {
specifiedClass = getSystemProperty(LOG_PROPERTY_OLD, null);
} catch (SecurityException e) {
if (isDiagnosticsEnabled()) {
logDiagnostic("No access allowed to system property '" +
LOG_PROPERTY_OLD + "' - " + e.getMessage());
}
}
}
// Remove any whitespace; it's never valid in a classname so its
// presence just means a user mistake. As we know what they meant,
// we may as well strip the spaces.
// 去除空格
if (specifiedClass != null) {
specifiedClass = specifiedClass.trim();
}
return specifiedClass;
}
创建Log对象 createLogFromClass
1. 根据类的全限定名 logAdapterClassName 去获取资源
2. 在baseClassLoader加载器中加载 logAdapterClassName
3. 找配置的org.apache.commons.logging.Log 是不是有setLogFactory 方法,找到了就修改当前的this.logMethod,异常就 this.logMethod = null
private Log createLogFromClass(String logAdapterClassName,
String logCategory,
boolean affectState)
throws LogConfigurationException {
if (isDiagnosticsEnabled()) {
logDiagnostic("Attempting to instantiate '" + logAdapterClassName + "'");
}
Object[] params = { logCategory };
Log logAdapter = null;
Constructor constructor = null;
Class logAdapterClass = null;
ClassLoader currentCL = getBaseClassLoader();
for(;;) {
// Loop through the classloader hierarchy trying to find
// a viable classloader.
logDiagnostic(
"Trying to load '"
+ logAdapterClassName
+ "' from classloader "
+ objectId(currentCL));
try {
if (isDiagnosticsEnabled()) {
URL url;
//1. 根据类的全限定名 logAdapterClassName 去获取资源
String resourceName = logAdapterClassName.replace('.', '/') + ".class";
if (currentCL != null) {
// 获得资源
// 内容: jar:file:/E:/around/maven_store/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar!/org/apache/commons/logging/impl/SimpleLog.class
url = currentCL.getResource(resourceName );
} else {
url = ClassLoader.getSystemResource(resourceName + ".class");
}
if (url == null) {
logDiagnostic("Class '" + logAdapterClassName + "' [" + resourceName + "] cannot be found.");
} else {
logDiagnostic("Class '" + logAdapterClassName + "' was found at '" + url + "'");
}
}
Class c = null;
try {
c = Class.forName(logAdapterClassName, true, currentCL);
} catch (ClassNotFoundException originalClassNotFoundException) {
String msg = "" + originalClassNotFoundException.getMessage();
logDiagnostic(
"The log adapter '"
+ logAdapterClassName
+ "' is not available via classloader "
+ objectId(currentCL)
+ ": "
+ msg.trim());
try {
c = Class.forName(logAdapterClassName);
} catch (ClassNotFoundException secondaryClassNotFoundException) {
// no point continuing: this adapter isn't available
msg = "" + secondaryClassNotFoundException.getMessage();
logDiagnostic(
"The log adapter '"
+ logAdapterClassName
+ "' is not available via the LogFactoryImpl class classloader: "
+ msg.trim());
break;
}
}
// 找到构造器 Constructor(String)
constructor = c.getConstructor(logConstructorSignature);
// 创建对象
Object o = constructor.newInstance(params);
//o 是log对象就返回
if (o instanceof Log) {
logAdapterClass = c;
logAdapter = (Log) o;
break;
}
handleFlawedHierarchy(currentCL, c);
} catch (NoClassDefFoundError e) {
String msg = "" + e.getMessage();
logDiagnostic(
"The log adapter '"
+ logAdapterClassName
+ "' is missing dependencies when loaded via classloader "
+ objectId(currentCL)
+ ": "
+ msg.trim());
break;
} catch (ExceptionInInitializerError e) {
String msg = "" + e.getMessage();
logDiagnostic(
"The log adapter '"
+ logAdapterClassName
+ "' is unable to initialize itself when loaded via classloader "
+ objectId(currentCL)
+ ": "
+ msg.trim());
break;
} catch(LogConfigurationException e) {
throw e;
} catch(Throwable t) {
handleFlawedDiscovery(logAdapterClassName, currentCL, t);
}
if (currentCL == null) {
break;
}
currentCL = getParentClassLoader(currentCL);
}
// 退出循环体
if ((logAdapter != null) && affectState) {
// We've succeeded, so set instance fields
this.logClassName = logAdapterClassName;
this.logConstructor = constructor;
// Identify the <code>setLogFactory</code> method (if there is one)
try {
// 找配置的org.apache.commons.logging.Log 是不是有setLogFactory 方法
this.logMethod = logAdapterClass.getMethod("setLogFactory",
logMethodSignature);
logDiagnostic("Found method setLogFactory(LogFactory) in '"
+ logAdapterClassName + "'");
} catch (Throwable t) {
this.logMethod = null;
logDiagnostic(
"[INFO] '" + logAdapterClassName
+ "' from classloader " + objectId(currentCL)
+ " does not declare optional method "
+ "setLogFactory(LogFactory)");
}
logDiagnostic(
"Log adapter '" + logAdapterClassName
+ "' from classloader " + objectId(logAdapterClass.getClassLoader())
+ " has been selected for use.");
}
return logAdapter;
}