RocketMQ普通消息安装和使用

一.安装

1.1 安装

官网地址:RocketMQ · 官方网站 | RocketMQ 下载直接解压

a) RocketMQ 是基于Java开发的,所以需要配置相应的jdk环境变量才能运行

b) RocketMQ也需要配置RocketMQ环境变量才可在windows上运行

1.2 基本概念简述

Producer

消息生产者,负责消息的产生,由业务系统负责产生

Consumer

消息消费者,负责消息消费,由后台业务系统负责异步消费

Topic

消息的逻辑管理单位(消息的一个属性,并且每个消息都一定有这个属性)

这三者是RocketMq中最最基本的概念。Producer是消息的生产者。Consumer是消息的消费者。

消息通过Topic进行传递。Topic存放的是消息的逻辑地址。

具体来说是Producer将消息发往具体的Topic。Consumer订阅Topic,主动拉取或被动接受消息,如果Consumer消费消息失败则默认会重试16次

二.启动

  1. 首先启动注册中心nameserver ,默认启动在9876端口,打开cmd命令窗口,进入bin目录,执行命令
start mqnamesrv.cmd  //windows
sh ./mqnamesrv  //Linux

出现下面日志表示启动成功

  1. 启动RocketMQ服务,进入bin目录,cmd执行命令
start mqbroker.cmd -n 127.0.0.1:9876 autoCreateTopicEnable=true //windows
sh ./mqbroker -n 127.0.0.1:9876 autoCreateTopicEnable=true //Linux

autoCreateTopicEnable=true这个设置表示开启自动创建topic功能,真实生产环境不建议开启。出现下面日志表示启动成功

如果写完代码之后运行抛出以下错误org.apache.rocketmq.client.exception.MQClientException: No route info of this topic, xxx那么表示你的rocketMQ中没有创建这个topic,表示开启autoCreateTopicEnable失效了,这个时候需要手动创建topic,还是进入bin目录,执行命令:

mqadmin updateTopic -n localhost:9876 -b localhost:10911 -t topicName //windows
sh ./mqadmin updateTopic -n localhost:9876 -b localhost:10911 -t topicName //linux

三.整合

3.1 导包

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

3.2 普通消息

  • 消息生产者
public static void main(String[] args){
    // 新增消息生产者
    DefaultMQProucer producer = new DefaultMQProucer("producer_group");
    // 配置注册中心
    producer.setNamesrvAddr("localhost:9876");
    // 启动
    producer.start();
    // 新建消息对象,指定主题topicA和message
    Message message = new Message("topicA","message".context.getBytes(Charset.forName("utf-8")));
    // 发送消息
    producer.send(message);
}
  • 消息消费者
public static void main(String[] args) throws MQClientException {
    DefaultMQPushConsumer mqConsumer = new DefaultMQPushConsumer("consumer_group");
    mqConsumer.setNamesrvAddr("localhost:9876");
    mqConsumer.subscribe("topicA", "*");
    // 设置消息监听器
    mqConsumer.registerMessageListener(new MessageListenerConcurrently() {
        @Override
        public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt>msgs, ConsumeConcurrentlyContext context) {
            MessageExt message = msgs.get(0);
            //获取消息内容
            byte[] body = message.getBody();
        });
    mqConsumer.start();

3.3 Demo

3.3.1 准备一个消息类,用来封装消息

FinancialMessage

@Data
public class FinancialMessage {
    private String mchId;                           // 商户ID  
    private BigDecimal orderAmount;                     // 订单金额
    private Long channelId;                       // 通道ID
    private BigDecimal mchServiceCharge;                // 商户服务费  
    private BigDecimal channelServiceCharge;            // 通道服务费  
    private String tradeNo;                         // 交易号  
    private String mchOrderSn;                      // 商户订单号  
    private String mchName;                         // 商户名称  
    private Date NotifyDate;                        // 通知日期
    private BigDecimal merchantBalance;                 // 商户账户余额  
    private String channelName;                     // 通道名称  
    private BigDecimal channelBalance;                  // 通道账户余额  
    private Integer supplementState;                 // 补单状态
}
3.3.2 controller层

封装两种消息,根据请求参数的不同调用service发送不同的消息

package com.example.demo.controller;

import com.example.demo.entity.FinancialMessage;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.Date;

@RestController
@RequestMapping("user")
public class UserController {
    @Autowired
    UserService userService;

    @GetMapping("/test")
    public String test(String str) {
        //准备消息(实际开发会从请求参数中获取)
        FinancialMessage financialMessage = new FinancialMessage();
        financialMessage.setChannelId(100L);
        financialMessage.setChannelName("测试");
        financialMessage.setMchId("测试");
        financialMessage.setMchName("测试");
        financialMessage.setOrderAmount(BigDecimal.valueOf(10000));
        financialMessage.setMchServiceCharge(BigDecimal.valueOf(10000));
        financialMessage.setTradeNo("2222222");
        financialMessage.setMchOrderSn("333333");
        financialMessage.setNotifyDate(new Date());
        financialMessage.setMerchantBalance(BigDecimal.valueOf(12312312));
        financialMessage.setSupplementState(3);
        financialMessage.setChannelBalance(BigDecimal.valueOf(54156454));
        financialMessage.setChannelServiceCharge(BigDecimal.valueOf(100000));

        boolean isSuccess = false;
        //根据请求的不同,模拟两种消息
        if ("1".equals(str)) {
            isSuccess = userService.test(financialMessage);

        } else if ("2".equals(str)) {
            financialMessage.setSupplementState(1);
            isSuccess = userService.test(financialMessage);
        }

        if (isSuccess) {
            return "消息消费成功了";
        }
        return "消息消费失败了";
    }
}
3.3.3 service层

注入消息生产者,调用发送消息方法

package com.example.demo.service.impl;


import com.example.demo.entity.FinancialMessage;
import com.example.demo.mq.BasicProducer;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserServiceImpl implements UserService {
    @Autowired
    BasicProducer producer; //注入消息生产者,还没实现

    @Override
    public boolean test(FinancialMessage financialMessage) {
        boolean isSuccess = producer.sendMessage(financialMessage);
        return isSuccess;
    }
}
3.3.4 producer

负责生产消息,并发送到MQ

package com.example.demo.mq;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.example.demo.entity.FinancialMessage;
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.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.nio.charset.Charset;

@Component
@Slf4j
public class BasicProducer {

    private DefaultMQProducer producer;

    @PostConstruct
    public void init(){
        //指定生产者组
        producer = new DefaultMQProducer("p-group"); 
        //指定注册中心
        producer.setNamesrvAddr("127.0.0.1:9876");
        try {
            producer.start();
        } catch (MQClientException e) {
            e.printStackTrace();
        }
    }
    public boolean sendMessage(FinancialMessage financialMessage) {
        //1.准备消息
        Message message = new Message();
        //1.1 设置主题topic
        message.setTopic("topic1");
        //1.2 设置消息body,将消息对象转换成jsonStr,再转换成byte
        JSON financialMsgJson = JSONUtil.parse(financialMessage);
        String jsonStr = JSONUtil.toJsonStr(financialMsgJson);
        byte[] msgBytes = jsonStr.getBytes(Charset.forName("utf-8"));
        message.setBody(msgBytes);
        //2.初始化结果集
        SendResult sendResult = null;
        Exception e = null;
        try {
            //3.发送消息
            sendResult = producer.send(message);
        } catch (MQClientException ex) {
            e=ex;
        } catch (RemotingException ex) {
            e=ex;
        } catch (MQBrokerException ex) {
            e=ex;
        } catch (InterruptedException ex) {
            e=ex;
        }
        if (e!=null){
            return false;
        }
        //结果集不为空,并且SendStatus为SEND_OK,返回成功,否则返回失败
        if (sendResult != null && SendStatus.SEND_OK.equals(sendResult.getSendStatus())){
            return true;
        }
        return false;
    }
}
3.3.5 consumer

负责消费消息,拿到消息后进行处理

package com.example.demo.mq;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.example.demo.entity.FinancialMessage;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
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.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.util.List;

@Component
@Slf4j
public class BasicConsumer {
    private DefaultMQPushConsumer consumer;

    @PostConstruct
    public void init(){
        //1.指定消费者组
        consumer = new DefaultMQPushConsumer("c-group");
        //2.指定nameserver
        consumer.setNamesrvAddr("127.0.0.1:9876");
        //3.获取消息监听器
        consumer.setMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
                //3.1 拿到消息对象,获取消息
                MessageExt messageExt = list.get(0);
                byte[] body = messageExt.getBody();
                try {
                    //3.2 解析消息,将jsonstr映射到目标消息对象
                    String financialMsgJson = new String(body, 0, body.length, "utf-8");
                    JSONObject jsonObject = JSONUtil.parseObj(financialMsgJson);
                    FinancialMessage financialMessage = JSONUtil.toBean(jsonObject, FinancialMessage.class);

                    //3.3 通过拿到的消息实现1个简单的方法
                    test(financialMessage);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    //消息消费失败,默认重试16次
                    return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                }
                //消息消费成功
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }

            private void test(FinancialMessage financialMessage) {
                System.out.println("-----------测试方法-----------"+ financialMessage.getSupplementState());
                System.out.println(financialMessage);
            }

        });

        try {
            //4.订阅主题
            consumer.subscribe("topic1","*");
            //5.启动
            consumer.start();
        } catch (MQClientException e) {
            e.printStackTrace();
        }
    }
}
3.3.6 application.yml
server:
  port: 7101
spring:
  application:
    name: test-mq
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.2.11:3306/ry-config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
    username: root
    password: root123
3.3.7 result

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值