消息中间件RocketMQ(四):如何在SpringBoot中使用RocketMQ原生API

生产者

1.依赖

	<dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-client</artifactId>
        <version>4.5.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-common</artifactId>
        <version>4.5.1</version>
    </dependency>

2.配置文件

  • 为了方便修改 并不是springboot的配置
# NameServer地址
apache.rocketmq.namesrvAddr=192.168.56.129:9876
# 生产者的组名
apache.rocketmq.producer.producerGroup=test_Producer

发送非事务消息
第一步:编写配置类

import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class MsgProducer {

    @Value("${apache.rocketmq.producer.producerGroup}")
    private String producerGroup;

    @Value("${apache.rocketmq.namesrvAddr}")
    private String namesrvAddr;

    private DefaultMQProducer mqProducer;

	//调用方注入MsgProducer后 通过这个方法获取配置好的DefaultMQProducer
    public DefaultMQProducer getMqProducer(){
        return mqProducer;
    }

    @PostConstruct
    public void initMQ(){
        mqProducer=new DefaultMQProducer(producerGroup);
        mqProducer.setNamesrvAddr(namesrvAddr);
        mqProducer.setVipChannelEnabled(false);
        try {
            mqProducer.start();
        } catch (MQClientException e) {
            e.printStackTrace();
        }
    }

    @PreDestroy
    public void destory(){
        mqProducer.shutdown();
    }
}

第二步:发送消息

  • 同步、非顺序
 	@Autowired
    private MsgProducer msgProducer;

    public void sendMsg() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
        //消息体
        String msg="hello";
        //包装成消息
        Message message=new Message("test_topic_2","test",msg.getBytes());
        //调用配置好的DefaultMQProducer发送消息
        SendResult result=msgProducer.getMqProducer().send(message);
    }
  • 异步、非顺序

    • 就是send()的参数多加个callback 省略…
  • 同步、顺序

	@Autowired
    private MsgProducer msgProducer;

    public void sendMsg() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
    	//发100条消息测试
        for(int i=1;i<=100;i++){
        	/**
        	 * 消息 
        	 * 因为默认自动创建的topic有四个队列 所以type表示队列id、value表示值
        	 * 如果按照队列读取 那么同一个type下的value一定按照接收的顺序从小到大
        	 * /
            String msg="type:"+i%4+" value:"+i;
            Message message=new Message("test_topic_2","test",msg.getBytes());
            
            SendResult result=msgProducer.getMqProducer().send(message, new MessageQueueSelector() {
                        @Override
                        //args一般是唯一id 用send的第三个参数传入(这里指的i)
                        public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
                        
                            int queueNum = Integer.valueOf(String.valueOf(arg)) % 4;
                            System.out.println("队列id:"+queueNum+" 消息:"+new String(msg.getBody()));
                            
                            return mqs.get(queueNum);
                        }
                    },i);
        }
    }

发送事务消息
(即消息先不发到broker的目的队列,而是包装一层放到中间队列,待提交之后再放到目的队列。)

第一步:配置类

@Component
public class TxMsgProducer {

    @Value("${apache.rocketmq.producer.producerGroup}")
    private String producerGroup;

    @Value("${apache.rocketmq.namesrvAddr}")
    private String namesrvAddr;

    private TransactionMQProducer mqProducer;

    public DefaultMQProducer getMqProducer(){
        return mqProducer;
    }

    @PostConstruct
    public void initMQ(){
        mqProducer=new TransactionMQProducer(producerGroup);
        mqProducer.setNamesrvAddr(namesrvAddr);
        mqProducer.setVipChannelEnabled(false);
        mqProducer.setNamesrvAddr(namesrvAddr);
        //下面两个时新增的
        mqProducer.setExecutorService(getExecutorService());
        mqProducer.setTransactionListener(new TransactionListenerImpl());

        try {
            mqProducer.start();
        } catch (MQClientException e) {
            e.printStackTrace();
        }
    }

    @PreDestroy//在程序运行结束时执行
    public void destory(){
        mqProducer.shutdown();
    }


    /**
     * 事务监听
     */
    class TransactionListenerImpl implements TransactionListener {
        /**
         * 第一次判断是否提交或回滚
         *
         * @param message
         * @param arg
         * @return
         */
        @Override
        public LocalTransactionState executeLocalTransaction(Message message, Object arg){

            //message就是那个半发送的消息 arg是在transcationProducter.send(Message,Object)时的另外一个携带参数)

            //执行本地事务或调用其他为服务

            if(true) return LocalTransactionState.COMMIT_MESSAGE;

            if(true) return LocalTransactionState.ROLLBACK_MESSAGE;

            //如果在检查事务时数据库出现宕机可以让broker过一段时间回查 和return null 效果相同
            return LocalTransactionState.UNKNOW;
        }

        /**
         * 返回UNKOWN时回查!
         * @param messageExt
         * @return
         */
        @Override
        public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {
            //只去返回commit或者rollback
            return LocalTransactionState.COMMIT_MESSAGE;
        }


    }

    /**
     * 定义一个线程池 让broker用来执行回调和回查
     * 
     * @return
     */
    public ExecutorService getExecutorService(){
        return new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2000));
    }
    
}

第二步:发送消息

@Autowired
    private TxMsgProducer msgProducer;

    public void sendMsg() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
        String msg="hello";
        Message message=new Message("test_topic_2","test",msg.getBytes());
        //调用配置好的TxMsgProducer 发送消息
        SendResult result=msgProducer.getMqProducer().send(message);
    }

消费者

1.依赖

	<dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-client</artifactId>
        <version>4.5.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-common</artifactId>
        <version>4.5.1</version>
    </dependency>

2.配置文件

  • 为了方便修改 并不是springboot的配置
# NameServer地址
apache.rocketmq.namesrvAddr=192.168.56.129:9876
# 消费者的组名
apache.rocketmq.consumer.PushConsumer=test_Consumer

3.消费消息

@Component
public class MsgConsumer {

    @Value("${apache.rocketmq.consumer.PushConsumer}")
    private String consumerGroup;

    @Value("${apache.rocketmq.namesrvAddr}")
    private String namesrvAddr;

    private DefaultMQPushConsumer consumer;

    @PostConstruct
    public void init() throws MQClientException {
        consumer=new DefaultMQPushConsumer(consumerGroup);
        consumer.setNamesrvAddr(namesrvAddr);

        //设置consumer所订阅的Topic和Tag,*代表全部的Tag
        consumer.subscribe("test_topic_2", "*");

        /**
         * CONSUME_FROM_LAST_OFFSET 默认策略,从该队列最尾开始消费,跳过历史消息
         * CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍
         * /
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
        
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeOrderlyContext consumeOrderlyContext) {
                try{
                    System.out.println("接受:"+new String(list.get(0).getBody()));
                }catch (Exception e){
                    return ConsumeConcurrentlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;
                }
                return ConsumeConcurrentlyStatus.SUCCESS;
            }
        });
        consumer.start();
    }


    @PreDestroy
    public void destory(){
        consumer.shutdown();
    }
}

4.其他消费情况说明

  • 顺序消费
    • 只用把 consumer.registerMessageListener(new MessageListenerConcurrently(){}) 改成consumer.registerMessageListener(new MessageListenerOrderly(){})
  • 事务消费
    • 不用改变消费者 如果事务的监听rollback了 消费者的消费结果会自动回滚
  • 广播消费
    consumer.setMessageMode(MessageMode.BROADCASTING)
    consumer.setOffsetStore(OffsetStore.LocalFileOffsetStore)
    
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值