Hi Tomcat Community:
BACKGROUND:
I have a Servlet-based WEBAPP that is running in Tomcat7, JDK 1.6.0_27 on
Windows Server 2008 R2 64-bit - all 64-bit. We make use of class.newInstance
quite a bit as we have a fairly modular, interface-based system, and create
class instances on the fly. As part of our extensibility, I'm also using a
pretty well documented "hack" [The code is listed below] for dynamically
adding JAR(s) so they are accessible immediately without stopping our WEBAPP or
the actual Tomcat server process. This process has worked great for both
JAR(s) in the WEB-INF/lib and for ones we dynamically added - until you try and
stop the WEBAPP via the Tomcat manager app.
PROBLEM:
This solution for dynamically loading JARs worked great as long as we
start/stop the actual Tomcat server process, but I found out the JAR(s) that I
have been dynamically loading this way are not released when you stop the
WEBAPP. I am using SysInternals Process Explorer to monitor the open file
handles of the Tomcat7 process. I can see that when I stop the WEBAPP, the
dynamically loaded JAR is still referenced.
QUESTION:
I made an assumption that calling
Thread.currentThread().getContextClassLoader() would provide me the classloader
of my WEBAPP - which should be the same classloader that all the JARs in the
WEB-INF/lib are in. We control the WEBAPP, so I assumed this was a safe
assumption.
The usage of the dynamically loaded JAR(s) is no different than the default
JAR(s) in WEB-INF/lib. None of the WEB-INF/lib JARs are left open when we stop
the WEBAPP - only the JAR(s) that are loaded via the "addUrl" approach below.
I have been through a number of online articles when I first created this logic
- including a PDF by Ted Neward [while at Developmentor] that described these
approaches, but am not sure how to troubleshoot this further now.
If anyone has an answer or any suggestions, I would greatly appreciate it.
Thanks in advance,
Bob
Code to dynamically load JAR(s):
public static void loadJarOnTheFly(File jarFile) throws IOException
{
Class<?>[] parameters = new Class[]{URL.class};
// IMPORTANT: MUST use the webapp classloader - so derived extension
classes can resolve their base classes
ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();
// cast to a URL class loader so we can additional JAR(s) to the search
path
URLClassLoader webappClassLoader = (URLClassLoader)contextClassLoader;
Class<?> sysclass = URLClassLoader.class;
try
{
URL jarUrl = jarFile.toURI().toURL();
Method method = sysclass.getDeclaredMethod("addURL", parameters);
method.setAccessible(true);
method.invoke(webappClassLoader, new Object[]{ jarUrl });
}
catch (Throwable t)
{
throw new IOException("Error, could not add URL to system
classloader");
}
}
Bob DeRemer
Senior Director, Architecture and Development
http://www.thingworx.com<http://www.thingworx.com/>
Skype: bob.deremer
O: 717.505.7923
M: 717.881.3986