Walk the entire hierarchy of ClassLoaders, releasing memory for the
current webapp from each copy of LogFactory found. git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk@370464 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -17,8 +17,11 @@
|
||||
|
||||
package org.apache.commons.logging.impl;
|
||||
|
||||
import javax.servlet.ServletContextListener;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -49,13 +52,55 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
public class ServletContextCleaner implements ServletContextListener {
|
||||
|
||||
private Class[] RELEASE_SIGNATURE = {ClassLoader.class};
|
||||
|
||||
/**
|
||||
* Invoked when a webapp is undeployed, this tells the LogFactory
|
||||
* class to release any logging information related to the current
|
||||
* contextClassloader.
|
||||
*/
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
LogFactory.release(Thread.currentThread().getContextClassLoader());
|
||||
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
Object[] params = new Object[1];
|
||||
params[0] = tccl;
|
||||
|
||||
// Walk up the tree of classloaders, finding all the available
|
||||
// LogFactory classes and releasing any objects associated with
|
||||
// the tccl (ie the webapp).
|
||||
ClassLoader loader = tccl;
|
||||
while (loader != null) {
|
||||
// Load via the current loader. Note that if the class is not accessable
|
||||
// via this loader, but is accessable via some ancestor then that class
|
||||
// will be returned.
|
||||
try {
|
||||
Class logFactoryClass = loader.loadClass("org.apache.commons.logging.LogFactory");
|
||||
Method releaseMethod = logFactoryClass.getMethod("release", RELEASE_SIGNATURE);
|
||||
releaseMethod.invoke(null, params);
|
||||
loader = logFactoryClass.getClassLoader().getParent();
|
||||
} catch(ClassNotFoundException ex) {
|
||||
// Neither the current classloader nor any of its ancestors could find
|
||||
// the LogFactory class, so we can stop now.
|
||||
loader = null;
|
||||
} catch(NoSuchMethodException ex) {
|
||||
// This is not expected; every version of JCL has this method
|
||||
System.err.println("LogFactory instance found which does not support release method!");
|
||||
loader = null;
|
||||
} catch(IllegalAccessException ex) {
|
||||
// This is not expected; every ancestor class should be accessable
|
||||
System.err.println("LogFactory instance found which is not accessable!");
|
||||
loader = null;
|
||||
} catch(InvocationTargetException ex) {
|
||||
// This is not expected
|
||||
System.err.println("LogFactory instance release method failed!");
|
||||
loader = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Just to be sure, invoke release on the LogFactory that is visible from
|
||||
// this ServletContextCleaner class too. This should already have been caught
|
||||
// by the above loop but just in case...
|
||||
LogFactory.release(tccl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user