📄 logfactoryimpl.java
字号:
// has been found and its underlying lib is present too, but
// there are multiple Log interface classes available making it
// impossible to cast to the type the caller wanted. We
// certainly can't use this logger, but we need to know whether
// to keep on discovering or terminate now.
//
// The handleFlawedHierarchy method will throw
// LogConfigurationException if it regards this problem as
// fatal, and just return if not.
handleFlawedHierarchy(currentCL, c);
} catch (NoClassDefFoundError e) {
// We were able to load the adapter but it had references to
// other classes that could not be found. This simply means that
// the underlying logger library is not present in this or any
// ancestor classloader. There's no point in trying higher up
// in the hierarchy in this case..
String msg = "" + e.getMessage();
logDiagnostic(
"The log adapter '"
+ logAdapterClassName
+ "' is missing dependencies when loaded via classloader "
+ objectId(currentCL)
+ ": "
+ msg.trim());
break;
} catch (ExceptionInInitializerError e) {
// A static initializer block or the initializer code associated
// with a static variable on the log adapter class has thrown
// an exception.
//
// We treat this as meaning the adapter's underlying logging
// library could not be found.
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) {
// call to handleFlawedHierarchy above must have thrown
// a LogConfigurationException, so just throw it on
throw e;
} catch(Throwable t) {
// handleFlawedDiscovery will determine whether this is a fatal
// problem or not. If it is fatal, then a LogConfigurationException
// will be thrown.
handleFlawedDiscovery(logAdapterClassName, currentCL, t);
}
if (currentCL == null) {
break;
}
// try the parent classloader
// currentCL = currentCL.getParent();
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 {
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;
}
/**
* Return the classloader from which we should try to load the logging
* adapter classes.
* <p>
* This method usually returns the context classloader. However if it
* is discovered that the classloader which loaded this class is a child
* of the context classloader <i>and</i> the allowFlawedContext option
* has been set then the classloader which loaded this class is returned
* instead.
* <p>
* The only time when the classloader which loaded this class is a
* descendant (rather than the same as or an ancestor of the context
* classloader) is when an app has created custom classloaders but
* failed to correctly set the context classloader. This is a bug in
* the calling application; however we provide the option for JCL to
* simply generate a warning rather than fail outright.
*
*/
private ClassLoader getBaseClassLoader() throws LogConfigurationException {
ClassLoader thisClassLoader = getClassLoader(LogFactoryImpl.class);
if (useTCCL == false) {
return thisClassLoader;
}
ClassLoader contextClassLoader = getContextClassLoaderInternal();
ClassLoader baseClassLoader = getLowestClassLoader(
contextClassLoader, thisClassLoader);
if (baseClassLoader == null) {
// The two classloaders are not part of a parent child relationship.
// In some classloading setups (e.g. JBoss with its
// UnifiedLoaderRepository) this can still work, so if user hasn't
// forbidden it, just return the contextClassLoader.
if (allowFlawedContext) {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"[WARNING] the context classloader is not part of a"
+ " parent-child relationship with the classloader that"
+ " loaded LogFactoryImpl.");
}
// If contextClassLoader were null, getLowestClassLoader() would
// have returned thisClassLoader. The fact we are here means
// contextClassLoader is not null, so we can just return it.
return contextClassLoader;
}
else {
throw new LogConfigurationException(
"Bad classloader hierarchy; LogFactoryImpl was loaded via"
+ " a classloader that is not related to the current context"
+ " classloader.");
}
}
if (baseClassLoader != contextClassLoader) {
// We really should just use the contextClassLoader as the starting
// point for scanning for log adapter classes. However it is expected
// that there are a number of broken systems out there which create
// custom classloaders but fail to set the context classloader so
// we handle those flawed systems anyway.
if (allowFlawedContext) {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"Warning: the context classloader is an ancestor of the"
+ " classloader that loaded LogFactoryImpl; it should be"
+ " the same or a descendant. The application using"
+ " commons-logging should ensure the context classloader"
+ " is used correctly.");
}
} else {
throw new LogConfigurationException(
"Bad classloader hierarchy; LogFactoryImpl was loaded via"
+ " a classloader that is not related to the current context"
+ " classloader.");
}
}
return baseClassLoader;
}
/**
* Given two related classloaders, return the one which is a child of
* the other.
* <p>
* @param c1 is a classloader (including the null classloader)
* @param c2 is a classloader (including the null classloader)
*
* @return c1 if it has c2 as an ancestor, c2 if it has c1 as an ancestor,
* and null if neither is an ancestor of the other.
*/
private ClassLoader getLowestClassLoader(ClassLoader c1, ClassLoader c2) {
// TODO: use AccessController when dealing with classloaders here
if (c1 == null)
return c2;
if (c2 == null)
return c1;
ClassLoader current;
// scan c1's ancestors to find c2
current = c1;
while (current != null) {
if (current == c2)
return c1;
current = current.getParent();
}
// scan c2's ancestors to find c1
current = c2;
while (current != null) {
if (current == c1)
return c2;
current = current.getParent();
}
return null;
}
/**
* Generates an internal diagnostic logging of the discovery failure and
* then throws a <code>LogConfigurationException</code> that wraps
* the passed <code>Throwable</code>.
*
* @param logAdapterClassName is the class name of the Log implementation
* that could not be instantiated. Cannot be <code>null</code>.
*
* @param classLoader is the classloader that we were trying to load the
* logAdapterClassName from when the exception occurred.
*
* @param discoveryFlaw is the Throwable created by the classloader
*
* @throws LogConfigurationException ALWAYS
*/
private void handleFlawedDiscovery(String logAdapterClassName,
ClassLoader classLoader,
Throwable discoveryFlaw) {
if (isDiagnosticsEnabled()) {
logDiagnostic("Could not instantiate Log '"
+ logAdapterClassName + "' -- "
+ discoveryFlaw.getClass().getName() + ": "
+ discoveryFlaw.getLocalizedMessage());
if (discoveryFlaw instanceof InvocationTargetException ) {
// Ok, the lib is there but while trying to create a real underlying
// logger something failed in the underlying lib; display info about
// that if possible.
InvocationTargetException ite = (InvocationTargetException)discoveryFlaw;
Throwable cause = ite.getTargetException();
if (cause != null) {
logDiagnostic("... InvocationTargetException: " +
cause.getClass().getName() + ": " +
cause.getLocalizedMessage());
if (cause instanceof ExceptionInInitializerError) {
ExceptionInInitializerError eiie = (ExceptionInInitializerError)cause;
Throwable cause2 = eiie.getException();
if (cause2 != null) {
logDiagnostic("... ExceptionInInitializerError: " +
cause2.getClass().getName() + ": " +
cause2.getLocalizedMessage());
}
}
}
}
}
if (!allowFlawedDiscovery) {
throw new LogConfigurationException(discoveryFlaw);
}
}
/**
* Report a problem loading the log adapter, then either return
* (if the situation is considered recoverable) or throw a
* LogConfigurationException.
* <p>
* There are two possible reasons why we successfully loaded the
* specified log adapter class then failed to cast it to a Log object:
* <ol>
* <li>the specific class just doesn't implement the Log interface
* (user screwed up), or
* <li> the specified class has bound to a Log class loaded by some other
* classloader; Log@classloaderX cannot be cast to Log@classloaderY.
* </ol>
* <p>
* Here we try to figure out which case has occurred so we can give the
* user some reasonable feedback.
*
* @param badClassLoader is the classloader we loaded the problem class from,
* ie it is equivalent to badClass.getClassLoader().
*
* @param badClass is a Class object with the desired name, but which
* does not implement Log correctly.
*
* @throws LogConfigurationException when the situation
* should not be recovered from.
*/
private void handleFlawedHierarchy(ClassLoader badClassLoader, Class badClass)
throws LogConfigurationException {
boolean implementsLog = false;
String logInterfaceName = Log.class.getName();
Class interfaces[] = badClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
if (logInterfaceName.equals(interfaces[i].getName())) {
implementsLog = true;
break;
}
}
if (implementsLog) {
// the class does implement an interface called Log, but
// it is in the wrong classloader
if (isDiagnosticsEnabled()) {
try {
ClassLoader logInterfaceClassLoader = getClassLoader(Log.class);
logDiagnostic(
"Class '" + badClass.getName()
+ "' was found in classloader "
+ objectId(badClassLoader)
+ ". It is bound to a Log interface which is not"
+ " the one loaded from classloader "
+ objectId(logInterfaceClassLoader));
} catch (Throwable t) {
logDiagnostic(
"Error while trying to output diagnostics about"
+ " bad class '" + badClass + "'");
}
}
if (!allowFlawedHierarchy) {
StringBuffer msg = new StringBuffer();
msg.append("Terminating logging for this context ");
msg.append("due to bad log hierarchy. ");
msg.append("You have more than one version of '");
msg.append(Log.class.getName());
msg.append("' visible.");
if (isDiagnosticsEnabled()) {
logDiagnostic(msg.toString());
}
throw new LogConfigurationException(msg.toString());
}
if (isDiagnosticsEnabled()) {
StringBuffer msg = new StringBuffer();
msg.append("Warning: bad log hierarchy. ");
msg.append("You have more than one version of '");
msg.append(Log.class.getName());
msg.append("' visible.");
logDiagnostic(msg.toString());
}
} else {
// this is just a bad adapter class
if (!allowFlawedDiscovery) {
StringBuffer msg = new StringBuffer();
msg.append("Terminating logging for this context. ");
msg.append("Log class '");
msg.append(badClass.getName());
msg.append("' does not implement the Log interface.");
if (isDiagnosticsEnabled()) {
logDiagnostic(msg.toString());
}
throw new LogConfigurationException(msg.toString());
}
if (isDiagnosticsEnabled()) {
StringBuffer msg = new StringBuffer();
msg.append("[WARNING] Log class '");
msg.append(badClass.getName());
msg.append("' does not implement the Log interface.");
logDiagnostic(msg.toString());
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -