【问题标题】:How to use WatchServiceDirectoryScanner with Spring Cloud Stream file supplier?如何将 WatchServiceDirectoryScanner 与 Spring Cloud Stream 文件供应商一起使用?
【发布时间】:2021-12-16 11:53:43
【问题描述】:

我正在尝试配置 SpCS 的文件供应商来监控目录并在创建或修改文件时发布消息。基于another SO question,我对FileInboundChannelAdapterSpec bean 有以下自定义配置:

@Bean
public BeanPostProcessor inboundFileAdaptorCustomizer() {
    return new BeanPostProcessor() {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) {

            if (bean instanceof FileInboundChannelAdapterSpec) {
                FileInboundChannelAdapterSpec spec = (FileInboundChannelAdapterSpec) bean;
                spec.get().setDirectory(properties.getDirectory());
                spec.autoCreateDirectory(false);
                spec.useWatchService(true);
                spec.watchEvents(WatchEventType.CREATE, WatchEventType.MODIFY);
                spec.preventDuplicates(false);  // We use a custom duplicates filter, see below

                spec.nioLocker();

                spec.filter(fileFilters());
            }

            return bean;
        }
    };
}

当我使用这个配置运行时,我得到以下异常:

java.lang.IllegalStateException: The WatchService hasn't been started
    at org.springframework.util.Assert.state(Assert.java:76) ~[spring-core-5.3.9.jar:5.3.9]
    at org.springframework.integration.file.FileReadingMessageSource$WatchServiceDirectoryScanner.listEligibleFiles(FileReadingMessageSource.java:466) ~[spring-integration-file-5.5.3.jar:5.5.3]
    at org.springframework.integration.file.DefaultDirectoryScanner.listFiles(DefaultDirectoryScanner.java:90) ~[spring-integration-file-5.5.3.jar:5.5.3]
    at org.springframework.integration.file.FileReadingMessageSource.scanInputDirectory(FileReadingMessageSource.java:375) ~[spring-integration-file-5.5.3.jar:5.5.3]
    at org.springframework.integration.file.FileReadingMessageSource.doReceive(FileReadingMessageSource.java:349) ~[spring-integration-file-5.5.3.jar:5.5.3]

使用断点我注意到WatchServiceDirectoryScanner 的 start() 方法永远不会被调用。相反,doReceived()listElibibleFiles() 在它开始之前被调用,这就是异常的来源。

为什么 SI 会在扫描程序启动之前告诉它列出文件?

【问题讨论】:

    标签: spring-integration spring-cloud-stream


    【解决方案1】:

    这是FileSupplierConfiguration 中的一个错误 - 缺少对start() 的调用。修复是already merged,但与此同时,解决方法是这样的:

    @Bean
    public SmartLifecycle fileReadingStart(FileReadingMessageSource fileMessageSource) {
        return new SmartLifecycle() {
    
            @Override
            public int getPhase() {
                // Make sure this runs as early as possible
                return Integer.MIN_VALUE;
            }
    
            @Override 
            public void start() {
                fileMessageSource.start();
            }
    
            @Override 
            public void stop() {
                fileMessageSource.stop();
            }
    
            @Override 
            public boolean isRunning() {
                return false;
            }
            
        };
    }
    

    【讨论】:

    • 太好了,该解决方法似乎有效。两个问题:A)是否在 GitHub 问题中跟踪了对 start() 的缺失调用(以便我可以关注它并在修复后更新我们的应用程序)? B) fileMessageSource.stop() 是否也丢失了,需要从上面的匿名生命周期中调用?
    • 是的,我会用我在回答中提到的问题来跟踪它。是的,将 stop() 委托添加到解决方法中。
    • 这个解决方案似乎有效,但我们仍然在应用程序启动时偶尔看到“WatchService 尚未启动”错误,这对于本地和我们的 RedHat 服务器上的一些开发人员都是如此。发生这种情况时,似乎简单的重新启动通常会起作用。但是即使使用SmartLifecycle 解决方法,是否也会出现微妙的计时错误?
    • SmartLifecycle.getPhase()。您可能需要覆盖它并返回 Integer.MIN_VALUE 以使这个 fileReadingStart bean 尽早启动。
    • 我已经更新了答案以反映额外的解决方法代码并参考实际的修复合并。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-11
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 2020-10-21
    相关资源
    最近更新 更多