publicstaticorg.apache.commons.logging.LogFactorygetFactory() throws LogConfigurationException {// Identify the class loader we will be usingClassLoader 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 loaderorg.apache.commons.logging.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.// classpath根目录下寻找commons-logging.propertiesProperties props =getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES);// 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).// classpath根目录下commons-logging.properties是否配置use_tcclClassLoader baseClassLoader = contextClassLoader;if (props !=null) {String useTCCLStr =props.getProperty(TCCL_KEY);if (useTCCLStr !=null) {// The Boolean.valueOf(useTCCLStr).booleanValue() formulation// is required for Java 1.2 compatibility.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; } } }// 这里真正开始决定使用哪个factory// 首先,尝试查找vm系统属性org.apache.commons.logging.LogFactory,其是否指定factory// Determine which concrete LogFactory subclass to use.// First, try a global system propertyif (isDiagnosticsEnabled()) {logDiagnostic("[LOOKUP] Looking for system property ["+ FACTORY_PROPERTY +"] to define the LogFactory subclass to use..."); }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; }// 第二,尝试使用java spi服务发现机制,载META-INF/services下寻找org.apache.commons.logging.LogFactory实现// 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.if (factory ==null) {if (isDiagnosticsEnabled()) {logDiagnostic("[LOOKUP] Looking for a resource file of name ["+ SERVICE_ID +"] to define the LogFactory subclass to use..."); }try {// META-INF/services/org.apache.commons.logging.LogFactory, SERVICE_IDfinalInputStream 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 xercesBufferedReader rd;try { rd =newBufferedReader(new InputStreamReader(is,"UTF-8")); } catch (java.io.UnsupportedEncodingException e) { rd =newBufferedReader(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 == nullif (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 } }// 第三,尝试从classpath根目录下的commons-logging.properties中查找org.apache.commons.logging.LogFactory属性指定的factory// Third try looking into the properties file read earlier (if found)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.."); } } }// 最后,使用后备factory实现,org.apache.commons.logging.impl.LogFactoryImpl// Fourth, try the fallback implementation classif (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);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;}