WatchEventType.DELETE 好像不行

WatchEventType.DELETE doesn't seem to work

我想做的是跟踪删除的文件并围绕此应用某些逻辑(获取 ID 并更新实体)。我发现我们可以在通道适配器中传递一个监视事件列表,包括

FileReadingMessageSource.WatchEventType.DELETE

但是当我从文件夹中删除文件时,我没有看到任何事件被触发,并且转换器从未被应用

@Bean
public IntegrationFlow integrationFlow(FileToMovieTransformer fileToMovieTransformer) {

    return this.integrationFlowBuilder()
            .transform(fileToMovieTransformer)
            .channel(movieHandlerChannel())
            .get();

}

    private IntegrationFlowBuilder integrationFlowBuilder() {

    return IntegrationFlows.from(

            Files.inboundAdapter(new File(localFilmFolder))
                    .autoCreateDirectory(true)
                    .useWatchService(true)
                    .watchEvents(FileReadingMessageSource.WatchEventType.CREATE, FileReadingMessageSource.WatchEventType.DELETE)
                    .patternFilter("*.xml"),

            e -> e.poller(Pollers.fixedDelay(10, TimeUnit.SECONDS)
            ));
}

我会说你对待 DELETE 的方式不对:

/**
 * Directory entry deleted.
 *
 * <p> When a directory is registered for this event then the {@link WatchKey}
 * is queued when it is observed that an entry is deleted or renamed out of
 * the directory. The event {@link WatchEvent#count count} for this event
 * is always {@code 1}.
 */
public static final WatchEvent.Kind<Path> ENTRY_DELETE =
    new StdWatchEventKind<Path>("ENTRY_DELETE", Path.class);

因此,已经没有任何消息可以作为消息发送到下游。我们这里肯定谈了一个FileReadingMessageSource。但是有了 DELETE 就没有什么可读的了。我错过了什么吗?

这是目前文档中的内容:

The ENTRY_DELETE events have effect for the ResettableFileListFilter implementations and, therefore, their files are provided for the remove() operation. This means that (when this event is enabled), filters such as the AcceptOnceFileListFilter will have the file removed, meaning that, if a file with the same name appears, it will pass the filter and be sent as a message.

因此,为了在发生 DELETE 事件时实现您想做的任何事情,您需要实现 ResettableFileListFilter 并且与 SimplePatternFileListFilter 一起,您应该将它们组合到 CompositeFileListFilter.

删除文件时,会发出 DELETE 事件,我们最终得到如下逻辑:

if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
    if (getFilter() instanceof ResettableFileListFilter) {
        ((ResettableFileListFilter<File>) getFilter()).remove(file);
    }

其中提到的 CompositeFileListFilter 肯定实现了这个 ResettableFileListFilter 并将委托给您自己的实现。

感谢@Artem,这是完整的代码示例,似乎对我来说效果很好

    private IntegrationFlowBuilder integrationFlowBuilder() {

    final List<FileListFilter<File>> defaultFilters = new ArrayList<>(2);

    defaultFilters.add(new IgnoreHiddenFileListFilter());
    defaultFilters.add(new AcceptOnceFileListFilter<>());
    defaultFilters.add(new SimplePatternFileListFilter("*.xml"));
    defaultFilters.add(myCustomRemovalFilter);

    CompositeFileListFilter fileListFilter = new CompositeFileListFilter<>(defaultFilters);

    return IntegrationFlows.from(

            Files.inboundAdapter(new File(localFilmFolder))
                    .autoCreateDirectory(true)
                    .filter(fileListFilter)
                    .useWatchService(true)
                    .watchEvents(FileReadingMessageSource.WatchEventType.CREATE, FileReadingMessageSource.WatchEventType.DELETE),

            e -> e.poller(Pollers.fixedDelay(10, TimeUnit.SECONDS)
            ));
} 

过滤器看起来像

@Component
public class MyCustomRemovalFilter implements ResettableFileListFilter<File> {

private static final Logger LOGGER = LogManager.getLogger(MyCustomRemovalFilter.class);

@Override
public boolean remove(File xmlFile) {

    if (xmlFile == null) {
        return true;
    }
    // TODO you own on removal logic 
}

@Override
public List<File> filterFiles(File[] files) {

    if (files == null || files.length == 0) {
        return Collections.emptyList();
    }
    return Arrays.asList(files);
}
}