假设有四个项目,分别为:Web 项目、Common项目、File 项目和 DB 项目。web 项目负责对外提供服务,Common项目是一个公共项目,File 项目负责内部文件管理,DB 项目负责内部的数据库管理。Web项目依赖于 Common项目、File项目以及 DB 项目,File 项目和 DB 项目依赖于 Common项目。
graph BT
A(Common项目) --> B(Web项目)
C(File项目) --> B
A --> C
D(DB项目) --> B
A --> D
publicstatic org.apache.commons.logging.LogFactory getFactory()throws LogConfigurationException { // Identify the class loader we will be using ClassLoadercontextClassLoader= 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. // ... }
// Return any previously registered factory for this class loader org.apache.commons.logging.LogFactoryfactory= getCachedFactory(contextClassLoader); if (factory != null) { return factory; }
// classpath根目录下commons-logging.properties是否配置use_tccl ClassLoaderbaseClassLoader= contextClassLoader; if (props != null) { StringuseTCCLStr= 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 // ... try { StringfactoryClass= getSystemProperty(FACTORY_PROPERTY, null); if (factoryClass != null) { // ... factory = newFactory(factoryClass, baseClassLoader, contextClassLoader); } else { // ... } } catch (SecurityException e) { // ... // 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. // ... throw e; }
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 = newBufferedReader(newInputStreamReader(is, "UTF-8")); } catch (java.io.UnsupportedEncodingException e) { rd = newBufferedReader(newInputStreamReader(is)); }
if (factoryClassName != null && !"".equals(factoryClassName)) { // ... factory = newFactory(factoryClassName, baseClassLoader, contextClassLoader); } } else { // is == null // ... } } 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. // ... } }
// 第三,尝试从classpath根目录下的commons-logging.properties中查找org.apache.commons.logging.LogFactory属性指定的factory if (factory == null) { if (props != null) { // ... StringfactoryClass= props.getProperty(FACTORY_PROPERTY); if (factoryClass != null) { // ... factory = newFactory(factoryClass, baseClassLoader, contextClassLoader); // TODO: think about whether we need to handle exceptions from newFactory } else { // ... } } else { // ... } }
// 最后,使用后备factory实现,org.apache.commons.logging.impl.LogFactoryImpl if (factory == null) { // 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);