SpringBoot集成RocketMQ

SpringBoot集成RocketMQ

1、导入依赖(注意启动类上是不需要加其它注解的)

<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.0.4</version>
</dependency>

2、相关配置

2.1、生产者配置
rocketmq:
  name-server: 192.168.171.128:9876
  producer:
    group: boot-product
2.2、消费者配置
rocketmq:
  name-server: 192.168.171.128:9876

3、发送同步/异步/单向消息

3.1、消息发送方式三种方式
3.1.1、同步消息
package com.xiaoge;

import com.xiaoge.util.OrderStep;
import com.xiaoge.util.OrderUtil;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.sql.SQLOutput;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@SpringBootTest(classes = RocketMQApplication.class)
@RunWith(SpringRunner.class)
public class TestApplication {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 发送同步消息
     * @throws Exception
     */
    @Test
    public void sendMessage() throws Exception {
        Message msg = MessageBuilder.withPayload("springboot发送同步消息").build();
        rocketMQTemplate.send("helloBoot", msg);
    }
}

3.1.2、异步消息
package com.xiaoge;

import com.xiaoge.util.OrderStep;
import com.xiaoge.util.OrderUtil;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.sql.SQLOutput;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@SpringBootTest(classes = RocketMQApplication.class)
@RunWith(SpringRunner.class)
public class TestApplication {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 发送异步消息
     * @throws Exception
     */
    @Test
    public void sendAsyncMessage() throws Exception {
        System.out.println("发送前");
        rocketMQTemplate
                .asyncSend("helloBoot", "springboot发送异步消息", new SendCallback() {
                    @Override
                    public void onSuccess(SendResult sendResult) {
                        System.out.println("发送状态:"+sendResult.getSendStatus());
                    }

                    @Override
                    public void onException(Throwable throwable) {
                        System.out.println("消息发送失败!");
                    }
                });

        System.out.println("发送完毕");
        TimeUnit.SECONDS.sleep(5);
    }
}

3.1.3、单向消息
package com.xiaoge;

import com.xiaoge.util.OrderStep;
import com.xiaoge.util.OrderUtil;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.sql.SQLOutput;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@SpringBootTest(classes = RocketMQApplication.class)
@RunWith(SpringRunner.class)
public class TestApplication {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 发送单向消息
     * @throws Exception
     */
    @Test
    public void sendOneWayMessage() throws Exception {
        rocketMQTemplate
                .sendOneWay("helloBoot", "springboot发送单向消息");
    }
}

3.2、消息消费方
package com.xiaoge.listener;

import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.util.Date;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@Component
@RocketMQMessageListener(consumerGroup = "boot-consumer", topic = "helloBoot")
public class HelloBootListener implements RocketMQListener<MessageExt> {
    @Override
    public void onMessage(MessageExt messageExt) {
        System.out.println("收到的消息: " + new String(messageExt.getBody(), Charset.defaultCharset()));
    }
}

4、消息消费方式

4.1、集群
package com.xiaoge.listener;

import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.util.Date;

/**
 * TODO
 *      集群 @RocketMQMessageListener(consumerGroup = "boot-consumer", topic = "helloBoot", messageModel = MessageModel.CLUSTERING)
 *      广播 @RocketMQMessageListener(consumerGroup = "boot-consumer", topic = "helloBoot", messageModel = MessageModel.BROADCASTING)
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@Component
// todo MessageModel.CLUSTERING(集群-->默认集群)  MessageModel.BROADCASTING(广播)
@RocketMQMessageListener(consumerGroup = "boot-consumer", topic = "helloBoot", messageModel = MessageModel.CLUSTERING)
public class HelloBootListener implements RocketMQListener<MessageExt> {
    @Override
    public void onMessage(MessageExt messageExt) {
        System.out.println("收到的消息: " + new String(messageExt.getBody(), Charset.defaultCharset()) + " " + new Date());
    }
}

4.2、广播
package com.xiaoge.listener;

import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.util.Date;

/**
 * TODO
 *      集群 @RocketMQMessageListener(consumerGroup = "boot-consumer", topic = "helloBoot", messageModel = MessageModel.CLUSTERING)
 *      广播 @RocketMQMessageListener(consumerGroup = "boot-consumer", topic = "helloBoot", messageModel = MessageModel.BROADCASTING)
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@Component
// todo MessageModel.CLUSTERING(集群-->默认集群)  MessageModel.BROADCASTING(广播)
@RocketMQMessageListener(consumerGroup = "boot-consumer", topic = "helloBoot", messageModel = MessageModel.BROADCASTING)
public class HelloBootListener implements RocketMQListener<MessageExt> {
    @Override
    public void onMessage(MessageExt messageExt) {
        System.out.println("收到的消息: " + new String(messageExt.getBody(), Charset.defaultCharset()) + " " + new Date());
    }
}

4.3、消息发送
package com.xiaoge;

import com.xiaoge.util.OrderStep;
import com.xiaoge.util.OrderUtil;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.sql.SQLOutput;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@SpringBootTest(classes = RocketMQApplication.class)
@RunWith(SpringRunner.class)
public class TestApplication {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 发送10单向消息, 消费者默认是集群的, 所以默认有负载
     * @throws Exception
     */
    @Test
    public void send10OneWayMessage() throws Exception {
        for (int i = 0; i < 10; i++) {
            rocketMQTemplate
                    .sendOneWay("helloBoot", "springboot发送单向消息" + i);
        }
    }

    
}

5、顺序消息

5.1、生产者
package com.xiaoge.util;

import lombok.Data;
import lombok.ToString;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@Data
@ToString
public class OrderStep {

    private long orderId;
    private String desc;

}

package com.xiaoge.util;

import java.util.ArrayList;
import java.util.List;

public class OrderUtil {
    /**
     * 生成模拟订单数据
     */
    public static <T> List<T> buildOrders() {
        List<OrderStep> orderList = new ArrayList();
  
        OrderStep orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);
  
        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);
  
        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);
  
        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);
  
        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);
  
        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);
  
        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);
  
        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("推送");
        orderList.add(orderDemo);
  
        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);
  
        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);
  
        return (List<T>) orderList;
    }
}
package com.xiaoge;

import com.xiaoge.util.OrderStep;
import com.xiaoge.util.OrderUtil;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.sql.SQLOutput;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@SpringBootTest(classes = RocketMQApplication.class)
@RunWith(SpringRunner.class)
public class TestApplication {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 发送顺序消息
     * @throws Exception
     */
    @Test
    public void sendOrderlyMessage() throws Exception {
        // 设置队列选择器
        rocketMQTemplate.setMessageQueueSelector(new MessageQueueSelector() {
            @Override
            public MessageQueue select(List<MessageQueue> list, org.apache.rocketmq.common.message.Message message, Object o) {
                String orderStr = (String) o;
                Long orderId = Long.valueOf(orderStr);
                int index = (int)(orderId % list.size());
                // 获取选择的队列返回
                return list.get(index);
            }
        });

        List<OrderStep> orderSteps = OrderUtil.buildOrders();

        // String.valueOf(orderStep.getOrderId())就是你用来决定去拉格队列的值, 它会传递给上面的Object o
        orderSteps.forEach(orderStep -> {
            rocketMQTemplate.sendOneWayOrderly("orderlyTopicBoot", orderStep.toString(), String.valueOf(orderStep.getOrderId()));
        });
    }
}

5.2、消费者
package com.xiaoge.listener;

import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;

/**
 * TODO 顺序消息的消费
 *      consumeMode = ConsumeMode.ORDERLY 表示 一个队列对应一个线程
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@Component
@RocketMQMessageListener(consumerGroup = "orderly-consumer", topic = "orderlyTopicBoot", consumeMode = ConsumeMode.ORDERLY)
public class OrderlyTopicListener implements RocketMQListener<MessageExt> {
    @Override
    public void onMessage(MessageExt messageExt) {
        System.out.println("收到的消息: " + new String(messageExt.getBody(), Charset.defaultCharset()));
    }
}

6、延时消息

6.1、生产者
package com.xiaoge;

import com.xiaoge.util.OrderStep;
import com.xiaoge.util.OrderUtil;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.sql.SQLOutput;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@SpringBootTest(classes = RocketMQApplication.class)
@RunWith(SpringRunner.class)
public class TestApplication {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 发送延时消息
     * @throws Exception
     */
    @Test
    public void sendDelayMessage() throws Exception {
        Message msg = MessageBuilder.withPayload("springboot发送延时消息" + new Date()).build();
        // 发送超时时间 3000(3秒钟)  rocketmq超时等级3
        rocketMQTemplate.syncSend("helloBoot", msg, 3000, 3);
    }
 
}

6.2、消费者
package com.xiaoge.listener;

import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.util.Date;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@Component
@RocketMQMessageListener(consumerGroup = "boot-consumer", topic = "helloBoot")
public class HelloBootListener implements RocketMQListener<MessageExt> {
    @Override
    public void onMessage(MessageExt messageExt) {
        System.out.println("收到的消息: " + new String(messageExt.getBody(), Charset.defaultCharset()) + " " + new Date());
    }
}

7、消息过滤

7.1、TAG过滤
7.1.1、生产者
package com.xiaoge;

import com.xiaoge.util.OrderStep;
import com.xiaoge.util.OrderUtil;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.sql.SQLOutput;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@SpringBootTest(classes = RocketMQApplication.class)
@RunWith(SpringRunner.class)
public class TestApplication {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

   
    /**
     * 发送tag消息过滤
     * todo tag只能跟topic写在一起用:分割
     * @throws Exception
     */
    @Test
    public void sendTagFilterMessage() throws Exception {
        Message msg1 = MessageBuilder.withPayload("消息A").build();
        // todo 它的tag标签只能写在topic中用:分割, :左边是主题, :右边是tag, 所以我们在命令主题的时候不要带:
        rocketMQTemplate.sendOneWay("tagFilterBoot:TagA", msg1);
        Message msg2 = MessageBuilder.withPayload("消息B").build();
        rocketMQTemplate.sendOneWay("tagFilterBoot:TagB", msg2);
        Message msg3 = MessageBuilder.withPayload("消息C").build();
        rocketMQTemplate.sendOneWay("tagFilterBoot:TagC", msg3);
    }
}

7.1.2、消费者
package com.xiaoge.listener;

import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;

/**
 * TODO
 *      接收消息tag过滤, selectorExpression写过滤规则
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@Component
@RocketMQMessageListener(consumerGroup = "tag-consumer", topic = "tagFilterBoot", selectorExpression = "TagA || TagC")
public class TagFilterListener implements RocketMQListener<MessageExt> {
    @Override
    public void onMessage(MessageExt message) {
        System.out.println("收到的消息: " + new String(message.getBody(), Charset.defaultCharset()));
    }
}

7.2、SQL92过滤
7.2.1、在broker.conf配置添加如下配置, 开始SQL92过滤
enablePropertyFilter = true
7.2.2、生产者
package com.xiaoge;

import com.xiaoge.util.OrderStep;
import com.xiaoge.util.OrderUtil;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.sql.SQLOutput;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@SpringBootTest(classes = RocketMQApplication.class)
@RunWith(SpringRunner.class)
public class TestApplication {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;


    /**
     * 发送sql92消息过滤
     * todo sql过滤属性只能写在setHeader里面, message没有对应的put
     * @throws Exception
     */
    @Test
    public void sendSql92FilterMessage() throws Exception {
        Message msg1 = MessageBuilder.withPayload("美女A, 年龄22, 体重45")
                .setHeader("age", 22)
                .setHeader("weight", 45)
                .build();

        rocketMQTemplate.sendOneWay("SQL92FilterBoot", msg1);
        Message msg2 = MessageBuilder.withPayload("美女B, 年龄25, 体重60")
                .setHeader("age", 25)
                .setHeader("weight", 60)
                .build();
        rocketMQTemplate.sendOneWay("SQL92FilterBoot", msg2);
        Message msg3 = MessageBuilder.withPayload("美女C, 年龄40, 体重70")
                .setHeader("age", 40)
                .setHeader("weight", 70)
                .build();
        rocketMQTemplate.sendOneWay("SQL92FilterBoot", msg3);
    }
}

7.2.3、消费者
package com.xiaoge.listener;

import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.annotation.SelectorType;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;

/**
 * TODO
 *      接收消息SQL92过滤, selectorType = SelectorType.SQL92(使用SQL92的方式)   selectorExpression = "age > 23 and weight > 60" (写过滤规则)
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@Component
@RocketMQMessageListener(consumerGroup = "sql92-consumer", topic = "SQL92FilterBoot", selectorType = SelectorType.SQL92, selectorExpression = "age > 23 and weight > 60")
public class Sql92FilterListener implements RocketMQListener<MessageExt> {
    @Override
    public void onMessage(MessageExt message) {
        System.out.println("收到的消息: " + new String(message.getBody(), Charset.defaultCharset()));
    }
}

8、事务消息(案例是退款, 积分增加, 修改订单状态保持最终一致性)

8.1、生产者
package com.xiaoge.service.impl;

import com.xiaoge.domain.OperateIntergralVo;
import com.xiaoge.domain.OrderInfo;
import com.xiaoge.mapper.OrderInfoMapper;
import com.xiaoge.service.IOrderInfoService;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * TODO
 *
 * @author <a href="mailto:1330137071@qq.com">Zhang Xiao</a>
 * @since
 */
@Service
public class OrderInfoServiceImpl implements IOrderInfoService {
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Override
    public String refund(String orderNo) {
        System.out.println("发送消息");
        OrderInfo orderInfo = orderInfoMapper.select(orderNo);
        OperateIntergralVo vo = new OperateIntergralVo();
        vo.setUserId(orderInfo.getUserId());
        vo.setValue(orderInfo.getIntergral());
        // setHeader可以额外添加值
        Message<OperateIntergralVo> message = MessageBuilder.withPayload(vo).setHeader("orderNo",orderNo).build();
        //发送事务消息
        TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction("tx_group", "tx_topic", message, orderNo);
        System.out.println("发送的状态:"+result.getSendStatus());
        System.out.println("本地事务执行结果:"+ result.getLocalTransactionState());
        int i = 1/0;
        if(LocalTransactionState.COMMIT_MESSAGE.equals(result.getLocalTransactionState())){
            return "退款成功";
        }else{
            return "退款失败";
        }
    }

    @Override
    @Transactional
    public void updateRefundStatus(String orderNo) {
        orderInfoMapper.changeRefundStatus(orderNo,OrderInfo.STATUS_REFUND);
    }

    @Override
    public OrderInfo find(String orderNo) {
        return orderInfoMapper.select(orderNo);
    }
}

发送事务消息

// tx_group 事务生产者
// tx_topic 主题
// message 消息
// orderNo 本地事务方法参数(注意mq调用本地事务方法会带这个参数, 回查方法不会带, 如果回查方法业务要这个参数, 那就放在消息setHeader里面)
TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction("tx_group", "tx_topic", message, orderNo);
8.2、消费者

正常监听消费, 只有事务状态为commit的时候, 半消息才会变成全消息, 这时候消费者监听才能监听到消息, 事务状态为rollback把mq中的半消息删除, 但是, 这里要注意, 有可能我们消费了, 告诉mq我们消费了这条消息时, 网络断了, 这样mq就会没收到回复, 走重试消息, 这样消费者继续消费这个消息, 这样重复消费了, 所以一定要保证幂等性。

package com.xiaoge.mq;

import com.xiaoge.domain.OperateIntergralVo;
import com.xiaoge.service.IIntegralService;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


@Component
@RocketMQMessageListener(consumerGroup = "consumer-order",topic = "tx_topic")
public class OrderInfoListener implements RocketMQListener<OperateIntergralVo> {
    @Autowired
    private IIntegralService iIntegralService;
    @Override
    public void onMessage(OperateIntergralVo message) {
        System.out.println("12.消费消息");
        iIntegralService.incrIntergral(message);
    }
}

本地事务方法回查方法 类必须实现这个RocketMQLocalTransactionListener监听

package com.xiaoge.mq;

import com.xiaoge.domain.OperateIntergralVo;
import com.xiaoge.domain.OrderInfo;
import com.xiaoge.service.IOrderInfoService;
import com.alibaba.fastjson.JSON;
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;


@Component
@RocketMQTransactionListener(txProducerGroup = "tx_group")
public class OrderTransactionMessageListener implements RocketMQLocalTransactionListener {
    @Autowired
    private IOrderInfoService orderInfoService;
    //执行本地事务
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message message, Object o) {
        System.out.println("执行本地事务方法");
        byte[] contents = (byte[]) message.getPayload();
        String objStr = new String(contents, Charset.defaultCharset());
        OperateIntergralVo vo = JSON.parseObject(objStr,OperateIntergralVo.class);
        System.out.println(vo);
        String orderNo = (String) o;
        try{
            //本地业务逻辑
            orderInfoService.updateRefundStatus(orderNo);
            System.out.println("执行成功");
            // return RocketMQLocalTransactionState.UNKNOWN; 这里返回UNKNOWN, mq会调用回查方法
            return RocketMQLocalTransactionState.COMMIT; // 把mq中的半消息变成全消息, 这样consumer才能正常消费
        }catch(Exception e){
            e.printStackTrace();
            System.out.println("执行失败");
            // 删除mq中的半消息
            return RocketMQLocalTransactionState.ROLLBACK;
        }
    }
    //回查方法
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message message) {
        System.out.println("回查方法");
        String orderNo = (String) message.getHeaders().get("orderNo");
        OrderInfo orderInfo = orderInfoService.find(orderNo);
        if(OrderInfo.STATUS_REFUND.equals(orderInfo.getStatus())){
            //已经退款成功,说明本地事务执行成功
            return RocketMQLocalTransactionState.COMMIT;  // 把mq中的半消息变成全消息, 这样consumer才能正常消费
        }else{
            //说明本地事务执行失败.
            return RocketMQLocalTransactionState.ROLLBACK; // 删除mq中的半消息
        }
    }
}

在这里插入图片描述

在这里插入图片描述
事务消息demo下载地址: https://download.csdn.net/download/zsx1314lovezyf/88347191

9、RocketMQ消息走向

9.1、集群模式

多个消费组监听同一个topic, 每个消费组都会读取获取该topic中的消息, 如果对应的消费组做了集群, 那么消息是分开发送的, 如果又有新的消费组监听该topic由于它的offset为0, 但是由于以前有消费组它们的offset为3的话, 新的消费组也会直接拿到0-3的消息, offset会跟老的消费组同步

在这里插入图片描述

在这里插入图片描述

9.2、广播模式

广播模式的话没什么特别的, 都是一起发同样的消息, 不管消费组做没做集群

在这里插入图片描述
demo下载地址: https://download.csdn.net/download/zsx1314lovezyf/88282585

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只因为你温柔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值