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;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user