Spring 在 IntegrationFlow 中使用 DirectChannel 的集成抛出 "Dispatcher has no subscribers"

Spring Integration using DirectChannel in IntegrationFlow throws "Dispatcher has no subscribers"

我有这个 IntegrationFlow 的非常基本的设置 Spring 集成 Java DSL:

@IntegrationComponentScan
@EnableIntegration
@Configuration
public class DummyConfig {

    @MessagingGateway
    public interface DummyGateway {
        @Gateway(requestChannel = "dummyInChannel")
        void echo(String payload);
    }

    @Bean(name = "dummyInChannel")
    public MessageChannel dummyInChannel() {
        return MessageChannels.direct().get();
    }

    @Bean
    public IntegrationFlow dummyFlow() {
        return IntegrationFlows.from(dummyInChannel())
            .handle(String.class, (payload, headers) -> {
                System.out.println(payload);
                return "";
            })
            .get();
    }

}

当我尝试post向我的网关发送消息时

dummyGateway.echo("test");

我遇到异常:

Caused by: org.springframework.messaging.MessageDeliveryException: 
Dispatcher has no subscribers for channel 'application.dummyInChannel'.; nested exception 
is org.springframework.integration.MessageDispatchingException: Dispatcher 
has no subscribers, failedMessage=GenericMessage [payload=test, 
headers={replyChannel=nullChannel, id=6e4302e4-95f0-bf5a-c1a3-e8cd587c23fb, timestamp=1643269549272}]

我想,在我的流程中做 .handle() 就是订阅一个频道。那么,为什么我会收到此异常?在这种情况下如何正确订阅我的频道?

不,ctor 太早了。此时创建了 bean,但它们还没有开始繁重的工作。您不能从 bean 初始化阶段进行 low-level 资源交互(技术上任何操作)。您需要等到应用程序上下文完全启动。请了解 Spring 容器的生命周期:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-lifecycle-processor .

您可以实施 SmartLifecycleContextStartedEvent 的侦听器。但是 bean 初始化阶段开始发出消息真的太早了。

QueueChannel 之所以有效,是因为它有自己的内部缓冲区来保存消息,直到它们被使用。并且它们在端点启动时被消耗掉。在 DirectChannel 的情况下,没有缓冲区,当我们发送消息时,消费者会立即被调用。在 bean 初始化阶段,该频道上还没有订阅者。

public static void main(String[] args) {
        SpringApplication application = new SpringApplication(DummyConfig.class);
        ConfigurableApplicationContext ctx = application.run(args);
         ctx.getBean(DummyGateway.class).echo("MyAwesomeString");
        ctx.close();
}