在 RabbitListener 中处理通用类型

Handle Generic Type in RabbitListener

在我的 springboot 应用程序中,我正在创建一条包含通用类型的消息,如下所示:

public List<QMessage<T>> composeMessage(String entityName, List<T> input) {
    if (CollectionUtils.isEmpty(input)) {
        return null;
    }

    log.debug("Composing message to send");

    List<QMessage<T>> result = new ArrayList<>();
    input.forEach(el -> {
        QMessage<T> tmp = new QMessage<>();
        tmp.setSourceId(getSourceId(el));
        tmp.setEntityName(entityName);
        tmp.setData(el);
        result.add(tmp);
    });
    return result;
}

public void convertAndPublishList(List<QMessage<T>> items) {
    try {
        log.debug("Converting message to JSON and publishing to RabbitMQ");
        rabbitTemplate.convertAndSend(MQConfig.WD_COMMONS_QUEUE_EXCHANGE, MQConfig.WD_COMMONS_QUEUE_ROUTING_KEY, items);
    } catch (AmqpException e) {
        log.error("Error during message publishing to RabbitMQ. Exception: {}", e.getMessage());
        throw new BlenderProducerException(e.getMessage(), e);
    }
}


@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class QMessage<T> implements Serializable {

    private static final long serialVersionUID = 9095736695643670685L;

    private Long sourceId;

    private String entityName;

    private T data;

}

在听众方面,我想以某种方式处理泛型,这就是我尝试过的:

@Slf4j
@Component
@RequiredArgsConstructor
@RabbitListener(queues = MQConfig.WD_COMMONS_QUEUE)
public class WDCommonsListeners {


        @RabbitHandler
        public void handleA(List<QMessage<Dog>> message) {
            System.out.println("handle 1");
        }

        @RabbitHandler
        public void handleB(List<QMessage<Cat>> message) {
            System.out.println("handle 2");
        }

}

但我收到此异常消息: org.springframework.amqp.AmqpException:负载类型的方法不明确:class java.util.ArrayList:handleA 和 handleB

考虑 Cat 和 Dog class 都在扩展 Animal class

我也尝试过使用未知类型的消息,但我收到了一个对象的 LinkedList:

@RabbitListener(queues = MQConfig.WD_COMMONS_QUEUE)
public void listener(List<QMessage<?>> message) throws IOException {

    if (!CollectionUtils.isEmpty(message)) {
            for (QMessage<?> msg : message) {
                System.out.println("msg");
            }
    }

也许我必须从消息中获取 JSON 并使用 ObjectMapper 将其转换为对象?

它只是不检查方法参数的通用类型:methodParameter.getParameterType().isAssignableFrom(payloadClass)。所以,这就是你产生歧义的原因。

由于您的逻辑很难处理集合及其深层嵌套的泛型类型,我真的建议使用单个 @RabbitListener 并手动执行相应的路由。

必须为 TypePrecedence.TYPE_ID 配置 DefaultJackson2JavaTypeMapper 以使其在调用侦听器方法之前将传入数据转换为 List<QMessage<?>>https://docs.spring.io/spring-amqp/docs/current/reference/html/#Jackson2JsonMessageConverter-from-message