收到消息MessageDeliveryException时:Dispatcher没有订阅者

时间:2018-06-22 11:19:40

标签: spring-boot spring-integration spring-integration-dsl

更新: 从持有人类的Tcp()转移到端点类后,它们再次运行良好,现在我困惑为什么它现在也可以工作了,因为对我而言,为什么工作没有意义

经过一些麻烦和在所有stackoverflow中的搜索之后,当我收到来自服务器的消息时,我有一个调度程序没有订户,但是当我将响应发送回正常工作时,没有调度程序。

连接生成器:

if (array[index].id) {
  return array[index]
} else {
  return undefined
}

消息端点:

@Service
@EnableIntegration
public class TcpConnectionsHolder {


@Autowired
private IntegrationFlowContext flowContext;


/**
 * Definition of flow channels
 * 
 * @return MessageChannel
 */
@Bean
public MessageChannel fromTcp() {
    final DirectChannel channel = new DirectChannel();
    channel.addInterceptor(new ChannelInterceptorAdapter() {
        @Override
        public Message<?> preSend(final Message<?> message, final MessageChannel channel) {
            // Parse Message byte[] to StringHex
            final byte[] bMessagePayload = (byte[]) message.getPayload();
            return MessageBuilder.withPayload(Hex.encodeHexString(bMessagePayload))
                    .copyHeaders(message.getHeaders()).build();
        }
    });
    return channel;
}

private final LinkedHashMap<String, TcpNetClientConnectionFactory> clientConnect =
        new LinkedHashMap<String, TcpNetClientConnectionFactory>();

private final LinkedHashMap<String, TcpReceivingChannelAdapter> reciverAdapter =
        new LinkedHashMap<String, TcpReceivingChannelAdapter>();

private final LinkedHashMap<String, MessageChannel> sendingAdpater =
        new LinkedHashMap<String, MessageChannel>();

public MessageChannel getMessageChannel(String host, int port) {
    return sendingAdpater.get(host+port);
}


public TcpReceivingChannelAdapter getReceiverChannel(String host, int port) {
    return reciverAdapter.get(host+port);
}

private TcpNetClientConnectionFactory getclientConnectionFactory(String host, int port,int headBytes) {

    TcpNetClientConnectionFactory cf = clientConnect.get(host+port);
    if(cf==null) {
        cf = new TcpNetClientConnectionFactory(host, port);
        final ByteArrayLengthHeaderSerializer by = new ByteArrayLengthHeaderSerializer(headBytes);
        cf.setSingleUse(false);
        cf.setSoKeepAlive(true);
        cf.setSerializer(by);
        cf.setDeserializer(by);
        clientConnect.put(host+port,cf);
    }
    return cf;
}
public TcpReceivingChannelAdapter addReceiverChannel(String host, int port) {
    return addReceiverChannel(host,port,2,2000);
}
public TcpReceivingChannelAdapter addReceiverChannel(String host, int port,int headBytes,int retryInterval) {
    TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
    TcpNetClientConnectionFactory cf = getclientConnectionFactory(host,port,headBytes);
    adapter.setConnectionFactory(cf);
    adapter.setClientMode(true);
    adapter.setErrorChannelName("errorChannel");
    adapter.setRetryInterval(retryInterval);
    adapter.setOutputChannel(fromTcp());

    IntegrationFlow flow = IntegrationFlows.from(adapter).get();

    this.flowContext.registration(flow).id(host+port + ".in").addBean(cf).register();

    this.reciverAdapter.put(host+port, adapter);

    return adapter;
}

public MessageChannel addSendingChannel(String host, int port) {
    return addSendingChannel(host,port,2);
}

public MessageChannel addSendingChannel(String host, int port,int headBytes) {
       TcpSendingMessageHandler sender = new TcpSendingMessageHandler();
       sender.setConnectionFactory(getclientConnectionFactory(host,port,headBytes));

        IntegrationFlow flow = f -> f.handle(sender);

        IntegrationFlowRegistration flowRegistration =
                this.flowContext.registration(flow).id(host+port + ".out").register();

        MessageChannel inputChannel = flowRegistration.getInputChannel();
        this.sendingAdpater.put(host+port, inputChannel);
        return inputChannel;
}

public void removeReceiverChannel(String host, int port) {
    this.reciverAdapter.remove(host+port);
    this.flowContext.remove(host+port + ".in");
}

public void removeSendingChannel(String host, int port) {
    this.sendingAdpater.remove(host+port);
    this.flowContext.remove(host+port + ".out");
}

}

然后是持有人的发起人

@Configuration
@MessageEndpoint
public class BridgeMessageEndpoint {

private static final Logger LOGGER = LoggerFactory.getLogger(BridgeMessageEndpoint.class);

@Autowired
private ApplicationContext applicationContext;

@ServiceActivator(inputChannel = "fromTcp")
public void outbound(final String inMessage, final @Headers Map<String, Object> headerMap) {
    sendToApi(inMessage, headerMap);
}

private void sendToApi(final String inMessage, final Map<String, Object> headerMap) {
    LOGGER.debug("Recuperando el mensaje Hex {}", inMessage);
    final PaymentOrder paymentOrder = new PaymentOrder();
    paymentOrder.setMessage(inMessage);
    final SplitterRestClient splitterRestClient = applicationContext.getBean(SplitterRestClient.class);
    splitterRestClient.reportPayment(paymentOrder, headerMap);
}

@Bean
@ServiceActivator(inputChannel = "errorChannel")
public MessageHandler logger() {
    final LoggingHandler loggingHandler = new LoggingHandler(LoggingHandler.Level.DEBUG.name());
    loggingHandler.setLoggerName("Log");
    return loggingHandler;
}

@Bean
public IntegrationFlow toTcp() {
    return f -> f.route(new TcpRouter());
}

}

我知道问题出在fromTcp()中,但是在搜索的过程中,我始终无法发现问题或错误所在。

编辑 完整的堆栈跟踪:

@Component
public class TcpConnectionsController implements CommandLineRunner{

@Autowired
private TcpConnectionsHolder holder;

@Autowired
private ListNodeConfig listNodes;

@Value("${socket.tcp.headBytes}")
private int headBytes;

@Value("${socket.tcp.retryInterval}")
private int retryInterval;

@Override
public void run(String... args) throws Exception {

    for(Node node:listNodes.getNodes()) {
        holder.addReceiverChannel(node.getIp(), node.getPort(),headBytes,retryInterval);
        holder.addSendingChannel(node.getIp(), node.getPort(),headBytes);
    }

}

}

1 个答案:

答案 0 :(得分:1)

您可以为org.springframework.integration类别打开DEBUG日志记录级别,并跟踪消息的传播方式。

还有一个Message History模式供您跟踪标题中的消息路径。这样,您将能够查看您的消息已通过哪些渠道以及被Dispatcher has no subscribers阻塞的位置。

尽管您需要在每次MessageHistoryConfigurer注册之后重新启动IntegrationFlow

随时可以就此问题提出JIRA,以便通过消息历史记录跟踪动态流。

更新

好。像这样简单的代码:

TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
TcpNetClientConnectionFactory cf = getclientConnectionFactory(host,port,headBytes);
adapter.setConnectionFactory(cf);
adapter.setClientMode(true);
adapter.setErrorChannelName("errorChannel");
adapter.setRetryInterval(retryInterval);
adapter.setOutputChannel(fromTcp());

IntegrationFlow flow = IntegrationFlows.from(adapter).get();

事实上,在这个handler之后没有更多组件了(adn堆栈跟踪确实证实了这一点),我假设您使用的是Spring Integration Java DSL版本,但没有正确的修复程序来提取{{1} },从提供的outputChannel

要解决此问题,建议您修改如下代码:

MessageProducer.getOutputChannel()

我的意思是将通道引用从IntegrationFlow flow = IntegrationFlows.from(adapter).channel(fromTcp()).get(); 定义移至流。或者只是尝试升级到TcpReceivingChannelAdapter依赖项的最新1.2.3版本!

更新2

关于我们到目前为止的代码的另一种想法。

您从spring-integration-java-dsl注册了一个TcpReceivingChannelAdapter。这样,CommandLineRunner会自动启动并准备通过TCP接收数据,但与此同时IntegrationFlow尚未启动,无法使用上述通道中的消息。这就是您获得@ServiceActivator(inputChannel = "fromTcp")的方式。或者,您应该将Dispatcher has no subscribersthis.flowContext.registration(flow)放在一起,并让它在正常的自动启动阶段(与服务激活器一起)在最近启动。否则,您不应该使用autoStartup(false)这种逻辑方法:从那里开始一些活动真的为时过早。