Java基于rocketmq的订单生产与消费场景示例

1 篇文章 0 订阅

一、依赖配置

1、maven pom.xml引入依赖

<properties>
        <rocketmq-client.version>4.5.2</rocketmq-client.version>
</properties>
<dependency>
         <groupId>org.apache.rocketmq</groupId>
         <artifactId>rocketmq-client</artifactId>
         <version>${rocketmq-client.version}</version>
</dependency>

2、生产者application.yml加上配置

rocketmq:
  producer:
    isOnOff: on
    groupName: k12OrderNotifyGroup
    namesrvAddr: rocket-01:9876;rocket-02:9876;rocket-03:9876
    maxMessageSize: 4096
    sendMsgTimeout: 3000
    retryTimesWhenSendFailed: 2
    topic: k12_order

 3、消费者application.yml加上配置

rocketmq:
  consumer:
    #该应用是否启用消费者
    isOnOff: on
    groupName: k12OrderNotifyGroup
    #mq的nameserver地址
    namesrvAddr: rocket-01:9876;rocket-02:9876;rocket-03:9876
    #该消费者订阅的主题和tags("*"号表示订阅该主题下所有的tags),格式:topic~tag1||tag2||tag3;topic2~*;
    topics: k12_order~*;
    consumeThreadMin: 20
    consumeThreadMax: 64
    #设置一次消费消息的条数,默认为1条
    consumeMessageBatchMaxSize: 1
    reconsumeTimes: 3
    topic: k12_order

二、Producer服务生产订单

1、生产启动配置类

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;

import java.util.UUID;

@Slf4j
@Data
@ConfigurationProperties(prefix = "rocketmq-producer")
public class RocketMQProducerConfig {

    /**
     * 生产/消费组
     */
    private String groupName;

    /**
     * 地址
     */
    private String namesrvAddr;

    /**
     * 最大生产量
     */
    private Integer maxMessageSize;

    /**
     * 往队列中发送消息超时时间
     */
    private Integer sendMsgTimeout;

    /**
     * 超时失败重发次数
     */
    private Integer retryTimesWhenSendFailed;

    /**
     * topic主题
     */
    private String topic;

    @Bean
    public DefaultMQProducer getRocketMQProducer() {
        DefaultMQProducer defaultMQProducer = new DefaultMQProducer(this.groupName);
        defaultMQProducer.setNamesrvAddr(this.namesrvAddr);

        //如果需要同一个jvm中不同的producer往不同的mq集群发送消息,需要设置不同的instanceName
        //defaultMQProducer.setInstanceName(UUID.randomUUID().toString());

        if (!ObjectUtils.isEmpty(this.maxMessageSize)) {
            defaultMQProducer.setMaxMessageSize(this.maxMessageSize);
        }
        if (!ObjectUtils.isEmpty(this.sendMsgTimeout)) {
            defaultMQProducer.setSendMsgTimeout(this.sendMsgTimeout);
        }
        if (!ObjectUtils.isEmpty(this.retryTimesWhenSendFailed)) {
            defaultMQProducer.setRetryTimesWhenSendFailed(this.retryTimesWhenSendFailed);
        }

        try {
            //生产者启动
            defaultMQProducer.start();
            log.info(String.format(
                    "producer start, groupName:[%s],namesrvAddr:[%s]"
                    , this.groupName
                    , this.namesrvAddr
                    )
            );
        } catch (MQClientException e) {
            log.error(String.format(
                    "producer is error, {}"
                    , e.getMessage()
                    , e
                    )
            );
        }
        return defaultMQProducer;
    }
}

2、生产者类

接口

public interface Producer {

    void send(String topic, String tags, String keys, String body);

    void sendDelay(String topic, String tags, String keys, String body, Integer delayTimeLevel);
}

 实现类

import com.xiyunerp.yzbizcenter.k12.order.dmm.Producer;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Slf4j
@Component
public class RocketMQProducer implements Producer {

    @Resource
    private DefaultMQProducer defaultMQProducer;

    @Override
    public void send(String topic, String tags, String keys, String body) {
        Message message = new Message(topic, tags, keys, body.getBytes());
        log.debug("消息发送信息内容:{}", body);
        SendResult sendResult;
        try {
            sendResult = defaultMQProducer.send(message);
            log.debug("消息发送响应信息: {}", sendResult.toString());
        } catch (MQClientException | RemotingException | MQBrokerException | InterruptedException e) {
            log.debug("发送消息异常信息: {}", e.getMessage());
        }
    }

    @Override
    public void sendDelay(String topic, String tags, String keys, String body, Integer delayTimeLevel) {
        Message message = new Message(topic, tags, keys, body.getBytes());
        message.setDelayTimeLevel(delayTimeLevel);
        log.debug("延迟消息发送信息内容:{}", body);
        SendResult sendResult;
        try {
            sendResult = defaultMQProducer.send(message);
            log.debug("延迟消息发送响应信息: {}", sendResult.toString());
        } catch (MQClientException | RemotingException | MQBrokerException | InterruptedException e) {
            log.debug("延迟发送消息异常信息: {}", e.getMessage());
        }
    }
}

3、业务类(调用生产者)

import com.xiyunerp.yzbizcenter.k12.order.config.RocketMQConfig;
import com.xiyunerp.yzbizcenter.k12.order.zys.dmm.RocketMQProducer;
import com.xiyunerp.yzbizcenter.k12.utility.context.BeanUtils;
import com.xiyunerp.yzbizcenter.k12.utility.utils.JsonUtils;
import com.xiyunerp.yzbizcenter.k12.utility.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Service;

import java.util.List;

@Slf4j
@Service
public class OrderProducerService {
    
    private RocketMQProducerConfig  rocketMQProducerConfig  = 
            BeanUtils.getBean("rocketMQProducerConfig ", RocketMQProducerConfig .class);

    private RocketMQProducer rocketMQProducer = BeanUtils.getBean("rocketMQProducer", RocketMQProducer.class);

    public void sendDelay() {
        //处理自己其他的业务逻辑,设置相关参数
        
        //调用生产类进行往队列中发送消息
        String topic = "";
        String tags = "";
        String keys = "";
        String body = "";
        Integer delayTimeLevel = 4;
        try {
            //指定延迟时间
            rocketMQProducer.sendDelay(topic, tags, keys, body, delayTimeLevel);
            //rocketMQProducer.send(topic, tags, keys, body);
        } catch (Exception e) {
            log.debug("rocketMQ producer error, {}", e.getMessage());
        }
    }
}

三、Consumer服务生产订单

1、消费启动配置类

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.UUID;

@Slf4j
@Data
@ConfigurationProperties(prefix = "rocketmq-consumer")
public class RocketMQConsumerConfig {

    private String namesrvAddr;

    private String groupName;

    private Integer consumeThreadMin;

    private Integer consumeThreadMax;

    private String topics;

    private Integer consumeMessageBatchMaxSize;

    private Integer reconsumeTimes;

    private String topic;

    @Resource
    private RocketListenerProcessor mqMessageListenerProcessor;

    @Bean
    public DefaultMQPushConsumer getRocketMQConsumer() {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(groupName);
        consumer.setNamesrvAddr(namesrvAddr);
        consumer.setInstanceName(UUID.randomUUID().toString());
        consumer.setConsumeThreadMin(consumeThreadMin);
        consumer.setConsumeThreadMax(consumeThreadMax);
        consumer.registerMessageListener(mqMessageListenerProcessor);
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
        /**
         * 设置消费模型,集群还是广播,默认为集群
         */
        //consumer.setMessageModel(MessageModel.CLUSTERING);
        consumer.setConsumeMessageBatchMaxSize(consumeMessageBatchMaxSize);
        try {
            String[] topicTagsArr = topics.split(";");
            for (String topicTags : topicTagsArr) {
                String[] topicTag = topicTags.split("~");
                consumer.subscribe(topicTag[0], topicTag[1]);
            }
            consumer.start();
            log.debug("consumer is start, groupName:{}, topics:{}, namesrvAddr:{}", groupName, topics, namesrvAddr);
        } catch (MQClientException e) {
            log.error("consumer is start, groupName:{}, topics:{}, namesrvAddr:{}", groupName, topics, namesrvAddr, e);
        }
        return consumer;
    }
}

2、消费者类(调用业务类处理业务)

import com.xiyunerp.yzbizcenter.k12.mini.alipay.service.trade.AliPayOrderSyncService;
import com.xiyunerp.yzbizcenter.k12.utility.utils.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class RocketListenerProcessor implements MessageListenerConcurrently {

    @Resource
    RocketMQConsumerConfig rocketMQConfig;

    @Resource
    AliPayOrderSyncService aliPayOrderSyncService;//处理业务类,自定义

    @Resource
    RedisTemplate redisTemplate;

    private final static Long EXPIRE_TIME_MILLI = 1 * 60 * 1000L;

    private final static Long INCREMENT_STEP = 1L;

    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
        if (CollectionUtils.isEmpty(list)) {
            log.debug("接受到的消息为空,不处理,直接返回成功");
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        }
        for (MessageExt messageExt : list) {
            if (this.barrier(messageExt.getMsgId(), EXPIRE_TIME_MILLI)) {
                continue;
            }
            if (messageExt.getTopic().equalsIgnoreCase(rocketMQConfig.getTopic())) {
                int reconsume = messageExt.getReconsumeTimes();
                if (reconsume == rocketMQConfig.getReconsumeTimes()) {
                    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                }

                log.debug("接受到的消息为:{}", messageExt.toString());
                log.debug("接受到的消息为:{}, {}", messageExt.getTags(), Long.parseLong(new String(messageExt.getBody())));
                //调用业务类消费数据,自定义
                //aliPayOrderSyncService.sendOrder(messageExt);
            }
        }
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
    /**
     * 做幂等避免重复消费
     * @param key
     * @param expireMillis
     * @return
     */
    public Boolean barrier(String key, Long expireMillis) {
        Long count = this.increment(key, expireMillis);
        if (count > 1) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    public Long increment(String key, Long expireMillis) {
        Long count = redisTemplate.opsForValue().increment(key, INCREMENT_STEP);
        if (1 == count) {
            redisTemplate.expire(key, expireMillis, TimeUnit.MILLISECONDS);
        }
        return count;
    }
}

3、业务类(被消费类调用,处理自己业务)

@Service
public class AliPayOrderSyncService {
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值