commons-logging 源码分析

目录

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 获取工厂

获取工厂的方法比较长,配上时序图不难理解

  1. 从缓存工厂获取LogFactory,获取到就直接返回
  2. 获取系统环境变量 org.apache.commons.logging.LogFactory 的值,成功就创建并返回
  3. 获取文件META-INF/services/org.apache.commons.logging.LogFactory 的内容
  4. 查找属性文件: commons-logging.properties 的key 为org.apache.commons.logging.LogFactory 的值
  5. 创建默认实现 org.apache.commons.logging.impl.LogFactoryImpl
  6. 将工厂加入到缓存,设置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
  1. 初始化配置 (initConfiguration)
  2. 获取配置 org.apache.commons.logging.Log (findUserSpecifiedLogClassName)
  3. 创建日志对象 (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();
    }
获取配置的值
  1. 从 LogFactoryImpl的attributes中获取,获取到就返回
  2. 从 系统环境变量中获取,获取到就返回
  3. 返回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;
    }
"Unresolved dependency: 'commons-logging:commons-logging:jar:unknown'" 这个错误通常发生在Maven或Gradle构建工具中,表示项目依赖于`commons-logging`库的一个未知版本。这个错误可能是由于以下几个原因: 1. **依赖声明缺失**:检查你的项目的pom.xml(Maven)或build.gradle(Gradle)文件,确认`commons-logging`模块是否已经添加到dependencies块,并且版本信息已正确指定。 ```xml <!-- Maven 示例 --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> <!-- 替换为你需要的实际版本 --> </dependency> // Gradle 示例 implementation 'commons-logging:commons-logging:1.2' // 同样替换为实际版本 ``` 2. **网络连接问题**:确保你的网络连接正常,因为某些时候仓库可能无法访问。尝试清理本地的maven或gradle缓存,然后重新同步依赖。 ```bash # Maven 清理 mvn clean mvn install # Gradle 清理 ./gradlew clean --refresh-dependencies ``` 3. **更新仓库列表**:如果你的POM.xml或build.gradle里指定了特定的仓库URL,确认这个仓库包含了你需要的版本。如果不确定,可以尝试将本地仓库设置为中央仓库或其他公共仓库。 4. **使用替代包**:有时,项目可能会推荐使用其他库来替代`commons-logging`,如`log4j`或`slf4j`等。查看文档看是否有替代方案。 5. **检查版本冲突**:如果有多个依赖有对`commons-logging`的不同版本引用,确保它们不会互相冲突。你可以使用插件如Maven Dependency Analyzer或Gradle的Dependency Graph查看潜在冲突。 如果以上步骤都不能解决问题,检查错误日志的详细信息,或者尝试在开发者社区寻求帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值