03,springboot整合RocketMQ

1,maven和配置文件

<dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>

        <dependency>
            <groupId>org.apache.rocketmqgroupId>
            <artifactId>rocketmq-spring-boot-starterartifactId>
            <version>2.0.2version>
        dependency>

        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-apiartifactId>
            <version>1.7.25version>
        dependency>

        <dependency>
            <groupId>org.apache.rocketmqgroupId>
            <artifactId>rocketmq-spring-boot-starterartifactId>
            <version>2.2.1version>
        dependency>

    dependencies>
spring:
  application:
    name: rocketmq-boot
server:
  port: 8083

# rocketmq配置
rocketmq:
  name-server: http://127.1.1.1:9876
  #自定义的组名称
  producer:
    group: producer_test
    #消息发送超时时长
    send-message-timeout: 5000



2,基础应用

2.1,创建生产者

package com.study.producer;

import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class Demo01_TestProducer {
    private static final Logger log = LoggerFactory.getLogger(Demo01_TestProducer.class);

    @Resource
    RocketMQTemplate rocketmqTemplate;

    public void send() {
        log.info("开始发送...");
        for (int i=1; i <= 20;i++){
            String text = "测试发送" + i;
            Message<String> message = MessageBuilder.withPayload(text).build();
            rocketmqTemplate.send("TEST_MESSAGE", message);
        }
        log.info("已发送...");
    }
}

2.2,创建消费者

package com.study.consumer;

import com.study.producer.Demo01_TestProducer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@RocketMQMessageListener(topic = "TEST_MESSAGE", consumerGroup = "test_group")
public class Demo01_TestConsumer implements RocketMQListener<String> {
    private static final Logger log = LoggerFactory.getLogger(Demo01_TestConsumer.class);

    @Override
    public void onMessage(String message) {
        log.info("TestConsumer - 接受到消息:" + message);
    }
}

2.3 调用接口

@GetMapping("sendDemo01TestPro")
    private void sendDemo01TestPro(){
        testProducer.send();
    }

2.4 测试

03,springboot整合RocketMQ_第1张图片

3,基本消息

  • 同步消息:这种可靠性同步地发送方式使用的比较广泛,比如:重要的消息通知,短信通知。
  • 异步消息:用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。
  • 单向发送消息:这种方式主要用在不关心发送结果的场景,例如日志发送。

3.1,创建生产者

package com.study.producer;

import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 基本消息样例
 * 1,同步消息:这种可靠性同步地发送方式使用的比较广泛,比如:重要的消息通知,短信通知。
 * 2,异步消息:用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。
 * 3,单向发送消息:这种方式主要用在不关心发送结果的场景,例如日志发送。
 */
@Service
public class Demo02_BasicsProducer {
    @Resource
    RocketMQTemplate rocketMQTemplate;

    private static final Logger log = LoggerFactory.getLogger(Demo02_BasicsProducer.class);

    /**
     * 同步消息: 这种可靠性同步地发送方式使用的比较广泛,比如:重要的消息通知,短信通知。
     */
    public void sync() {
        String text = "基本信息案例-同步发送" + System.currentTimeMillis();
        log.info(text);
        for (int a = 1; a <= 10; a++) {
            rocketMQTemplate.syncSend("SYNC_TOPIC", text+"----"+a);
        }
        log.info("同步发送-已发送...");
    }

    /**
     * 异步消息:异步消息通常用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。
     */
    public void async() {
        String text = "基本信息案例-异步发送" + System.currentTimeMillis();
        log.info(text);
        for (int a = 1; a <= 10; a++) {
            rocketMQTemplate.asyncSend("ASYNC_TOPIC", text + ",ID:" + a, new SendCallback() {

                // SendCallback接收异步返回结果的回调
                // 成功发送
                @Override
                public void onSuccess(SendResult sendResult) {
                    log.info("异步发送 - 发送成功");
                }

                // 发送失败
                @Override
                public void onException(Throwable throwable) {
                    log.info("异步发送 - 发送失败");
                    throwable.printStackTrace();
                }
            });
        }
        log.info("异步发送-已发送...");
    }

    /**
     * 单向发送消息:这种方式主要用在不特别关心发送结果的场景,例如日志发送。
     */
    public void oneWay() {
        String text = "基本信息案例-单向发送" + System.currentTimeMillis();
        log.info(text);
        for (int a = 1; a <= 10; a++) {
            rocketMQTemplate.sendOneWay("ONEWAY_TOPIC", text+"----"+a);
        }
        rocketMQTemplate.sendOneWay("ONEWAY_TOPIC", text);
        log.info("单向发送-已发送...");
    }
}

3.1,创建消费者

3.1.1 异步消息消费者

package com.study.consumer;

import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 异步消息
 */
@Component
@RocketMQMessageListener(selectorExpression = "", topic = "ASYNC_TOPIC", consumerGroup = "async_group")
public class Demo02_Basics_Async_Consumer implements RocketMQListener<String> {
    private static final Logger log = LoggerFactory.getLogger(Demo02_Basics_Async_Consumer.class);

    /**
     *
     * @param message
     */
    @Override
    public void onMessage(String message) {
        log.info("异步消息-接受到消息:" + message);
    }
}

3.1.2 单向发送消息消费者

package com.study.consumer;

import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 单向发送消息
 */
@Component
@RocketMQMessageListener(selectorExpression = "", topic = "ONEWAY_TOPIC", consumerGroup = "oneway_group")
public class Demo02_Basics_Oneway_Consumer implements RocketMQListener<String> {
    private static final Logger log = LoggerFactory.getLogger(Demo02_Basics_Oneway_Consumer.class);

    /**
     *
     * @param message
     */
    @Override
    public void onMessage(String message) {
        log.info("单向发送消息-接受到消息:" + message);
    }
}

3.1.3 同步消息消费者

package com.study.consumer;

import com.study.producer.Demo02_BasicsProducer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 同步消息
 */
@Component
@RocketMQMessageListener(selectorExpression = "", topic = "SYNC_TOPIC", consumerGroup = "sync_group")
public class Demo02_Basics_Sync_Consumer implements RocketMQListener<String> {
    private static final Logger log = LoggerFactory.getLogger(Demo02_Basics_Sync_Consumer.class);

    /**
     *
     * @param message
     */
    @Override
    public void onMessage(String message) {
        log.info("同步消息-接受到消息:" + message);
    }
}

3.3 调用接口

/**
     * 异步消息
     */
    @GetMapping("sendAsync")
    private String sendAsync(){
        demo02_basicsProducer.async();
        return"异步发送 - 发送成功";
    }

    /**
     * 单向发送消息
     */
    @GetMapping("sendOneway")
    private String sendOneway(){
        demo02_basicsProducer.oneWay();
        return"单向发送消息 - 发送成功";
    }

    /**
     * 同步消息
     */
    @GetMapping("sendSync")
    private String sendSync(){
        demo02_basicsProducer.sync();
        return"同步消息 - 发送成功";
    }

3.4 测试

3.4.1 测试异步消息

http://localhost:8083/sendAsync
03,springboot整合RocketMQ_第2张图片
03,springboot整合RocketMQ_第3张图片

3.4.2 测试单项发送消息

http://localhost:8083/sendOneway
03,springboot整合RocketMQ_第4张图片
03,springboot整合RocketMQ_第5张图片

3.4.3 测试同步消息

http://localhost:8083/sendSync
03,springboot整合RocketMQ_第6张图片
03,springboot整合RocketMQ_第7张图片

4,顺序消息

消息有序指的是可以按照消息的发送顺序来消费(FIFO),rocketmq可以严格的保证消息有序

4.1 创建生产者

package com.study.producer;

import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

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

/**
 * 顺序消息
 */
@Service
public class Demo03_OrderProducer {
    @Resource
    RocketMQTemplate rocketMQTemplate;

    private static final Logger log = LoggerFactory.getLogger(Demo03_OrderProducer.class);

    public void order() {
        log.info("顺序消息");
        try {
            for (int i = 1; i <= 10; i++) {
                int num = (int) (Math.random() * 10000);
                // 设置一个延时,表示同一个消息先后进入到队形中
                TimeUnit.MILLISECONDS.sleep(50);
                log.info("顺序消息,ID:" + num);
                // 第一个参数为topic,第二个参数为内容,第三个参数为Hash值,不同hash值在不同的队列中
                rocketMQTemplate.syncSendOrderly("ORDER_TOPIC", "顺序消息,ID:" + num, "order");
            }
            log.info("已发送...");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.2 创建消费者

package com.study.consumer;

import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@RocketMQMessageListener(topic = "ORDER_TOPIC", consumerGroup = "ORDER_TOPIC", consumeMode = ConsumeMode.ORDERLY)
public class Demo03_OrderConsumer implements RocketMQListener<String> {
    private static final Logger log = LoggerFactory.getLogger(Demo03_OrderConsumer.class);
    @Override
    public void onMessage(String message) {
        log.info("顺序消息生产-接受到消息:" + message);
    }


}

4.3 调用接口

@GetMapping("/sendOrder")
    public Object order() {
        demo03_orderProducer.order();
        return "发送顺序消息";
    }

4.4 测试

03,springboot整合RocketMQ_第8张图片

5,延时消息

通过设置延时等级,实现消费者延时消费数据,比如电商里,提交了一个订单就可以发送一个延时消息,1h后去检查这个订单的状态,如果还是未付款就取消订单释放库存。

5.1 创建生产者

package com.study.producer;

import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class Demo04_ScheduledProducer {
    private static final Logger log = LoggerFactory.getLogger(Demo04_ScheduledProducer.class);

    /**
     * 测试发送将参数topic定死,实际开发写入到配置文件
     */
    @Resource
    RocketMQTemplate rocketMQTemplate;

    public void scheduled() {
        String text = "延时消息"+ System.currentTimeMillis();
        log.info(text);

        // 设置延时等级2,这个消息将在5s之后发送
        // 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
        Message<String> message = MessageBuilder.withPayload(text).build();
        rocketMQTemplate.syncSend("SCHEDULED_TOPIC", message, 1000, 4);

        log.info("已发送...");
    }

}

5.2 创建消费者

package com.study.consumer;

import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@RocketMQMessageListener(topic = "SCHEDULED_TOPIC", consumerGroup = "SCHEDULED_TOPIC")
public class Demo04_ScheduledConsumer  implements RocketMQListener<String> {
    private static final Logger log = LoggerFactory.getLogger(Demo04_ScheduledConsumer.class);

    /**
     * 测试接收将参数topic定死,实际开发写入到配置文件
     * @param message
     */
    @Override
    public void onMessage(String message) {
        log.info("延时消息-接受到消息:" + message);
    }
}

5.3 调用接口

 /**
     * 延时消息
     * @return
     */
    @GetMapping("/sendScheduled")
    public Object scheduled() {
        scheduledProducer.scheduled();
        return "发送延时消息";
    }

5.4 测试

http://localhost:8083/sendScheduled
03,springboot整合RocketMQ_第9张图片
在这里插入图片描述

6,标签过滤消息

一个应用尽可能用一个Topic,消息子类型用tag来标识,tag可以由应用自由设置。 在使用rocketmqTemplate发送消息时,通过设置发送方法的destination参数来设置消息的目的地,destination的格式为topicName:tagName,:前面表示topic的名称,后面表示tag名称。

6.1 创建生产者

package com.study.producer;

import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class Demo05_TagProducer {
    private static final Logger log = LoggerFactory.getLogger(Demo05_TagProducer.class);

    @Resource
    RocketMQTemplate rocketMQTemplate;

    public void tag() {
        String text = "标签过滤消息," + System.currentTimeMillis();
        log.info(text);
        for (int i = 1; i <= 10; i++) {
            // 任何类型的send方法均可以指定TAG,默认可以不指定则为*
            Message<String> message = MessageBuilder.withPayload(text+"-----"+i).build();
            rocketMQTemplate.syncSend("TAG_TOPIC:TAG-A", message);
        }
        log.info("已发送...");
    }
}

6.2 创建消费者

package com.study.consumer;

import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@RocketMQMessageListener(selectorExpression = "TAG-A||TAG-B", topic = "TAG_TOPIC", consumerGroup = "TAG_TOPIC")
public class Demo05_TagConsumer implements RocketMQListener<String> {
    private static final Logger log = LoggerFactory.getLogger(Demo05_TagConsumer.class);

    /**
     *
     * @param message
     */
    @Override
    public void onMessage(String message) {
        log.info("标签过滤消息-接受到消息:" + message);
    }

}

6.3 调用接口

@GetMapping("/sendTag")
    public Object tag() {
        // TAG过滤
        tag.tag();
        return "指定标签消息";
    }

6.4 测试

http://localhost:8083/sendTag
03,springboot整合RocketMQ_第10张图片

7,批量消息

生产者进行消息发送时可以一次发送多条消息,这可以大大提升Producer的发送效率。

  • 批量发送的消息必须具有相同的Topic。
  • 批量发送的消息必须具有相同的刷盘策略。
  • 批量发送的消息不能是延时消息与事务消息。
  • 消息的总大小不应超过4MB。

默认情况下,一批发送的消息总大小不能超过4MB字节,如果想超出该值,有两种解决

  • 方案一:将批量消息进行拆分,拆分为若干不大于4M的消息集合分多次批量发送,一般不大于1M。
  • 方案二:在Producer端与Broker端修改属性。
    Producer端需要在发送之前设置Producer的maxMessageSize属性
    Broker端需要修改其加载的配置文件中的maxMessageSize属性

7.1 创建工具类

package com.study.splitter;

import org.springframework.messaging.Message;

import java.util.Iterator;
import java.util.List;

public class MessageSplitter implements Iterator<List<Message>> {
    /**
     * 分割数据大小
     */
    private final int sizeLimit = 1024 * 1024;
    ;

    /**
     * 分割数据列表
     */
    private final List<Message> messages;

    /**
     * 分割索引
     */
    private int currIndex;

    public MessageSplitter(List<Message> messages) {
        this.messages = messages;
        // 保证单条数据的大小不大于sizeLimit
        messages.forEach(m -> {
            if (m.toString().length() > sizeLimit) {
                throw new RuntimeException("单挑消息不能大于" + sizeLimit + "B");
            }
        });
    }


    @Override
    public boolean hasNext() {
        return currIndex < messages.size();
    }

    @Override
    public List<Message> next() {
        int nextIndex = currIndex;
        int totalSize = 0;
        for (; nextIndex < messages.size(); nextIndex++) {
            Message t = messages.get(nextIndex);
            totalSize = totalSize + t.toString().length();
            if (totalSize > sizeLimit) {
                break;
            }
        }
        List<Message> subList = messages.subList(currIndex, nextIndex);
        currIndex = nextIndex;
        return subList;
    }
}

7.2 创建生产者

package com.study.producer;

import com.study.splitter.MessageSplitter;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Service
public class Demo06_BatchProducer {
    private static final Logger log = LoggerFactory.getLogger(Demo06_BatchProducer.class);

    /**
     * 测试发送将参数topic定死,实际开发写入到配置文件
     */
    @Resource
    RocketMQTemplate rocketMQTemplate;

    public void batch() {
        String text = "批量消息";
        log.info(text);

        List<Message> messageList = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            messageList.add(MessageBuilder.withPayload(text + "--" + i).build());
        }
        log.info("开始发送...");

        //把大的消息分裂成若干个小的消息
        MessageSplitter splitter = new MessageSplitter(messageList);

        while (splitter.hasNext()) {
            List<Message> nextList = splitter.next();
            SendResult result = rocketMQTemplate.syncSend("BATCH_TOPIC", nextList);
            if (result.getSendStatus() == SendStatus.SEND_OK) {
                log.info("发送批量消息成功!消息ID为:{}", result.getMsgId());
            } else {
                log.info("发送批量消息失败!消息ID为:{},消息状态为:{}", result.getMsgId(), result.getSendStatus());
            }
        }
        log.info("已发送...");
    }
}

7.3 创建消费者

package com.study.consumer;

import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@RocketMQMessageListener(topic = "BATCH_TOPIC", consumerGroup = "BATCH_TOPIC")
public class Demo06_BatchComsumer  implements RocketMQListener<String> {
    private static final Logger log = LoggerFactory.getLogger(Demo06_BatchComsumer.class);

    /**
     *
     * @param message
     */
    @Override
    public void onMessage(String message) {
        log.info("批量消息-接受到消息:" + message);
    }

}

7.4 调用接口

@GetMapping("/sendBatch")
    public Object batch() {
        // 批量消息样例
        batchProducer.batch();
        return "批量消息样例";
    }

7.5 测试

http://localhost:8083/sendBatch
03,springboot整合RocketMQ_第11张图片

8,回馈消息

生产者通过sendAndReceive发送消息,消费者需要实现rocketmqReplyListener接口

如果连续通过sendAndReceive发送消息,生产者必须收到消费者的回复才能发送下一条消息。

8.1 创建生产者

package com.study.producer;

import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class Demo07_ReplyProducer {
    private static final Logger log = LoggerFactory.getLogger(Demo07_ReplyProducer.class);

    @Resource
    RocketMQTemplate rocketMQTemplate;

    public void reply() {

        // 如果消费者没有回馈消息,则不会发送下一条消息
        for (int i = 1; i <= 10; i++) {
            String text = "回馈消息" + "--" + i;
            log.info("发送" + text);
            Object obj = rocketMQTemplate.sendAndReceive("REPLY_TOPIC", text, String.class);
            log.info("消费者返回的消息:" + obj);
        }
    }
}

8.2 创建消费者

package com.study.consumer;

import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQReplyListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@RocketMQMessageListener(topic = "REPLY_TOPIC", consumerGroup = "REPLY_TOPIC")
public class Demo07_ReplyConsumer implements RocketMQReplyListener<String, byte[]> {
    private static final Logger log = LoggerFactory.getLogger(Demo07_ReplyConsumer.class);

    @Override
    public byte[] onMessage(String message) {
        log.info("接受到消息:" + message);
        // 返回消息到生成者
        return ("返回消息到生产者").getBytes();
    }
}

8.3 调用接口

 @GetMapping("/sendReply")
    public Object reply() {
        // 消息事务
        replyProducer.reply();
        return "回馈消息样例";
    }

8.4 测试

http://localhost:8083/sendReply
03,springboot整合RocketMQ_第12张图片

你可能感兴趣的:(RocKetMQ,spring,boot,java-rocketmq,rocketmq)