Spring integration Spring反应式文件集成

Spring integration Spring反应式文件集成,spring-integration,reactive,Spring Integration,Reactive,我试图使用spring集成文件轮询一个目录,并从该目录中放置的文件创建一个反应流。这在很大程度上是有效的,但是当我放置一个文件但没有订户时,我会得到一个异常。为了演示这个问题,我编写了一个小型演示应用程序: import org.reactivestreams.Publisher; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootA

我试图使用spring集成文件轮询一个目录,并从该目录中放置的文件创建一个反应流。这在很大程度上是有效的,但是当我放置一个文件但没有订户时,我会得到一个异常。为了演示这个问题,我编写了一个小型演示应用程序:

import org.reactivestreams.Publisher;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.dsl.Pollers;
import org.springframework.integration.file.dsl.Files;
import org.springframework.messaging.Message;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.io.File;

@SpringBootApplication
@RestController
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public Publisher<Message<File>> reactiveSource() {
        return IntegrationFlows
                .from(Files.inboundAdapter(new File("."))
                                .patternFilter("*.csv"),
                        e -> e.poller(Pollers.fixedDelay(1000)))
                .channel("processFileChannel")
                .toReactivePublisher();
    }

    @GetMapping(value = "/files", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> files() {
        return Flux.from(reactiveSource())
                .map(message -> message.getPayload().getAbsolutePath());
    }
}

我认为反应流的一个属性是,当没有订户时,流不会启动,因为流是惰性的。但显然情况并非如此。有人能解释一下,如果没有订阅者,我需要做什么才能使流不启动吗?

如果您使用的是最新版本,那么您可以使用
FluxMessageChannel
频道,而不是
DirectChannel
频道,用于
processFileChannel
。这样一来,
SourcePollingChannel
适配器将变为反应式,实际上,在订阅该
FluxMessageChannel
之前,不会对源进行轮询

然后,您可以从此
FluxMessageChannel
文件()
API中创建
Flux
——无需在
.toReactivePublisher()中创建

请参阅文档中的更多内容:

关键是,
.toReactivePublisher()
正是在这一点上作为
发布者
进行了集成。这一点之前的一切都是以常规的、命令式的方式进行的,并且独立于下游逻辑

更新

大概是这样的:

@Bean
FluxMessageChannel filesChannel() {
    return new FluxMessageChannel();
}

@Bean
public IntegrationFlow reactiveSource() {
        return IntegrationFlows
                .from(Files.inboundAdapter(new File("."))
                                .patternFilter("*.csv"),
                        e -> e.poller(Pollers.fixedDelay(1000)))
                .channel(filesChannel())
                .get();
    }

@GetMapping(value = "/files", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> files() {
        return Flux.from(filesChannel())
                .map(message -> ((File) message.getPayload()).getAbsolutePath());
    }
@Bean
FluxMessageChannel文件通道(){
返回新的FluxMessageChannel();
}
@豆子
公共集成流反应源(){
返回积分流
.from(Files.inboundAdapter(新文件(“.”))
.patternFilter(“*.csv”),
e->e.poller(Pollers.fixedDelay(1000)))
.channel(文件通道())
.get();
}
@GetMapping(value=“/files”,products=MediaType.TEXT\u EVENT\u STREAM\u value)
公共流量文件(){
从(filescannel())返回通量
.map(message->((文件)message.getPayload()).getAbsolutePath());
}

Hi Artem,非常感谢您的回复。你可以发布一些示例代码吗?我应该怎么做?我已经非常深入地阅读了文档,但我无法从中获得工作。谢谢在我的回答中看到更新。谢谢你,非常感谢!嗨,阿泰姆,如果可以的话,还有一个后续问题。我注意到,在我关闭订阅者后,例如通过终止curl调用,如果我在轮询目录中放置另一个csv文件,那么我再次收到相同的错误消息,即没有订阅者接受消息。似乎当客户端关闭其连接时,这并不意味着订阅被取消。你能告诉我怎么取消订阅吗?是的。。。这就是
FluxMessageChannel
的实现方式:一旦订阅,直到应用程序结束才会取消。我们可能应该考虑在那里做些改进。。。请随意提出GH问题!
@Bean
FluxMessageChannel filesChannel() {
    return new FluxMessageChannel();
}

@Bean
public IntegrationFlow reactiveSource() {
        return IntegrationFlows
                .from(Files.inboundAdapter(new File("."))
                                .patternFilter("*.csv"),
                        e -> e.poller(Pollers.fixedDelay(1000)))
                .channel(filesChannel())
                .get();
    }

@GetMapping(value = "/files", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> files() {
        return Flux.from(filesChannel())
                .map(message -> ((File) message.getPayload()).getAbsolutePath());
    }