Undeploying Google Guice jar file locked
When trying to undeploy an webapp that uses Google Guice from an webapp server like Tomcat, you may notice that it doesn't undeploy properly. The problem seems to be related to
My solution is to modify this class (by just adding that individual source file to the project as I don't want to rebuild the whole project) adding a stop method that can be call from a
My modified Finializer:
Then from listener (in this case I've modified GuiceContextListener from GuiceSF, which seems to have now disappeared but you could write your own from scratch), you need to stop the thread:
Download the modified source: undeploy_guice-src.zip
Other people have noticed the problem, which trace it to problems with FinalizableReferenceQueue. There is an attached patch which resolves the issue of having to manually stop the thread.
com.google.inject.internal.Finalizer
, which is a Thread created to clean up after Guice is finished. However the thread doesn't stop properly.My solution is to modify this class (by just adding that individual source file to the project as I don't want to rebuild the whole project) adding a stop method that can be call from a
ServletContextListener.contextDestroyed()
.My modified Finializer:
private boolean stop = false; /** * Loops continuously, pulling references off the queue and cleaning them up. */ // @SuppressWarnings("InfiniteLoopStatement") @Override public void run() { try { while (!stop) { try { cleanUp(queue.remove()); } catch (InterruptedException e) { /* ignore */ } } } catch (ShutDown shutDown) { /* ignore */ } } public void stopThread() { this.stop = true; this.interrupt(); }
Then from listener (in this case I've modified GuiceContextListener from GuiceSF, which seems to have now disappeared but you could write your own from scratch), you need to stop the thread:
public class GuiceContextListener implements ServletContextListener { public void contextDestroyed(ServletContextEvent contextEvent) { ServletContext context = contextEvent.getServletContext(); //start custom code //first use the GuiceyFruit Injectors class to notify all objects their being destroyed try { Injector injector = getInjector(context); Injectors.close(injector); } catch (CloseFailedException e) { LOG.log(Level.SEVERE, "Guicesf finhised", e); } ThreadGroup root = Thread.currentThread().getThreadGroup().getParent(); while (root.getParent() != null) { root = root.getParent(); } //now find the thread Thread thread = getThread(root, Finalizer.class.getName()); if (thread == null) { LOG.log(Level.INFO, "finalizer not found"); } else { LOG.log(Level.INFO, "Stopping finalizer"); callMethod(thread, "stopThread"); } //end custom code context.removeAttribute(Injector.class.getName()); LOG.log(Level.INFO, "Guicesf finished"); } private static Thread getThread(ThreadGroup group, String name) { int num = group.activeCount(); Thread[] threads = new Thread[num * 2]; num = group.enumerate(threads, true); for (int i = 0; i < num; i++) { Thread thread = threads[i]; if (thread == null) { } else if (thread.getName().equals(name)) { return thread; } } return null; } private static void callMethod(Object obj, String methodName) { try { Class clazz = obj.getClass(); Method method = clazz.getMethod(methodName, (Class[]) null); method.invoke(obj, (Object[]) null); } catch (Exception e) { LOG.log(Level.SEVERE, "callMethod caught exception", e); } }
Download the modified source: undeploy_guice-src.zip
Other people have noticed the problem, which trace it to problems with FinalizableReferenceQueue. There is an attached patch which resolves the issue of having to manually stop the thread.
Comments
Post a Comment