I am trying to shutdown threads when Tomcat is being shutdown.
Specifically I am trying to shutdown log4j watchdog (for filechanges) and also I am trying to shutdown an executor which uses a class in my web app.
On shutdown I see exceptions in Catalina.out.
For Log4J I see:
INFO: Illegal access: this web application instance has been stopped
already. Could not load org.apache.log4j.helpers.NullEnumeration.
The eventual following stack trace is caused by an error thrown for
debugging purposes as well as to attempt to terminate the thread which
caused the illegal access, and has no functional impact. Throwable
occurred: java.lang.IllegalStateException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546)
at org.apache.log4j.Category.getAllAppenders(Category.java:413)
at org.apache.log4j.Category.closeNestedAppenders(Category.java:226)
at org.apache.log4j.Hierarchy.shutdown(Hierarchy.java:467)
at org.apache.log4j.LogManager.shutdown(LogManager.java:267)
at com.listeners.myListener$1.run(myListener.java:232)
Exception in thread "Thread-14" java.lang.NoClassDefFoundError:
org.apache.log4j.helpers.NullEnumeration
at org.apache.log4j.Category.getAllAppenders(Category.java:413)
at org.apache.log4j.Category.closeNestedAppenders(Category.java:226)
at org.apache.log4j.Hierarchy.shutdown(Hierarchy.java:467)
at org.apache.log4j.LogManager.shutdown(LogManager.java:267)
And for the executor part:
INFO: Illegal access: this web application instance has been stopped
already. Could not load com.my.class.SomeClass. The eventual
following stack trace is caused by an error thrown for debugging
purposes as well as to attempt to terminate the thread which caused
the illegal access, and has no functional impact. Throwable occurred:
java.lang.IllegalStateException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546)
at Exception in thread "Thread-13" java.lang.NoClassDefFoundError:
com.my.class.SomeClass
What I am doing is in ServletContextListener
on contextDestroyed
I have added shutdown hooks as follows:
public void contextDestroyed(ServletContextEvent arg0) {
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run(){
LogManager.shutdown();
}
});
}
public void contextDestroyed(ServletContextEvent arg0) {
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run(){
SomeClass.updater.shutdown();
}
});
}
What am I doing wrong here? Why do I get exceptions?
UPDATE:SomeClass.updater
is a public static ScheduledExecutorService
.LogManager
is org.apache.log4j.LogManager
UPDATE2:
After following the answer from BGR I do directly
public void contextDestroyed(ServletContextEvent arg0) {
SomeClass.updater.shutdown();
}
and
public void contextDestroyed(ServletContextEvent arg0) {
LogManager.shutdown();
}
I don't get exception from Log4j but I get the following exception for SomeClass.updater
which is a public static ScheduledExecutorService
:
INFO: Illegal access: this web application instance has been stopped
already. Could not load java.util.concurrent.ExecutorService. The
eventual following stack trace is caused by an error thrown for
debugging purposes as well as to attempt to terminate the thread which
caused the illegal access, and has no functional impact. Throwable
occurred: java.lang.IllegalStateException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546)
Why? Are the classes already been garbage collected?
I would register shutdown hooks in the init() method of the servlet rather than contextDetroyed(), but anyway, why do you need Shutdown hooks in the first place?
Can't you just call SomeClass.updater.shutdown();
directly in the contextDestroyed() method ?
EDIT
contextDestroyed()
of the listener is to late for the executor service. As stated in the javadoc All servlets and filters will have been destroyed before any ServletContextListeners are notified of context destruction.
whereas overriding the servlet destroy()
should be OK as according to the javadoc This method gives the servlet an opportunity to clean up any resources that are being held (for example, memory, file handles, threads...
@Override
public void destroy( ) {
myThreadExecutor.shutdown();
super.destroy( );
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With