我在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();
}
}
}
这段代码正常工作,除了下面的异常,我想修复:
- 执行过程中的任何故障都会使监视停止(显然),并且我不知道如何重新启动监视在这些事件发生后
你应该改变这个循环,并添加一个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);
实际上解决方案很简单。在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();
}
}
}