重新启动WatchService以解决异常问题。

4

我正在Spring Boot应用程序中使用Java的WatchService API监控一个目录,并对创建的文件执行一些操作。这个过程是异步执行的:它会在应用程序准备就绪后自动启动,并在后台监视该目录,直到应用程序停止。

这是配置类:

@Configuration
public class DirectoryWatcherConfig {

    @Value("${path}")
    private String path;

    @Bean
    public WatchService watchService() throws IOException {
        WatchService watchService = FileSystems.getDefault().newWatchService();
        Path directoryPath = Paths.get(path);
        directoryPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
        return watchService;
    }

}

这是监控服务:

@Service
@RequiredArgsConstructor
public class DirectoryWatcherService {

    private final WatchService watchService;

    @Async
    @EventListener(ApplicationReadyEvent.class)
    public void startWatching() throws InterruptedException {
        WatchKey key;
        while ((key = watchService.take()) != null) {
            for (WatchEvent<?> event : key.pollEvents()) {
                // actions on created files
            }

            key.reset();
        }
    }

}

这段代码按预期工作,但存在以下异常情况,我希望解决它:

  • 执行过程中的任何失败都会导致监控停止(显然),而我不知道如何在此类事件发生后重新启动监控
2个回答

2
你应该改变循环并添加 try/Catch,在 catch 中重新启动服务。正如你所评论的,即使中断也需要保持运行,因此你需要使用 ExecutorService。将 Executor 声明在方法外。
@Autowired
private ExecutorService executor;

在方法内部,类似于我上次回答的方式,但使用执行器

Runnable task = () -> {
        while (true) {
            try {
                WatchKey key = watchService.take();
                if (key != null) {
                    for (WatchEvent<?> event : key.pollEvents()) {
                        // Perform actions on created files here
                    }
                    key.reset();
                }
            } catch (Exception e) {
                // Wait for some time before starting the thread again
                Thread.sleep(5000);
            }
        }
    };
    //submit the task to the executor
    executor.submit(task);

问题不在于watchService已关闭,而是在执行此方法期间发生任何异常都会使线程停止(请注意,此过程是异步执行的)。我需要的是每次执行被中断时都异步重新启动此过程。 - thmasker

0
实际上,解决方案非常简单。在DirectoryWatcherService中使用try/catch(捕获所需的异常)包装所需的操作,就像这样,允许线程继续监视目录:
@Service
@RequiredArgsConstructor
public class DirectoryWatcherService {

    private final WatchService watchService;

    @Async
    @EventListener(ApplicationReadyEvent.class)
    public void startWatching() throws InterruptedException {
        WatchKey key;
        while ((key = watchService.take()) != null) {
            for (WatchEvent<?> event : key.pollEvents()) {
                try {
                    // actions on created files
                } catch (RuntimeException ex) {
                    // log exception or whatever you choose, as long as execution continues
                }
            }

            key.reset();
        }
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接