Spring集成 - 路由到多个通道时丢失消息

时间:2016-01-06 08:42:24

标签: spring spring-integration

我是Spring Integration的新手,并编写了一个示例,将消息从单个通道发送到多个通道,在此透视图中,为每个通道使用Redis消息存储,目的是不丢失任何消息。要求是向频道发送消息 - replyChannel,mailChannel和dbChannel。目前,代码只打印sysout语句,没有主要功能。

为了检查消息是否正确路由,我编写了一个java测试类来发送15条消息。

检查输出我发现有些消息丢失了。此外,没有任何例外情况正在显示。

感谢您的支持。

以下是示例代码:

config.java - 具有所有集成配置

@Bean
public MessageChannel replyQueueChannel () {    return new QueueChannel (new MessageGroupQueue(redisMesageStore(),replyQueue, 1000));    }  

@Bean
public MessageChannel mailQueueChannel () {    return new QueueChannel (new MessageGroupQueue(redisMesageStore(),mailQueue, 1000));    }            

@Bean
public MessageChannel auditlogQueueChannel () {     return new QueueChannel (new MessageGroupQueue(redisMesageStore(),auditLogQueue, 1000));    }

将消息发送到通道的Java代码

@Override
@ServiceActivator (inputChannel="dbQueueChannel", poller =@Poller(fixedDelay="10", taskExecutor="dbServiceExecutor"))
public void executeDBConditions (Message<DeferredModel> deferredMsg) {
replyQueueChannel.send(deferredMsg);        
auditlogQueueChannel.send(deferredMsg);
mailQueueChannel.send (deferredMsg);        
}

1 个答案:

答案 0 :(得分:0)

第一步始终是为org.springframework启用DEBUG日志记录;您将看到许多显示消息流的调试消息。

您还可以使用redis-climonitor命令监控redis以跟踪redis活动。

如果您无法弄清楚使用这些技术发生了什么,请将日志发布到github gist或pastebin等地方。

修改

这是您的方案的工作版本;我对“丢失的消息”没有任何问题。由于您没有显示完整的申请表,我不知道您为什么遇到麻烦。

我还使用在Java中配置的RecipientListRouter添加了一个版本 - 但你真的应该将其作为一个新问题而不是捎带在这个问题上......

package com.example;

import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.integration.annotation.MessageEndpoint;
import org.springframework.integration.annotation.Router;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.redis.store.RedisChannelMessageStore;
import org.springframework.integration.store.MessageGroupQueue;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.PollableChannel;
import org.springframework.util.Assert;

@SpringBootApplication
public class So34628789Application {

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(So34628789Application.class, args);
        MessageChannel foo = context.getBean("foo", MessageChannel.class);
        for (int i = 0; i < 15; i++) {
            foo.send(MessageBuilder.withPayload("foo" + i).build());
        }
        getOutput(context);

        // now with an RLR...

        foo = context.getBean("routedMessageChannel", MessageChannel.class);
        for (int i = 0; i < 15; i++) {
            foo.send(MessageBuilder.withPayload("foo" + (i + 15)).build());
        }
        getOutput(context);

        context.close();
    }

    private static void getOutput(ConfigurableApplicationContext context) {
        int n = 0;
        PollableChannel out = context.getBean("replyQueueChannel", PollableChannel.class);
        for (int i = 0; i < 15; i++) {
            Message<?> received = out.receive(10000);
            if (received != null) {
                System.out.println(received);
                n++;
            }
        }
        out = context.getBean("mailQueueChannel", PollableChannel.class);
        for (int i = 0; i < 15; i++) {
            Message<?> received = out.receive(10000);
            if (received != null) {
                System.out.println(received);
                n++;
            }
        }
        out = context.getBean("auditlogQueueChannel", PollableChannel.class);
        for (int i = 0; i < 15; i++) {
            Message<?> received = out.receive(10000);
            if (received != null) {
                System.out.println(received);
                n++;
            }
        }
        Assert.state(n == 45, "expected 45 messages");
    }

    @Autowired
    private JedisConnectionFactory connectionFactory;

    @Bean
    public MessageChannel replyQueueChannel() {
        return new QueueChannel(new MessageGroupQueue(redisMessageStore(), "replyQueue", 1000));
    }

    @Bean
    public MessageChannel mailQueueChannel() {
        return new QueueChannel(new MessageGroupQueue(redisMessageStore(), "mailQueue", 1000));
    }

    @Bean
    public MessageChannel auditlogQueueChannel() {
        return new QueueChannel(new MessageGroupQueue(redisMessageStore(), "auditLogQueue", 1000));
    }

    @Bean
    public RedisChannelMessageStore redisMessageStore() {
        return new RedisChannelMessageStore(connectionFactory);
    }

    @Bean
    public MessageChannel foo() {
        return new DirectChannel();
    }

    @Bean
    public Foo fooService() {
        return new Foo();
    }

    @Bean
    public MessageChannel routedMessageChannel() {
        return new DirectChannel();
    }

// Router Technique 1
//  @Bean
//  @ServiceActivator(inputChannel="routedMessageChannel")
//  public RecipientListRouter router() {
//      RecipientListRouter router = new RecipientListRouter();
//      List<Recipient> recipients = new ArrayList<>();
//      recipients.add(new Recipient(replyQueueChannel()));
//      recipients.add(new Recipient(mailQueueChannel()));
//      recipients.add(new Recipient(auditlogQueueChannel()));
//      router.setRecipients(recipients);
//      return router;
//  }

    @MessageEndpoint
    public static class Foo {

        @Autowired
        private MessageChannel replyQueueChannel;

        @Autowired
        private MessageChannel mailQueueChannel;

        @Autowired
        private MessageChannel auditlogQueueChannel;

        private List<MessageChannel> channels;

        @ServiceActivator(inputChannel="foo")
        public void sendIt(Message<String> deferredMsg) {
            replyQueueChannel.send(deferredMsg);
            auditlogQueueChannel.send(deferredMsg);
            mailQueueChannel.send (deferredMsg);
        }

        // Router Technique 2
        @Router(inputChannel="routedMessageChannel")
        public List<MessageChannel> route(Message<?> message) {
            if (this.channels == null) {
                this.channels = Arrays.asList(new MessageChannel[] { this.replyQueueChannel, this.mailQueueChannel,
                        this.auditlogQueueChannel });
            }
            return this.channels;
        }

    }

}

<强> EDIT2

在Java配置中创建路由器有两种技术。

使用XML声明的端点创建2个bean - 消息处理程序和使用者。使用JavaConfig时,任何MessageHandler @Bean都可以使用@ServiceActivator进行注释,以创建相应的使用者。

或者,您可以使用注释为@Router的POJO方法。

我已更新上面的示例以显示其他技术。再一次,它对我来说很好。

您可以找到完整的项目on github here

正如我所说,如果你丢失消息,你应该使用调试日志记录以及redis-cli monitor命令来弄清楚发生了什么。