如何访问MongoDB支持的Spring集成消息存储中存储的消息?

如何访问MongoDB支持的Spring集成消息存储中存储的消息?,mongodb,spring-integration,Mongodb,Spring Integration,我实现了一个Spring集成QueueChannel,由MongoDbChannelMessageStore支持。消息生成和使用消息的集成流都按预期工作 现在我尝试实现一种逻辑,它列出并记录当前包含在消息存储或队列通道中的所有消息。信息应与其POJO有效载荷一起记录(采用toString()格式)。不得通过列出从队列通道中删除消息。这个逻辑应该在应用程序启动或按需调用 下面是一些代码片段(我使用的是SpringBoot2.3.4) 我的信息有效载荷: @Data public class Exa

我实现了一个Spring集成
QueueChannel
,由
MongoDbChannelMessageStore
支持。消息生成和使用消息的集成流都按预期工作

现在我尝试实现一种逻辑,它列出并记录当前包含在消息存储或队列通道中的所有消息。信息应与其POJO有效载荷一起记录(采用
toString()
格式)。不得通过列出从队列通道中删除消息。这个逻辑应该在应用程序启动或按需调用

下面是一些代码片段(我使用的是SpringBoot2.3.4)

我的信息有效载荷:

@Data
public class ExampleMessage implements Serializable {
    private String id;
    private Instant timestamp;
}
我的集成配置:

@SpringBootApplication
@EnableIntegration
@Slf4j
public class IntegrationApp {

    private static final String GROUP_ID = "my-group";

    // ... main method omitted

    @Bean
    public MongoDbChannelMessageStore mongoDbChannelMessageStore(MongoDatabaseFactory mongoDatabaseFactory) {
        return new MongoDbChannelMessageStore(mongoDatabaseFactory, "message-store");
    }

    @Bean
    public PollableChannel channel(MongoDbChannelMessageStore messageStore) {
        MessageGroupQueue messageGroupQueue = new MessageGroupQueue(messageStore, GROUP_ID);
        return new QueueChannel(messageGroupQueue);
    }

    @Bean
    public IntegrationFlow integrationFlow(PollableChannel channel) {
        return IntegrationFlows.from(channel)
                .handle(message -> log.info("Message received: {}", message.getPayload()),
                        e -> e.poller(Pollers
                            .fixedRate(7000, 5000)
                            .maxMessagesPerPoll(1)
                            .taskExecutor(Executors.newSingleThreadExecutor())))
                .get();
    }
我的信息制作人:

@Component
@EnableScheduling
@Slf4j
public class ExampleMessageProducer {

    @Autowired
    private PollableChannel channel;

    private final MessagingTemplate messagingTemplate = new MessagingTemplate();

    @Scheduled(initialDelay = 1000, fixedDelay = 3000)
    void produceMessage() {
        ExampleMessage exampleMessage = new ExampleMessage();
        messagingTemplate.send(channel, MessageBuilder.withPayload(exampleMessage).build());
        log.info("Message sent: {}", exampleMessage);
    }
}
从Spring Integration messaging的公共API中,可以针对该问题得出以下方法:

@Component
@Slf4j
public class EventListenerBean {

    @Autowired
    MongoDbChannelMessageStore messageStore;

    @EventListener
    public void onApplicationEvent(ContextRefreshedEvent event) {

        Collection<Message<?>> messages = messageStore.getMessageGroup(GROUP_ID).getMessages();
        log.info("# of messages in group: {}", messages.size());
        messages.forEach(m -> log.info("Stored message: {}", m.getPayload()));
    }
}

我希望避免直接查询MongoDB
消息存储
集合,而更喜欢使用Spring集成API


有人能解决这个问题吗?提前感谢。

如果您对特定的
MessageGroup
感兴趣,可以使用
BasicMessageGroupStore
合同的
getMessageGroup()
API

无论哪种方式,在bean初始化阶段访问低级资源(如数据库)都不好,就像您在
channel
bean定义中使用日志一样。您必须推迟这样的操作,直到整个应用程序上下文就绪。或者捕获一个
上下文刷新事件
,或者实现一个
SmartLifecycle.start()
契约

更新

事实证明,关于
MongoDbChannelMessageStore
及其API,您是对的。我们绝对无法访问该合同中的消息:

/**
 * Not fully used. Only wraps the provided group id.
 */
@Override
public MessageGroup getMessageGroup(Object groupId) {
    return getMessageGroupFactory().create(groupId);
}
因此,我们只创建一个新的空组,而不使用MongoDB集合中的任何钩子

作为一种解决方法,我建议您使用一个常规的
ConfigurableMongoDbMessageStore
作为一个bean,用于相同的
消息存储
集合。这已经为我们提供了一个API来迭代组及其消息。因此,您将使用
MongoDbChannelMessageStore
在该
QueueChannel
上执行活动操作,并使用常规
ConfigurableMongoDbMessageStore
读取集合内容


我们可能需要考虑在
ChannelMessageStore
中实现此API。看起来没有什么害处。。。请随意提出GH问题,以便改进

我做了一些调试。我看不出
MongoDbChannelMessageStore
的方法是如何实现的

public MessageGroup getMessageGroup(Object groupId) {
    return this.getMessageGroupFactory().create(groupId);
}
(我在
EventListenerBean
中使用)可以生成与空的
MessageGroup
不同的任何内容

我试图通过以下初始化
MongoDBChannel MessageStore
来改变这种行为:

@Bean
public MongoDbChannelMessageStore mongoDbChannelMessageStore(MongoDatabaseFactory mongoDatabaseFactory) {
    MongoDbChannelMessageStore store = new MongoDbChannelMessageStore(mongoDatabaseFactory, "message-store");
    SimpleMessageGroupFactory messageGroupFactory = new SimpleMessageGroupFactory(GroupType.PERSISTENT) {
        @Override
        public MessageGroup create(Object groupId) {
            return this.create(store, groupId);
        }
    };

    store.setLazyLoadMessageGroups(false);
    store.setMessageGroupFactory(messageGroupFactory);
    return store;
}

这是一个相当不错的技巧,但在它最终出现在
AbstractConfigurableMongoDbMessageStore
getMessagesForGroup()
中之前效果很好,不幸的是,它没有实现。

我完全同意你最后的评论,并相应地修改了我的问题。调用
迭代器()
MongodbChannel MessageStore
上的
导致
不支持操作异常
;它似乎没有在
AbstractConfigurableMongoDbMessageStore
中实现。您答案第2段中的解决方案正是我在
EventListenerBean
中试图做的。它会导致一个空集合。是的,我看到它没有为
MongoDbChannelMessageStore
实现。但不确定是否必须这样做。。。你的第二个论点无关紧要:很可能你店里没有什么东西可看。我不同意。我仍然能够通过非空的消息存储和上面问题中发布的代码重现这种行为。我问题中的日志输出部分应该说明这一点。在初始延迟之后和生成新消息之前,应用程序立即开始使用消息存储中的消息(我为此输出禁用了生产者)。但请注意我下面的后续行动。好的。我会试着复制。敬请期待!
@Bean
public MongoDbChannelMessageStore mongoDbChannelMessageStore(MongoDatabaseFactory mongoDatabaseFactory) {
    MongoDbChannelMessageStore store = new MongoDbChannelMessageStore(mongoDatabaseFactory, "message-store");
    SimpleMessageGroupFactory messageGroupFactory = new SimpleMessageGroupFactory(GroupType.PERSISTENT) {
        @Override
        public MessageGroup create(Object groupId) {
            return this.create(store, groupId);
        }
    };

    store.setLazyLoadMessageGroups(false);
    store.setMessageGroupFactory(messageGroupFactory);
    return store;
}