mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-14 17:26:22 +01:00
fix possible class loader leak
This commit is contained in:
@@ -71,14 +71,25 @@ public class BootstrapFilter implements Filter
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void destroy()
|
public void destroy()
|
||||||
|
{
|
||||||
|
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (classLoader != null)
|
if (classLoader != null)
|
||||||
{
|
{
|
||||||
Thread.currentThread().setContextClassLoader(classLoader);
|
Thread.currentThread().setContextClassLoader(classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug("destroy guice filter");
|
||||||
|
|
||||||
guiceFilter.destroy();
|
guiceFilter.destroy();
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Thread.currentThread().setContextClassLoader(oldClassLoader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
@@ -95,6 +106,10 @@ public class BootstrapFilter implements Filter
|
|||||||
public void doFilter(ServletRequest request, ServletResponse response,
|
public void doFilter(ServletRequest request, ServletResponse response,
|
||||||
FilterChain chain)
|
FilterChain chain)
|
||||||
throws IOException, ServletException
|
throws IOException, ServletException
|
||||||
|
{
|
||||||
|
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (classLoader != null)
|
if (classLoader != null)
|
||||||
{
|
{
|
||||||
@@ -103,6 +118,11 @@ public class BootstrapFilter implements Filter
|
|||||||
|
|
||||||
guiceFilter.doFilter(request, response, chain);
|
guiceFilter.doFilter(request, response, chain);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Thread.currentThread().setContextClassLoader(oldClassLoader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
|
|||||||
@@ -35,14 +35,19 @@ package sonia.scm.boot;
|
|||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import sonia.scm.SCMContext;
|
import sonia.scm.SCMContext;
|
||||||
import sonia.scm.SCMContextProvider;
|
import sonia.scm.SCMContextProvider;
|
||||||
|
import sonia.scm.util.ClassLoaders;
|
||||||
|
import sonia.scm.util.IOUtil;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
@@ -51,6 +56,7 @@ import java.net.URL;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletContextEvent;
|
import javax.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.servlet.ServletContextListener;
|
||||||
|
|
||||||
@@ -89,8 +95,28 @@ public class BootstrapListener implements ServletContextListener
|
|||||||
{
|
{
|
||||||
if (scmContextListener != null)
|
if (scmContextListener != null)
|
||||||
{
|
{
|
||||||
|
logger.info("destroy scm context listener");
|
||||||
scmContextListener.contextDestroyed(sce);
|
scmContextListener.contextDestroyed(sce);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServletContext servletContext = sce.getServletContext();
|
||||||
|
ClassLoader classLoader = BootstrapUtil.getClassLoader(servletContext);
|
||||||
|
|
||||||
|
if (classLoader != null)
|
||||||
|
{
|
||||||
|
if (classLoader instanceof Closeable)
|
||||||
|
{
|
||||||
|
logger.info("close plugin class loader");
|
||||||
|
IOUtil.close((Closeable) classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("remove plugin class loader from servlet context");
|
||||||
|
BootstrapUtil.removeClassLoader(servletContext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.debug("plugin class loader is not available");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,6 +136,44 @@ public class BootstrapListener implements ServletContextListener
|
|||||||
context.getStage());
|
context.getStage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClassLoader classLoader = createClassLoader(context);
|
||||||
|
|
||||||
|
if (classLoader != null)
|
||||||
|
{
|
||||||
|
if (logger.isInfoEnabled())
|
||||||
|
{
|
||||||
|
logger.info("try to use ScmBootstrapClassLoader");
|
||||||
|
}
|
||||||
|
|
||||||
|
scmContextListener = BootstrapUtil.loadClass(classLoader,
|
||||||
|
ServletContextListener.class, LISTENER);
|
||||||
|
BootstrapUtil.setClassLoader(sce.getServletContext(), classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scmContextListener == null)
|
||||||
|
{
|
||||||
|
if (logger.isWarnEnabled())
|
||||||
|
{
|
||||||
|
logger.warn("fallback to default classloader");
|
||||||
|
}
|
||||||
|
|
||||||
|
scmContextListener =
|
||||||
|
BootstrapUtil.loadClass(ServletContextListener.class, LISTENER);
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeContext(classLoader, scmContextListener, sce);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private ClassLoader createClassLoader(SCMContextProvider context)
|
||||||
|
{
|
||||||
ClassLoader classLoader = null;
|
ClassLoader classLoader = null;
|
||||||
File pluginDirectory = new File(context.getBaseDirectory(),
|
File pluginDirectory = new File(context.getBaseDirectory(),
|
||||||
PLUGIN_DIRECTORY);
|
PLUGIN_DIRECTORY);
|
||||||
@@ -144,31 +208,7 @@ public class BootstrapListener implements ServletContextListener
|
|||||||
logger.debug("no plugin directory found");
|
logger.debug("no plugin directory found");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classLoader != null)
|
return classLoader;
|
||||||
{
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("try to use ScmBootstrapClassLoader");
|
|
||||||
}
|
|
||||||
|
|
||||||
scmContextListener = BootstrapUtil.loadClass(classLoader,
|
|
||||||
ServletContextListener.class, LISTENER);
|
|
||||||
Thread.currentThread().setContextClassLoader(classLoader);
|
|
||||||
BootstrapUtil.setClassLoader(sce.getServletContext(), classLoader);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scmContextListener == null)
|
|
||||||
{
|
|
||||||
if (logger.isWarnEnabled())
|
|
||||||
{
|
|
||||||
logger.warn("fallback to default classloader");
|
|
||||||
}
|
|
||||||
|
|
||||||
scmContextListener =
|
|
||||||
BootstrapUtil.loadClass(ServletContextListener.class, LISTENER);
|
|
||||||
}
|
|
||||||
|
|
||||||
scmContextListener.contextInitialized(sce);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,7 +228,7 @@ public class BootstrapListener implements ServletContextListener
|
|||||||
logger.debug("create classloader from plugin classpath");
|
logger.debug("create classloader from plugin classpath");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<URL> classpathURLs = new LinkedList<URL>();
|
List<URL> classpathURLs = Lists.newLinkedList();
|
||||||
|
|
||||||
for (String path : classpath)
|
for (String path : classpath)
|
||||||
{
|
{
|
||||||
@@ -224,32 +264,36 @@ public class BootstrapListener implements ServletContextListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
return BootstrapUtil.createClassLoader(classpathURLs,
|
return BootstrapUtil.createClassLoader(classpathURLs,
|
||||||
getParentClassLoader());
|
ClassLoaders.getContextClassLoader(BootstrapListener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @return
|
* @param classLoader
|
||||||
|
* @param listener
|
||||||
|
* @param sce
|
||||||
*/
|
*/
|
||||||
private ClassLoader getParentClassLoader()
|
private void initializeContext(ClassLoader classLoader,
|
||||||
|
ServletContextListener listener, ServletContextEvent sce)
|
||||||
{
|
{
|
||||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
if (classLoader == null)
|
try
|
||||||
{
|
{
|
||||||
if (logger.isWarnEnabled())
|
if (classLoader != null)
|
||||||
{
|
{
|
||||||
logger.warn("could not use context classloader, try to use default");
|
Thread.currentThread().setContextClassLoader(classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
classLoader = BootstrapListener.class.getClassLoader();
|
logger.info("initialize scm context listener");
|
||||||
|
listener.contextInitialized(sce);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Thread.currentThread().setContextClassLoader(oldClassLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
return classLoader;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|||||||
@@ -235,4 +235,17 @@ public final class BootstrapUtil
|
|||||||
{
|
{
|
||||||
context.setAttribute(CLASSLOADER, classLoader);
|
context.setAttribute(CLASSLOADER, classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
*/
|
||||||
|
public static void removeClassLoader(ServletContext context)
|
||||||
|
{
|
||||||
|
context.removeAttribute(CLASSLOADER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user