Java 春季一体化;复制服务在复制完成之前拾取的文件

Java 春季一体化;复制服务在复制完成之前拾取的文件,java,spring,spring-boot,spring-integration,Java,Spring,Spring Boot,Spring Integration,应用背景 应用程序中有2个服务。我们叫他们 1) 服务A 2) 服务B 服务A基本上将符合特定条件的文件从源目录复制到目标目录。在这里使用spring集成。 服务A的目标目录是服务B的源目录 服务B不断轮询目录中的文件并对其进行处理,然后将其移动到另一个名为“已处理”的子目录中 问题: 最初的问题是,当服务A将文件复制到目标目录时,服务B会拾取复制了一半的文件并对其进行处理 尝试过的解决方案 请参阅下面的服务B集成上下文.xml。我在入站通道上附加了一个复合过滤器。我在这个复合过滤器中添加了一个

应用背景

应用程序中有2个服务。我们叫他们
1) 服务A
2) 服务B

服务A基本上将符合特定条件的文件从源目录复制到目标目录。在这里使用spring集成。 服务A的目标目录是服务B的源目录

服务B不断轮询目录中的文件并对其进行处理,然后将其移动到另一个名为“已处理”的子目录中

问题:
最初的问题是,当服务A将文件复制到目标目录时,服务B会拾取复制了一半的文件并对其进行处理

尝试过的解决方案
请参阅下面的服务B
集成上下文.xml
。我在入站通道上附加了一个复合过滤器。我在这个复合过滤器中添加了一个名为
LastCreatedFileListFilter
的自定义过滤器。此筛选器基于
spring integration file
提供的
LastModifiedFileListFilter
行,这基本上会丢弃年龄(按创建时间)小于30秒的任何文件

此过滤器工作正常,直到文件30秒后才会拾取文件。但现在的问题是,我正在使用
防止重复=“true”
。因此,发生的情况是服务B第一次轮询文件夹时,文件的保存时间小于30秒,它会过滤掉文件,但30秒后,过滤器不会过滤掉文件,这是正确的行为,但现在服务已将其标记为重复并拒绝

所以,我这里的问题是,我确实希望保留一个防止重复检查,并且在文件完全复制之前不处理它

我不太熟悉spring集成,我希望实现的两种方法是:
1) 在应用程序处理之前,是否在上述场景中将文件标记为重复文件?这可能吗?是这样吗?建议这样做吗?
2) 在服务A中,我是否可以先用临时名称创建文件,然后在复制完成后重命名它们?这里的问题是,服务B将不会拾取文件,直到它们以配置的名称开始。这样,我就不必信任age属性,因为源和目标位于不同的网络上,并且复制时间可能很长(#MurphysLaw),因此age属性不能100%起决定性作用。 但这里的问题是,我在概念化如何通过spring集成最好地实现这个解决方案方面遇到了困难。有什么指导或建议吗

请参阅服务A的集成上下文以了解当前实现。如果有任何事情需要澄清,请告诉我

服务A

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:int-file="http://www.springframework.org/schema/integration/file"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/integration/file
    http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="classpath:application.properties"/>


    <bean name="redisMetaDataStore" class="org.springframework.integration.redis.metadata.RedisMetadataStore">
        <constructor-arg ref="redisConnectionFactory" />
    </bean>

    <bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="port" value="6379" />
    </bean>

    <int-file:inbound-channel-adapter id = "filesIn"
                                      channel="fileChannel"
                                      directory="file:${input.directory}"
                                      filter="incomingCompositeFilter">

        <int:poller id="fileInboudPoller" fixed-rate="${in.interval}" time-unit="SECONDS"  />
    </int-file:inbound-channel-adapter>

    <bean id="incomingCompositeFilter" class="org.springframework.integration.file.filters.CompositeFileListFilter">
        <constructor-arg>
            <list>
                <bean id="acceptOnceFilter" class="org.springframework.integration.file.filters.FileSystemPersistentAcceptOnceFileListFilter">
                    <constructor-arg ref="redisMetaDataStore"/>
                    <constructor-arg value="*"/>
                </bean>
                <bean id="notOlderThanDateFilter" class="com.fexco.bgeadmin.file.filter.NotOlderThanDateFilter">
                    <constructor-arg value="${file.lastModified.ignoreBeforeDate}"/>
                </bean>
                <bean id="documentConfigFilter" class="com.fexco.bgeadmin.file.filter.DocumentConfigFilter">
                </bean>
            </list>
        </constructor-arg></bean>

    <int:channel id="fileChannel"/>

    <int-file:outbound-channel-adapter id="save-as-file"
                                       auto-create-directory="true"
                                       channel="fileChannel"
                                       directory="file:${output.directory}"/>
</beans>

服务B

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:int="http://www.springframework.org/schema/integration"
       xmlns:int-file="http://www.springframework.org/schema/integration/file"
       xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/integration
         http://www.springframework.org/schema/integration/spring-integration.xsd
         http://www.springframework.org/schema/integration/file
         http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
         http://www.springframework.org/schema/batch-integration
         http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">

    <int:channel id="inboundFileChannel"/>
    <int:channel id="outboundJobRequestChannel"/>
    <int:channel id="jobLaunchReplyChannel"/>

    <int-file:inbound-channel-adapter id="filePoller"
                                      channel="inboundFileChannel"
                                      directory="${app.file.source}"
                                      auto-create-directory="true"
                                      prevent-duplicates="true"
                                      filter="incomingCompositeFilter">
        <int:poller fixed-rate="5000"/>
    </int-file:inbound-channel-adapter>

    <bean id="incomingCompositeFilter" class="org.springframework.integration.file.filters.CompositeFileListFilter">
        <constructor-arg>
            <list>
                <bean id="fileNameFilter" class="org.springframework.integration.file.filters.RegexPatternFileListFilter">
                    <constructor-arg value=".*\.(xls|xlsx|csv)$" />
                </bean>
                <bean id="ageFilter" class="com.fexco.bgeadmin.integration.filter.LastCreatedFileListFilter">
                    <property name="age" value="30"/>
                </bean>
            </list>
        </constructor-arg></bean>

    <int:transformer input-channel="inboundFileChannel"
                     output-channel="outboundJobRequestChannel" method="toRequest">
        <bean class="com.fexco.bgeadmin.integration.FileMessageToJobRequest"/>
    </int:transformer>

    <batch-int:job-launching-gateway request-channel="outboundJobRequestChannel"
                                     reply-channel="jobLaunchReplyChannel"/>

    <int:logging-channel-adapter channel="jobLaunchReplyChannel"/>

</beans>

解决此类问题的最佳方法是#2-对于A来说,不要“就地”将文件写入B。使用上次修改的时间是不可靠的


这是
的标准过程,它在下面使用
文件写入消息处理程序。它有一个属性
temporaryFileSuffix
,默认为
。writing
。文件复制后会被重命名。

解决此类问题的最佳方法是#2-对于A,不要将文件“就地”写入B。使用上次修改的时间是不可靠的


这是
的标准过程,它在下面使用
文件写入消息处理程序。它有一个属性
temporaryFileSuffix
,默认为
。writing
。文件在复制后被重命名。

确切地说,我对“上次修改时间”解决方案不太满意。谢谢你的回答,工作很有魅力。没错,我对“上次修改时间”的解决方案不太满意。谢谢你的回答,工作起来很有魅力。我也有同样的问题,即使没有防止重复=“真”。我认为LastModifiedFileListFilter类在处理文件系统事件的场景中是无用的。使用此筛选器时,将跳过一个文件,但文件系统在x秒后不会触发另一个事件。因此,您的程序不会因新的/更新的文件而被注意到。我将使用Gary Russell建议的解决方案。谢谢我也有同样的问题,即使没有“防止重复”=“true”。我认为LastModifiedFileListFilter类在处理文件系统事件的场景中是无用的。使用此筛选器时,将跳过一个文件,但文件系统在x秒后不会触发另一个事件。因此,您的程序不会因新的/更新的文件而被注意到。我将使用Gary Russell建议的解决方案。谢谢