1

I'm developing a web application using Spring Framework 4.2 with Apache Tomcat 8.5. When I modify a file in a directory, I need to call a method in a bean object in order to reload the information. I work with Apache Commons IO to watch the directory, however when I undeploy the application, the thread which scan the directory still lives.

This is the code to watch the changes

    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();

And this the message that Tomcat shows me when I undeploy the webapplication:

22-May-2016 19:13:14.377 WARNING [http-nio-8084-exec-12] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [Argo] appears to have started a thread named [Thread-12] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread: java.lang.Thread.sleep(Native Method) org.apache.commons.io.monitor.FileAlterationMonitor.run(FileAlterationMonitor.java:188) java.lang.Thread.run(Thread.java:745)

renyalvarado
  • 169
  • 5

3 Answers3

0

What you can do is Implement a ServletContextListener as described in this post: Call method on undeploy from a Java web-application

Then you should be able to stop the monitor in the contextDestroyed() method of your ServletContextListener.

I would recommend having a Factory object that holds onto the static monitor instance, then you can make calls to the Factory and not have the ServletContextListener deal with the monitor directly.

The Factory would persist for the life of the classloader (e.g. the duration of the webapp being started)

Community
  • 1
  • 1
Michael Markidis
  • 4,163
  • 1
  • 14
  • 21
0

I just used the annotation @PreDestroy to stop the monitor before the applications stops.

@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);
        }
    }
}
renyalvarado
  • 169
  • 5
0

Old answer but an issue remains with FileAlterationMonitor.

Even if you call FileAlterationMonitor#stop(), the monitor won't stop until the pollingInterval delay has elapsed.

See : https://github.com/apache/commons-io/pull/58

An alternative to solve the issue is to set a small value for pollingInterval.

Anthony Raymond
  • 7,434
  • 6
  • 42
  • 59