malloc4k
malloc4k

Reputation: 1937

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

I have this very basic setup of IntegrationFlow with Spring Integration 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();
    }

}

When I try to post a message to my gateway

dummyGateway.echo("test");

I'm getting and exception:

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}]

I thought, that doing .handle() in my flow is exactly subscribing to a channel. Then, why am I getting this exception? How to properly subscribe to my channel in this scenario?

Upvotes: 1

Views: 907

Answers (2)

Petr
Petr

Reputation: 45

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();
}

Upvotes: 0

Artem Bilan
Artem Bilan

Reputation: 121177

No, the ctor is too early. The beans are created at this point, but they have not started their heavy lifting. You cannot do low-level resources interaction (technically any actions) from the bean initialization phase. You need to wait until application context is fully started. Please, learn a lifecycle of Spring container: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-lifecycle-processor .

You may implement a SmartLifecycle, or listener for the ContextStartedEvent. But bean initialization phase is really too early to start emitting messages.

The QueueChannel works because it has its own internal buffer to keep messages until they are consumed. And they are consumed when the endpoint is started. In case of DirectChannel there is no buffer and consumer is called immediately, when we send a message. There is just no subscriber yet on that channel within bean initialization phase.

Upvotes: 1

Related Questions