【问题标题】:Spring integration migration to Redis from RabbitMQ to share application eventsSpring 集成从 RabbitMQ 迁移到 Redis 以共享应用程序事件
【发布时间】:2021-11-29 13:57:42
【问题描述】:

我们正在微服务应用程序中从 RabbitMQ 迁移到 Redis。

这是我们的服务激活器

@ServiceActivator(inputChannel = ApplicationEventChannelNames.REMOTE_CHANNEL)
public void handleApplicationEvent(@Header(value = ApplicationEventHeaders.APPLICATION_EVENT) final ApplicationEvent event,
                                   @Payload Object message) {
...
}

最初我们遇到了一个问题,我们在SimpleMessageConverter 中丢失了应用程序事件。我们通过实现CustomRedisMessageConverter 并将应用程序事件放入fromMessage 方法中的有效负载中并从有效负载中检索它并在toMessage 方法中使用应用程序事件创建新的消息头来解决它。

    @Override
    public Object fromMessage(Message<?> message, Class<?> targetClass) {
        if (message.getHeaders().get(ApplicationEventHeaders.APPLICATION_EVENT) != null) {

            Map<String, Object> map = new HashMap<>();

            map.put("headers", ((ApplicationEvent) message.getHeaders().get(ApplicationEventHeaders.APPLICATION_EVENT)).getName());
            map.put("payload", message.getPayload());

            GenericMessage<Map<String, Object>> msg = new GenericMessage<>(map, message.getHeaders());

            return super.fromMessage(msg, targetClass);
        }
        return super.fromMessage(message, targetClass);
    }

    @Override
    public Message<?> toMessage(Object payload, MessageHeaders headers) {

        try {
            final Map<String, ?> message = new ObjectMapper().readValue((String) payload, new TypeReference<Map<String, ?>>() {});

            if (message.get("headers") != null) {
                final Map<String, Object> messageHeaders = new HashMap<>(headers);

                messageHeaders.put(ApplicationEventHeaders.APPLICATION_EVENT, new ApplicationEvent((String) message.get("headers")));

                return super.toMessage(message.get("payload"), new MessageHeaders(messageHeaders));
            }
        } catch (JsonProcessingException exception) {
            /* Intentionally left blank */
        }

        return super.toMessage(payload, headers);
    }

我们想知道是否有更好的方法来做到这一点?

最后,服务激活器中的有效负载以LinkedHashMap 的形式出现,但我们希望它是一个对象。使用 RabbitMQ 可以解决此问题。

有没有办法在 Redis 中做同样的事情?还是我们使用 headers 来跟踪有效载荷的类型并手动将它们转换为对象?

更新 - REDIS 配置

    @Bean
    public RedisInboundChannelAdapter applicationEventInboundChannelAdapter(@Value(value = "${com.xxx.xxx.xxx.integration.spring.topic}") String topic,
                                                                            MessageChannel applicationEventRemoteChannel,
                                                                            RedisConnectionFactory connectionFactory) {



        final RedisInboundChannelAdapter inboundChannelAdapter = new RedisInboundChannelAdapter(connectionFactory);
        inboundChannelAdapter.setTopics(topic);
        inboundChannelAdapter.setOutputChannel(applicationEventRemoteChannel);
        inboundChannelAdapter.setErrorChannel(errorChannel());
        inboundChannelAdapter.setMessageConverter(new CustomRedisMessageConverter());

        return inboundChannelAdapter;
    }

    @ServiceActivator(inputChannel = "errorChannel")
    public void processError(MessageHandlingException exception) {

        try {

            logger.error(
                    "Could not process {}, got exception: {}",
                    exception.getFailedMessage().getPayload(),
                    exception.getMessage());

            logger.error(
                    ExceptionUtils.readStackTrace(exception));

        } catch (Throwable throwable) {

            logger.error(
                    "Got {} during processing with message: {} ",
                    MessageHandlingException.class.getSimpleName(),
                    exception);
        }
    }

    @Bean
    @ServiceActivator(inputChannel = ApplicationEventChannelNames.LOCAL_CHANNEL)
    public RedisPublishingMessageHandler redisPublishingMessageHandler(@Value(value = "${com.xxx.xxx.xxx.integration.spring.topic}") String topic,
                                                                       RedisConnectionFactory redisConnectionFactory) {

        final RedisPublishingMessageHandler redisPublishingMessageHandler = new RedisPublishingMessageHandler(redisConnectionFactory);


        redisPublishingMessageHandler.setTopic(topic);
        redisPublishingMessageHandler.setSerializer(new Jackson2JsonRedisSerializer<>(String.class));
        redisPublishingMessageHandler.setMessageConverter(new CusomRedisMessageConverter());
        return redisPublishingMessageHandler;
    }

    /*
     * MessageChannel
     */

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

【问题讨论】:

  • 我会说最初的想法是完全错误的。用一些基于 NoSQL DB 的仿真来替代像 RabbitMQ 这样成熟的消息代理是不可能的。我没有任何答案可以帮助您,但您可能自己尝试重新实现许多消息传递方面。如果您将一些相关代码分享给您尝试获取消息的 Redis 以及如何获取消息,它可能会更接近。
  • 我已经更新了问题。你能告诉我们哪个组件将有效负载从String 转换为LinkedHashMap

标签: spring-integration


【解决方案1】:

Redis 不支持标头,因此您必须将它们嵌入到正文中。请参阅EmbeddedJsonHeadersMessageMapper,它可以提供给双方的org.springframework.integration.support.converter.SimpleMessageConverter

【讨论】:

    猜你喜欢
    • 2017-10-29
    • 1970-01-01
    • 1970-01-01
    • 2016-05-26
    • 2012-04-08
    • 1970-01-01
    • 2014-05-04
    • 2016-11-14
    • 2015-11-17
    相关资源
    最近更新 更多