使用Spring和Apache Commons IO的Web应用程序和目录监视程序的线程问题



我正在使用Spring Framework 4.2和Apache Tomcat 8.5开发一个web应用程序。当我修改目录中的文件时,我需要调用bean对象中的方法来重新加载信息。我使用Apache Commons IO来监视目录,但是当我取消部署应用程序时,扫描目录的线程仍然存在。

这是观察变化的代码

final File directory = new File(groupsDirectory);
FileAlterationObserver fao = new FileAlterationObserver(directory);
fao.addListener(new FileAlterationListenerImpl());
final FileAlterationMonitor monitor = new FileAlterationMonitor(pollingInterval);
monitor.addObserver(fao);
monitor.start();

这是Tomcat在我取消部署Web应用程序时向我显示的消息:

2016年5月22日19:13:14.377警告[http-nio-8084-esec-12]org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads web应用程序[Argo]似乎启动了名为[thread-12]的线程,但未能停止。这很可能会造成内存泄漏。线程的堆栈跟踪:java.lang.Thread.sleep(本机方法)org.apache.commons.io.monitor.FileAlterationMonitor.run(FileAlterationMonitors.java:188)java.lang.Thread.run(线程.java:745)

您所能做的是实现一个ServletContextListener,如本文所述:从Java web应用程序取消部署时调用方法

然后,您应该能够在ServletContextListenercontextDestroyed()方法中停止监视器。

我建议使用一个Factory对象来保存静态监视器实例,然后您可以调用Factory,而不让ServletContextListener直接处理监视器。

工厂将在类加载器的生命周期内持续存在(例如,启动Web应用程序的持续时间)

我刚刚使用注释@PreDestroy在应用程序停止之前停止监视器。

@Component
public class GroupsMonitor {
private final FileAlterationMonitor monitor;
@Autowired
public GroupsMonitor(@Value("${groups.directory}") String groupsDirectory,
@Value("${groups.intervalMonitor}") long pollingInterval) throws Exception {
final File directory = new File(groupsDirectory);
FileAlterationObserver fao = new FileAlterationObserver(directory);
fao.addListener(new FileAlterationListenerImpl());
monitor = new FileAlterationMonitor(pollingInterval);
monitor.addObserver(fao);
monitor.start();
}
@PreDestroy
public void stop() {
try {
monitor.stop();
} catch (Exception ex) {
Logger.getLogger(StopWatcher.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

旧答案,但FileAlterationMonitor仍然存在问题。

即使您调用FileAlterationMonitor#stop(),监视器也不会停止,直到pollingInterval延迟结束。

请参阅:https://github.com/apache/commons-io/pull/58

解决该问题的另一种方法是为pollingInterval设置一个小值。

最新更新