1
0

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:
Simon Kitching
2006-01-19 12:16:56 +00:00
parent c0de38481c
commit de40e38a37

View File

@@ -17,8 +17,11 @@
package org.apache.commons.logging.impl; 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.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -49,13 +52,55 @@ import org.apache.commons.logging.LogFactory;
public class ServletContextCleaner implements ServletContextListener { public class ServletContextCleaner implements ServletContextListener {
private Class[] RELEASE_SIGNATURE = {ClassLoader.class};
/** /**
* Invoked when a webapp is undeployed, this tells the LogFactory * Invoked when a webapp is undeployed, this tells the LogFactory
* class to release any logging information related to the current * class to release any logging information related to the current
* contextClassloader. * contextClassloader.
*/ */
public void contextDestroyed(ServletContextEvent sce) { 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);
} }
/** /**