📄 logfactory.java
字号:
return classLoader; } /** * Check cached factories (keyed by contextClassLoader) * * @param contextClassLoader is the context classloader associated * with the current thread. This allows separate LogFactory objects * per component within a container, provided each component has * a distinct context classloader set. This parameter may be null * in JDK1.1, and in embedded systems where jcl-using code is * placed in the bootclasspath. * * @return the factory associated with the specified classloader if * one has previously been created, or null if this is the first time * we have seen this particular classloader. */ private static LogFactory getCachedFactory(ClassLoader contextClassLoader) { LogFactory factory = null; if (contextClassLoader == null) { // We have to handle this specially, as factories is a Hashtable // and those don't accept null as a key value. // // nb: nullClassLoaderFactory might be null. That's ok. factory = nullClassLoaderFactory; } else { factory = (LogFactory) factories.get(contextClassLoader); } return factory; } /** * Remember this factory, so later calls to LogFactory.getCachedFactory * can return the previously created object (together with all its * cached Log objects). * * @param classLoader should be the current context classloader. Note that * this can be null under some circumstances; this is ok. * * @param factory should be the factory to cache. This should never be null. */ private static void cacheFactory(ClassLoader classLoader, LogFactory factory) { // Ideally we would assert(factory != null) here. However reporting // errors from within a logging implementation is a little tricky! if (factory != null) { if (classLoader == null) { nullClassLoaderFactory = factory; } else { factories.put(classLoader, factory); } } } /** * Return a new instance of the specified <code>LogFactory</code> * implementation class, loaded by the specified class loader. * If that fails, try the class loader used to load this * (abstract) LogFactory. * <p> * <h2>ClassLoader conflicts</h2> * Note that there can be problems if the specified ClassLoader is not the * same as the classloader that loaded this class, ie when loading a * concrete LogFactory subclass via a context classloader. * <p> * The problem is the same one that can occur when loading a concrete Log * subclass via a context classloader. * <p> * The problem occurs when code running in the context classloader calls * class X which was loaded via a parent classloader, and class X then calls * LogFactory.getFactory (either directly or via LogFactory.getLog). Because * class X was loaded via the parent, it binds to LogFactory loaded via * the parent. When the code in this method finds some LogFactoryYYYY * class in the child (context) classloader, and there also happens to be a * LogFactory class defined in the child classloader, then LogFactoryYYYY * will be bound to LogFactory@childloader. It cannot be cast to * LogFactory@parentloader, ie this method cannot return the object as * the desired type. Note that it doesn't matter if the LogFactory class * in the child classloader is identical to the LogFactory class in the * parent classloader, they are not compatible. * <p> * The solution taken here is to simply print out an error message when * this occurs then throw an exception. The deployer of the application * must ensure they remove all occurrences of the LogFactory class from * the child classloader in order to resolve the issue. Note that they * do not have to move the custom LogFactory subclass; that is ok as * long as the only LogFactory class it can find to bind to is in the * parent classloader. * <p> * @param factoryClass Fully qualified name of the <code>LogFactory</code> * implementation class * @param classLoader ClassLoader from which to load this class * @param contextClassLoader is the context that this new factory will * manage logging for. * * @exception LogConfigurationException if a suitable instance * cannot be created * @since 1.1 */ protected static LogFactory newFactory(final String factoryClass, final ClassLoader classLoader, final ClassLoader contextClassLoader) throws LogConfigurationException { // Note that any unchecked exceptions thrown by the createFactory // method will propagate out of this method; in particular a // ClassCastException can be thrown. Object result = AccessController.doPrivileged( new PrivilegedAction() { public Object run() { return createFactory(factoryClass, classLoader); } }); if (result instanceof LogConfigurationException) { LogConfigurationException ex = (LogConfigurationException) result; if (isDiagnosticsEnabled()) { logDiagnostic( "An error occurred while loading the factory class:" + ex.getMessage()); } throw ex; } if (isDiagnosticsEnabled()) { logDiagnostic( "Created object " + objectId(result) + " to manage classloader " + objectId(contextClassLoader)); } return (LogFactory)result; } /** * Method provided for backwards compatibility; see newFactory version that * takes 3 parameters. * <p> * This method would only ever be called in some rather odd situation. * Note that this method is static, so overriding in a subclass doesn't * have any effect unless this method is called from a method in that * subclass. However this method only makes sense to use from the * getFactory method, and as that is almost always invoked via * LogFactory.getFactory, any custom definition in a subclass would be * pointless. Only a class with a custom getFactory method, then invoked * directly via CustomFactoryImpl.getFactory or similar would ever call * this. Anyway, it's here just in case, though the "managed class loader" * value output to the diagnostics will not report the correct value. */ protected static LogFactory newFactory(final String factoryClass, final ClassLoader classLoader) { return newFactory(factoryClass, classLoader, null); } /** * Implements the operations described in the javadoc for newFactory. * * @param factoryClass * * @param classLoader used to load the specified factory class. This is * expected to be either the TCCL or the classloader which loaded this * class. Note that the classloader which loaded this class might be * "null" (ie the bootloader) for embedded systems. * * @return either a LogFactory object or a LogConfigurationException object. * @since 1.1 */ protected static Object createFactory(String factoryClass, ClassLoader classLoader) { // This will be used to diagnose bad configurations // and allow a useful message to be sent to the user Class logFactoryClass = null; try { if (classLoader != null) { try { // First the given class loader param (thread class loader) // Warning: must typecast here & allow exception // to be generated/caught & recast properly. logFactoryClass = classLoader.loadClass(factoryClass); if (LogFactory.class.isAssignableFrom(logFactoryClass)) { if (isDiagnosticsEnabled()) { logDiagnostic( "Loaded class " + logFactoryClass.getName() + " from classloader " + objectId(classLoader)); } } else { // // This indicates a problem with the ClassLoader tree. // An incompatible ClassLoader was used to load the // implementation. // As the same classes // must be available in multiple class loaders, // it is very likely that multiple JCL jars are present. // The most likely fix for this // problem is to remove the extra JCL jars from the // ClassLoader hierarchy. // if (isDiagnosticsEnabled()) { logDiagnostic( "Factory class " + logFactoryClass.getName() + " loaded from classloader " + objectId(logFactoryClass.getClassLoader()) + " does not extend '" + LogFactory.class.getName() + "' as loaded by this classloader."); logHierarchy("[BAD CL TREE] ", classLoader); } } return (LogFactory) logFactoryClass.newInstance(); } catch (ClassNotFoundException ex) { if (classLoader == thisClassLoader) { // Nothing more to try, onwards. if (isDiagnosticsEnabled()) { logDiagnostic( "Unable to locate any class called '" + factoryClass + "' via classloader " + objectId(classLoader)); } throw ex; } // ignore exception, continue } catch (NoClassDefFoundError e) { if (classLoader == thisClassLoader) { // Nothing more to try, onwards. if (isDiagnosticsEnabled()) { logDiagnostic( "Class '" + factoryClass + "' cannot be loaded" + " via classloader " + objectId(classLoader) + " - it depends on some other class that cannot" + " be found."); } throw e; } // ignore exception, continue } catch(ClassCastException e) { if (classLoader == thisClassLoader) { // There's no point in falling through to the code below that // tries again with thisClassLoader, because we've just tried // loading with that loader (not the TCCL). Just throw an // appropriate exception here. final boolean implementsLogFactory = implementsLogFactory(logFactoryClass); // // Construct a good message: users may not actual expect that a custom implementation // has been specified. Several well known containers use this mechanism to adapt JCL // to their native logging system. // String msg = "The application has specified that a custom LogFactory implementation should be used but " + "Class '" + factoryClass + "' cannot be converted to '" + LogFactory.class.getName() + "'. "; if (implementsLogFactory) { msg = msg + "The conflict is caused by the presence of multiple LogFactory classes in incompatible classloaders. " + "Background can be found in http://jakarta.apache.org/commons/logging/tech.html. " + "If you have not explicitly specified a custom LogFactory then it is likely that " + "the container has set one without your knowledge. " + "In this case, consider using the commons-logging-adapters.jar file or " + "specifying the standard LogFactory from the command line. "; } else { msg = msg + "Please check the custom implementation. "; } msg = msg + "Help can be found @http://jakarta.apache.org/commons/logging/troubleshooting.html."; if (isDiagnosticsEnabled()) { logDiagnostic(msg); } ClassCastException ex = new ClassCastException(msg); throw ex; } // Ignore exception, continue. Presumably the classloader was the // TCCL; the code below will try to load the class via thisClassLoader. // This will handle the case where the original calling class is in // a shared classpath but the TCCL has a copy of LogFactory and the // specified LogFactory implementation; we will fall back to using the // LogFactory implementation from the same classloader as this class. // // Issue: this doesn't handle the reverse case, where this LogFactory // is in the webapp, and the specified LogFactory implementation is // in a shared classpath. In that case: // (a) the class really does implement LogFactory (bad log msg above) // (b) the fallback code will result in exactly the same problem. } } /* At this point, either classLoader == null, OR * classLoader was unable to load factoryClass. * * In either case, we call Class.forName, which is equivalent * to LogFactory.class.getClassLoader().load(name), ie we ignore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -