CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)

文章目录

  • 一.环境搭建
    • 1-安装包和插件准备
      • 1.1在本地新建空文件夹存放rpm安装包
      • 1.2下载RabbitMQ
      • 1.3下载RabbitMQ的延迟插件
      • 1.4下载ErLang
    • 2-上传安装包和插件到服务器
      • 2.1上传准备
      • 2.2上传本地文件到服务器
      • 2.3注意事项
    • 3-安装
      • 3.1使用win10自带ssh连接服务器
      • 3.2正式搭建
  • 二.代码实现一个简单的订单超时自动取消功能
    • 1-代码编辑

笔者在安装RabbitMQ时发现大部分博客记录的安装复杂且版本固定且过时,或复制粘贴缺胳膊少腿;故写下此博客,希望有需要的同学可以少走些弯路。
笔者设备: win10+Linux CentOS7。
笔者RabbitMQ版本3.8.16,Java版本11,Spring Boot版本2.4.5。
使用win10系统去连接服务器不需要安装其它任何软件。
服务器安装使用root用户,使用rpm包。
本文宗旨操作简单化,描述详细化 。
项目源码:https://github.com/MuweiLaw/RabbitMQ.git
项目源码分为两个服务,一个生产者一个消费者,适用于分布式架构。

一.环境搭建

1-安装包和插件准备

1.1在本地新建空文件夹存放rpm安装包

在PC上新建一个文件夹用来存放安装包
例如我在E盘上新建一个空文件夹,路径为E:\upload
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第1张图片

1.2下载RabbitMQ

进入 RabbitMQ下载地址,下载RabbitMQ的包。
笔者的Linux版本均为CentOS7,故下载图中蓝框版本
蓝色框上方为CentOS8版本
linux7需要下载的图片截图
点击下载放入到我们刚才建好的文件夹中

1.3下载RabbitMQ的延迟插件

进入延迟插件下载地址,在页面使用Ctrl+F直接搜索rabbitmq_delayed_message_exchange即可找到我们需要下载的插件
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第2张图片
下载和RabbitMQ配套的版本
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第3张图片

1.4下载ErLang

RabbitMQ是基于Erlang语言开发,so在安装RabbitMQ之前,需要先安装Erlang,这里使用RabbitM
Q团队提供的Erlang依赖包。
进入Erlang下载页
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第4张图片
点击下载放入到我们刚才建好的文件夹中

2-上传安装包和插件到服务器

2.1上传准备

此时我们已经下载好了3个包并放在了E:\upload文件夹下
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第5张图片

2.2上传本地文件到服务器

回到电脑桌面
使用快捷键win+R
在弹出的窗口输入cmd
回车后打开windows运行命令行窗口,笔者的字体颜色是绿色(人生在世总要带点绿哈哈哈),大部分同学的字体颜色是白色CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第6张图片
输入命令sftp user@host建立sftp连接,user是你的Linux账户名,host是你的Linux系统对外的IP地址。注意,密码不会显示,带有小键盘的同学尽量不要用小键盘。输入密码后回车显示
Connected to user@host.
则表示连接成功。如下:
在这里插入图片描述
连接成功后输入命令lcd E:\upload
再输入命令lls
就能看到我们之前放在 E:\upload 里的三个文件
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第7张图片
好了,现在我们开始本地上传这三个文件,put 加上对应的文件名称
put erlang-23.3.2-1.el7.x86_64.rpm
put rabbitmq_delayed_message_exchange-3.8.0.ez
put rabbitmq-server-3.8.16-1.el7.noarch.rpm
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第8张图片
再接着,我们把这三个文件保存到服务器,get 加上对应的文件名称
get erlang-23.3.2-1.el7.x86_64.rpm
get rabbitmq_delayed_message_exchange-3.8.0.ez
get rabbitmq-server-3.8.16-1.el7.noarch.rpm
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第9张图片
我们使用命令ls查看服务器是否保存这三个文件
使用命令pwd知道服务器当前保存的文件夹为 /root
如下:查看服务器保存文件
最后,我们使用Ctrl+C关闭sftp连接

2.3注意事项

IP查看方式:
1.虚拟机: 使用ifconfig命令
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第10张图片
2.云服务器:在云服务器控制台上找到服务器的公网IP,笔者是一台最低配阿里云ECS服务器,年费用不超过100软妹币,满足日常学习开发使用,其它高配云服务器享受同等折扣,链接戳我直达

CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第11张图片

第一次使用sftp传输文件回有如下提示
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第12张图片

3-安装

3.1使用win10自带ssh连接服务器

使用Xshell,PuTTY,CRT等ssh工具的可以跳过这一步

打开windows运行命令行
输入ssh user@host这里user依旧是你的Linux账户名,host依旧是你的Linux系统对外的IP地址。密码不显示,输入密码时尽量不要使用小键盘。
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第13张图片图示我们已经通过ssh用root账号连接上了我们的服务器,接下来我们将正式在服务器搭建环境

3.2正式搭建

登录到服务器成功之后
使用 ls 即可查看我们之前通过sftp传输的三个文件。CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第14张图片

依次执行如下命令:

rpm -ivh erlang-23.3.2-1.el7.x86_64.rpm 安装erlang依赖
安装erlang依赖
yum -y install socat 安装socat
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第15张图片
rpm -ivh rabbitmq-server-3.8.16-1.el7.noarch.rpm 安装RabbitMQ 安装RabbitMQ

接下来我们启动RabbitMQ

使用命令 systemctl start rabbitmq-server 稍等几秒钟,正常启动如下,没有任何提示启动
systemctl enable rabbitmq-server 设置RabbitMQ开机自启
rabbitmq-plugins enable rabbitmq_management 启用web控制台
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第16张图片

开放端口(防火墙已关闭的同学可以跳过这一小步)

firewall-cmd --zone=public --add-port=5672/tcp --permanent 开放客户端端口
firewall-cmd --zone=public --add-port=15672/tcp --permanent 开放web控制台端口
firewall-cmd --reload 重启防火墙
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第17张图片
需要注意一点的是,使用阿里云服务器的同学还需要配置安全组云服务器配置安全组

尝试登录web控制台

RabbitMQ默认的账号用户名和密码都是guest
在浏览器输入 http://host:15672/ 即可访问web控制台,这里的 host 依旧是你的服务器对外IP。
例如笔者的web控制台的Url为 http://10.1.2.4:15672/
默认情况下,RabbitMQ的默认的guest用户只允许本机访问,当我们在web控制台输入账号密码后会发现如下图所示CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第18张图片

所以我们还需要让guest用户能够远程访问

cd /etc/rabbitmq 进入到 etc/rabbitmq 目录下
touch rabbitmq.config 创建名为 rabbitmq.config 的配置文件
创建配置文件
vi rabbitmq.config 编辑配置文件编辑配置文件
按下回车键之后效果如下:注意红框内描述变化CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第19张图片
此时我们按下键盘 “ i ” 键,进行编辑,注意左下角变化,表示已进入编辑状态
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第20张图片
输入 [{rabbit, [{loopback_users, []}]}].
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第21张图片
再按下键盘“ Esc ”键退出编辑模式CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第22张图片键盘依次按下 :wq
再按下回车键后保存并退出,注意此处冒号是英文冒号
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第23张图片
systemctl restart rabbitmq-server重启RabbitMQ,等待数秒
重启

再次访问web控制台

重新输入guest账号密码即可实现登录CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第24张图片

安装延迟插件

cd /usr/lib/rabbitmq/lib 先进入lib目录,
再使用 ls 查看RabbitMQ安装目录名称,因为版本因素,各位同学此处的目录名称可能也存在不同
查看文件夹
好了,知道黄色框内该版本的安装目录名称之后
cd rabbitmq_server-3.8.16/plugins 我们直接进入插件库文件夹内
ls 查看,后缀 .ez 的文件都是RabbitMQ自带的插件CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第25张图片
cp /root/rabbitmq_delayed_message_exchange-3.8.0.ez ./ 我们将先前保存在 /root 目录下的延迟插件 rabbitmq_delayed_message_exchange-3.8.0.ez 拷贝到当前目录。
ls 可以查看到,我们的延迟插件已经拷贝到当前文件夹了
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第26张图片

现在我们要启用插件了

cd …/sbin 进入sbin目录(注意注意注意!!CSDN的bug,导致此处命令高亮区域显示了三个“ . ”,下图是两个“ . ”,直接复制粘贴时注意)
rabbitmq-plugins enable rabbitmq_delayed_message_exchange 启用插件成功后就可以看到如下信息CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第27张图片
再进入到我们的web控制台,哎哟新增了一个交换机类型可选项 x-delayed-messageCentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第28张图片

环境搭建大功告成!!!

二.代码实现一个简单的订单超时自动取消功能

项目源码:https://github.com/MuweiLaw/RabbitMQ.git

1-代码编辑

笔者用的IDE是intellij IDEA,新建两个Spring Initializr项目
项目1:mq_producer
项目2:mq_consumer

两个项目的结构类似,如下:
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第29张图片

首先我们需要在两个项目中的pom.xml文件中都添加这3个依赖;

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

之后在application.properties添加RabbitMQ的相关配置;

mq_producer:

server.port=52320

spring.application.name=Spring-boot-rabbitmq
spring.rabbitmq.host=10.1.2.4
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#开启confirm 确认机制,如果对异步消息需要回调必须设置为correlated
#spring.rabbitmq.publisher-confirms=true   已过时,下行替代
spring.rabbitmq.publisher-confirm-type=correlated

mq_consumer:

server.port=52321

spring.rabbitmq.host=10.1.2.4
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.publisher-confirm-type=correlated

接下来创建RabbitMQ的Java配置,主要用于配置交换机、队列和绑定关系,两个项目的配置相同,如下。
枚举类

/**
 * 消息队列枚举配置
 *
 * @author Murray
 * @date 2021/5/6 14:30
 */
public enum QueueEnum {
     
    /**
     * 插件实现延迟队列
     */
    QUEUE_ORDER_PLUGIN_CANCEL("mall.order.direct.plugin", "mall.order.cancel.plugin", "mall.order.cancel.plugin");

    /**
     * 交换名称
     */
    private String exchange;
    /**
     * 队列名称
     */
    private String name;
    /**
     * 路由键
     */
    private String routeKey;

    QueueEnum(String exchange, String name, String routeKey) {
     
        this.exchange = exchange;
        this.name = name;
        this.routeKey = routeKey;
    }

    public String getExchange() {
     
        return exchange;
    }

    public String getName() {
     
        return name;
    }

    public String getRouteKey() {
     
        return routeKey;
    }
}

RabbitMQ配置类

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.CustomExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * RabbitMQ配置类
 *
 * @author Murray
 * @date 2021/5/6 14:24
 */
@Configuration
public class RabbitConfig {
     

    /**
     * 订单延迟插件消息队列所绑定的交换机
     */
    @Bean
    CustomExchange orderPluginDirect() {
     
        //创建一个自定义交换机,可以发送延迟消息
        Map<String, Object> args = new HashMap<>();
        args.put("x-delayed-type", "direct");
        return new CustomExchange(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getExchange(), "x-delayed-message", true, false, args);
    }

    /**
     * 订单延迟插件队列
     */
    @Bean
    public Queue orderPluginQueue() {
     
        return new Queue(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getName());
    }

    /**
     * 将订单延迟插件队列绑定到交换机
     */
    @Bean
    public Binding orderPluginBinding(CustomExchange orderPluginDirect, Queue orderPluginQueue) {
     
        return BindingBuilder
                .bind(orderPluginQueue)
                .to(orderPluginDirect)
                .with(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getRouteKey())
                .noargs();
    }
 	/**
     * 将默认的消息转换器替换成json消息转换器
     */
    @Bean
    public MessageConverter jsonMessageConverter() {
     
        return new Jackson2JsonMessageConverter();
    }
}

两个项目都需要订单实体类,且包名也得一样

import java.io.Serializable;
import java.util.UUID;

/**
 * 订单实体类
 *
 * @author Murray Law
 * @date 2021/5/8 14:30
 */
public class Order implements Serializable {
     
    private static final long serialVersionUID = -8432910728496351007L;
    String orderNumber;
    String userName;
    Integer age;
    String remark;

    public Order() {
     
    }

    public Order(String userName, Integer age, String remark) {
     
        this.orderNumber = UUID.randomUUID().toString().trim().replaceAll("-", "");
        this.userName = userName;
        this.age = age;
        this.remark = remark;
    }

    public String getOrderNumber() {
     
        return orderNumber;
    }

    public void setOrderNumber(String orderNumber) {
     
        this.orderNumber = orderNumber;
    }

    public String getUserName() {
     
        return userName;
    }

    public void setUserName(String userName) {
     
        this.userName = userName;
    }

    public Integer getAge() {
     
        return age;
    }

    public void setAge(Integer age) {
     
        this.age = age;
    }

    public String getRemark() {
     
        return remark;
    }

    public void setRemark(String remark) {
     
        this.remark = remark;
    }

    @Override
    public String toString() {
     
        return "Order{" +
                "orderNumber='" + orderNumber + '\'' +
                ", userName='" + userName + '\'' +
                ", age=" + age +
                ", remark='" + remark + '\'' +
                '}';
    }
}

mq_producer 里创建一个 延时消息队列发出者,通过给消息设置x-delay头来设置消息从交换机发送到队列的延迟时间

import com.murray.mq.producer.config.QueueEnum;
import com.murray.mq.commons.entity.Order;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 订单自动取消的消息发出者
 *
 * @author Murray Law
 * @date  2021/5/6 13:24
 */
@Component
public class CancelOrderSender {
     
    private static Logger LOGGER = LoggerFactory.getLogger(CancelOrderSender.class);
    @Autowired
    private AmqpTemplate amqpTemplate;

    public void sendMessage(Order order, final long delayTimes) {
     
        //给延迟队列发送消息
        amqpTemplate.convertAndSend(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getExchange(), QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getRouteKey(), order, message -> {
     
            //给消息设置延迟毫秒值
            message.getMessageProperties().setHeader("x-delay", delayTimes);
            return message;
        });
        LOGGER.info("发送出了一个延时取消订单{}", order);
    }
}

mq_producer 里还需要一个订单服务,在订单生成之后调用延时消息发出者的方法

import com.murray.mq.commons.entity.Order;
import com.murray.mq.producer.sender.CancelOrderSender;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 前台订单管理Service
 *
 * @author Murray Law
 * @date 2021/5/6 13:26
 */

@Service
public class OrderService {
     

    @Autowired
    private CancelOrderSender cancelOrderSender;

    public void generateOrder(Order order) {
     
        //TODO 实际项目中会执行一系类下单操作
        //下单完成后开启一个延迟消息,用于当用户没有付款时取消订单
        sendDelayMessageCancelOrder(order);
    }

    private void sendDelayMessageCancelOrder(Order order) {
     
        //获取订单超时时间,假设为60分钟(测试用的10秒)
        long delayTimes = 10 * 1000;
        //发送延迟消息
        cancelOrderSender.sendMessage(order, delayTimes);
    }
}

既然我们有了消息发出者和订单发出服务,那我们就需要在 mq_consumer 里创建一个延时消息接收者用于处理订单延迟队列中的消息,还有收到订单被取消消息后的订单取消服务

import com.murray.mq.commons.entity.Order;
import com.murray.mq.consumer.service.CancelOrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 订单自动取消的消息接受者
 *
 * @author Murray Law
 * @date 2021/5/6 13:23
 */
@Component
@RabbitListener(queues = "mall.order.cancel.plugin")
public class CancelOrderReceiver {
     
    private static Logger LOGGER = LoggerFactory.getLogger(CancelOrderReceiver.class);
    @Autowired
    private CancelOrderService portalOrderService;

    @RabbitHandler
    public void handle(Order order) {
     
        LOGGER.info("接受到一个订单因超时未支付{}", order);
        portalOrderService.cancelOrder(order);
    }
}
import com.murray.mq.commons.entity.Order;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * 前台订单管理Service
 *
 * @author Murray Law
 * @date 2021/5/6 13:26
 */

@Service
public class CancelOrderService {
     
    private static Logger LOGGER = LoggerFactory.getLogger(CancelOrderService.class);

    public void cancelOrder(Order order) {
     
        //TODO 实际项目中执行一系类取消订单操作
        LOGGER.info("已取消订单{}", order);
    }
}

好了,我们启动消息消费端项目 mq_consumer,清空控制台上的启动log,方便我们直观看出新的log记录
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第30张图片
清空后CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第31张图片

接着我们在 mq_producer 的测试类里写一个测试方法,添加图中红框内代码。
CentOS7下安装RabbitMQ,并使用Spring Boot实现一个简单的延迟队列(小白教程,附源码)_第32张图片
运行测试类后 mq_producer 的控制台,注意时间 1:03:57orderNumber
测试类运行效果

等待10秒后, mq_consumer 的控制台,消息时间是 1:04:07
因为网络等原因额外延迟了 264ms
消费者时间
好了,一个简单的RabbitMQ延迟队列就这么完成啦, 撒花!!!

你可能感兴趣的:(rabbitMQ,Linux,java,spring,boot,后端,linux,rabbitmq)