Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring integration 'Dispatcher has no subscribers' when channels are used in init-method

Getting 'Dispatcher has no subscribers' error while trying to post message to a channel in spring bean's init-method. Please take a look at below example:

applicationContext.xml

<?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:p="http://www.springframework.org/schema/p"
    xmlns:rmi="http://www.springframework.org/schema/integration/rmi"
    xmlns:int="http://www.springframework.org/schema/integration"
    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/rmi
        http://www.springframework.org/schema/integration/rmi/spring-integration-rmi.xsd">

    <bean id="currencyService" class="com.demo.CurrencyService" init-method="init"/>

    <int:channel id="currencyChannel" />
    <int:channel id="currencyReplyChannel">
        <int:queue/>
    </int:channel>
    <rmi:outbound-gateway id="currencyServiceGateway"
        request-channel="currencyChannel" remote-channel="currencyServiceChannel"
        reply-channel="currencyReplyChannel" host="localhost" port="2197" />
</beans>

Spring managed bean:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.message.GenericMessage;

public class CurrencyService {

    @Autowired
    private MessageChannel currencyChannel;

    @Autowired
    private PollableChannel currencyReplyChannel;

    private CurrencyListBO currencyListBO;

    public CurrencyListBO getCurrencyList() {
        return currencyListBO;
    }

    public void init() {
        CurrencyIN request = new CurrencyIN();
        request.setChannelCode("RMW");
        request.setTransactionType(CurrencyIN.TransactionType.currencyLoaderService
                .toString());
        GenericMessage<IRequestBO> message = new GenericMessage<IRequestBO>(
                request);
        MessagingTemplate template = new MessagingTemplate();
        template.send(currencyChannel, message);
        Message<CurrencyListBO> reply = template.receive(currencyReplyChannel);
        currencyListBO = reply.getPayload();
    }
}

If instead of init-method, currencyListBO was initialized after during first call, everything works fine.

public CurrencyListBO getCurrencyList() {
    if(currencyListBO == null) {
        init();
    }
    return currencyListBO;
}

Please let me know what is the issue with first approach.

like image 311
Sudhir Avatar asked Jun 21 '12 10:06

Sudhir


1 Answers

The init/@PostConstruct method is called after your bean has been instantiated but before the rest of the context has been wired up (in this case before the RMI adapter has been subscribed to the channel).

You need to wait until the context is fully refreshed.

One way to do that is implement

ApplicationListener<ContextRefreshedEvent>

and put your code in

public void onApplicationEvent(ContextRefreshedEvent event)

That method will be called after the context is fully wired.

like image 116
Gary Russell Avatar answered Jan 01 '23 13:01

Gary Russell