apache / rocketmq-spring

Apache RocketMQ Spring Integration
https://rocketmq.apache.org/
Apache License 2.0
2.09k stars 894 forks source link

【Bug Report】报告 rocketmq-v5-client-spring-boot 的 3 个 Bug #674

Open ldcsaa opened 4 weeks ago

ldcsaa commented 4 weeks ago

BUG REPORT

在使用的过程中,发现了 rocketmq-v5-client-spring-boot 的以下 3 个Bug:

  1. ExtTemplateResetConfiguration.javaExtConsumerResetConfiguration.java

String.format 应该用 '%' 而不是 '{}' 作为占位符;另外,也不存在文本中提到的 '@ExtTemplateConfiguration' 注解

    private void validate(ExtProducerResetConfiguration annotation,
                          GenericApplicationContext genericApplicationContext) {
        if (genericApplicationContext.isBeanNameInUse(annotation.value())) {
            // ! BUG !
            // String.format 应该用 '%' 而不是 '{}' 作为占位符;另外,也不存在文本中提到的 '@ExtTemplateConfiguration' 注解
            throw new BeanDefinitionValidationException(String.format("Bean {} has been used in Spring Application Context, " +
                            "please check the @ExtTemplateConfiguration",
                    annotation.value()));
        }
    }
  1. ExtTemplateResetConfiguration.javaExtConsumerResetConfiguration.java

private void registerTemplate(String beanName, Object bean) 中调用 validate(annotation, genericApplicationContext) 检测beanName 是否已存在:

    private void validate(ExtProducerResetConfiguration annotation,
                          GenericApplicationContext genericApplicationContext) {
        if (genericApplicationContext.isBeanNameInUse(annotation.value())) {
            throw new BeanDefinitionValidationException(String.format("Bean {} has been used in Spring Application Context, " +
                            "please check the @ExtTemplateConfiguration",
                    annotation.value()));
        }
    }

以下 template 定义会导致导致 validate() 校验失败:

@ExtProducerResetConfiguration(value = FifoPruducerTemplate.BEAN_NAME, topic = "${rocketmq-fifo.simple-consumer.topic}")
public class FifoPruducerTemplate extends RocketMQClientTemplate
{
    public static final String BEAN_NAME = "fifoPruducerTemplate";
}
@ExtConsumerResetConfiguration
(
    value = FifoConsumerTemplate.BEAN_NAME,
    topic = "${rocketmq-fifo.simple-consumer.topic}"
)
public class FifoConsumerTemplate extends SoaRocketMQClientTemplate
{
    public static final String BEAN_NAME = "fifoConsumerTemplate";
}

因为 FifoPruducerTemplate、FifoConsumerTemplate 使用了 fifoPruducerTemplatefifoConsumerTemplate 这个beanName,validate() 检测到存在这个beanName。因此报错。
唯一的处理办法就是不能定义注解的value属性,因为只要value有值就过不了validate()校验。
validate() 校验似乎是多余的,可以去掉;即使不去掉也应排除自身的 beanName。

  1. RocketMQUtil.java

调用 keys.toString() 有问题:意味着无论 keys 参数是逗号分隔的字符串,或者是字符串数组,传入 messageBuilder.setKeys() 后都变为单个字符串。这似乎与 messageBuilder.setKeys() 的设计目标不一致。

    public static org.apache.rocketmq.client.apis.message.Message getAndWrapMessage(
            String destination, MessageHeaders headers, byte[] payloads, Duration messageDelayTime, String messageGroup) {
        if (payloads == null || payloads.length < 1) {
            return null;
        }
        if (destination == null || destination.length() < 1) {
            return null;
        }
        String[] tempArr = destination.split(":", 2);
        final ClientServiceProvider provider = ClientServiceProvider.loadService();
        org.apache.rocketmq.client.apis.message.MessageBuilder messageBuilder = null;
        // resolve header
        if (Objects.nonNull(headers) && !headers.isEmpty()) {
            Object keys = headers.get(RocketMQHeaders.KEYS);
            if (ObjectUtils.isEmpty(keys)) {
                keys = headers.get(toRocketHeaderKey(RocketMQHeaders.KEYS));
            }
            messageBuilder = provider.newMessageBuilder()
                    .setTopic(tempArr[0]);
            if (tempArr.length > 1) {
                messageBuilder.setTag(tempArr[1]);
            }
            if (StringUtils.hasLength(messageGroup)) {
                messageBuilder.setMessageGroup(messageGroup);
            }
            if (!ObjectUtils.isEmpty(keys)) {
                // ! BUG !
                // 这里调用 keys.toString() 有问题:意味着无论 keys 参数是逗号分隔的字符串,或者是字符串数组,传入 messageBuilder.setKeys() 后都变为单个字符串。这似乎与 messageBuilder.setKeys() 的设计目标不一致。
                messageBuilder.setKeys(keys.toString());
            }
            if (Objects.nonNull(messageDelayTime)) {
                messageBuilder.setDeliveryTimestamp(System.currentTimeMillis() + messageDelayTime.toMillis());
            }
            messageBuilder.setBody(payloads);
            org.apache.rocketmq.client.apis.message.MessageBuilder builder = messageBuilder;
            headers.forEach((key, value) -> builder.addProperty(key, String.valueOf(value)));
        }
        return messageBuilder.build();
    }