Title

RabbitMQ安装与使用

系统环境

1、JDK1.8
2、Centos7-64位
3、Erlang-OTP 23
4、RabbitMQ-3.8.5

linux版本信息查看

cat /proc/version

Linux version 3.10.0-1127.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) ) #1 SMP Tue Mar 31 23:36:51 UTC 2020

uname -r

3.10.0-1127.el7.x86_64

cat /etc/redhat-release

CentOS Linux release 7.8.2003 (Core)

uname -s

Linux

cat /etc/os-release

NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

安装Erlang

erlang和rabbitmq的版本对应关系

通过rpm安装erlang

完成erlang的前置条件配置

curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash

安装erlang

yum install -y erlang

检查erlang的版本号

erl

安装RabbitMQ

先导入两个key

rpm --import https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey
rpm --import https://packagecloud.io/gpg.key

没报错就表示正常

完成RabbitMQ的前置条件配置

curl -s https://packagecloud.io/install/repositories/rabbitmq/rabbitmq-server/script.rpm.sh | sudo bash

下载RabbitMQ安装包

注意看CentOS的版本,6,7,8都有。我这里是7.4。有时候直接点击浏览器下载可能会很慢,可以F12,找到链接,在centos里面去使用wget下载,可能会很快。这里给出Centos7和Centos8的下载链接。

CentOS7:
https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.5/rabbitmq-server-3.8.5-1.el7.noarch.rpm
CentOS8:
https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.5/rabbitmq-server-3.8.5-1.el8.noarch.rpm

下载成功后,上传到服务器,然后使用命名安装。

rpm -ivh rabbitmq-server-3.8.5-1.el7.noarch.rpm

仔细看有一个警告和一个错误。警告是缺少key,而错误是socat,只需要导入key和安装socat即可。

解决:

  1. 导入key

rpm --import https://www.rabbitmq.com/rabbitmq-release-signing-key.asc

  1. 安装socat

yum -y install epel-release
yum -y install socat

  1. 再次安装RabbitMQ

rpm -ivh rabbitmq-server-3.8.5-1.el7.noarch.rpm

启用管理平台插件,启用插件后,可以可视化管理RabbitMQ。

rabbitmq-plugins enable rabbitmq_management

启动RabbitMQ

systemctl start rabbitmq-server

访问控制台界面

访问地址

http://192.168.10.88:15672

192.168.10.88是安装RabbitMQ的服务器IP地址。如果访问不了,确认是否开启端口5672和15672。

用户登录

RabbitMQ3.3以后,guest账号只能在本机登录。这里就不去修改相应配置了,而是另外创建其他登录账号。

创建用户

创建用户名admin,密码abcd的用户:

rabbitmqctl add_user admin abcd

设置admin为超级管理员

rabbitmqctl set_user_tags admin administrator

授权远程访问(也可以登录后,可视化配置)

rabbitmqctl set_permissions -p / admin "." "." ".*"

创建完成后,重启RabbitMQ

systemctl restart rabbitmq-server

登录用户admin

设置虚拟主机

在正常安装RabbitMQ之后, 系统会默认创建一个虚拟主机 名称以 / 的形式,看到admin是No access的,需要设置一下虚拟主机

点击Virtual Hosts 添加一个名为test的虚拟主机

添加成功后点击test这里我们为虚拟主机添加用户

点击权限后, 选择User的下拉中就能看到我们的刚添加的用户

点击Set permission 设置权限后就能在上方权限列表中看见我们刚添加的用户

回到虚拟主机的页面后, 我们发现会多出一条记录

页面配置

添加队列 Queues

创建交换机 Exchanges

选择交换机 Exchanges 加入已经创建好的队列 Queues

延迟队列

简介

延迟队列,名字中有个队列,队列是先进先出的。所以说延迟队列是一个有方向性的。

其次,延迟队列和普通队列最大的区别就是,普通队列里的消息是希望自己早点被取出来消费。而延迟队列中的消息都是由时间来控制的。也就是说,他们进入队列的时候,就已经被安排何时被取出了

rabbitmq实现延迟队列主要有种方式。

  • 第一种是使用普通队列和死信队列来模拟实现延迟的效果。大致上是将消息放入一个没有被监听的队列上,设置TTL(一条消息的最大存活时间)为延迟的时间,时间到了没有被消费,直接成为私信。监听私信队列来进行操作。

  • 第二种是使用rabbitmq官方提供的delayed插件来真正实现延迟队列。本文对第二种进行详解

应用场景

订单超时支付取消订单
用户发起退款卖家3天不处理自动退款
预约抢购活动,活动开始前10分钟短信通知用户

安装延迟插件

默认交换机是有4种模式的

下载延迟插件: https://www.rabbitmq.com/community-plugins.html

下载完成之后,上传到服务器mq容器的plugins目录下

安装插件:rabbitmq-plugins enable rabbitmq_delayed_message_exchange

交换机新增一个延迟模式

配置

配置类

初始化一个队列和一个延迟交换机(这里我交换机模式用的是路由模式)。将队列绑定到交换机上并设置路由Key


@Component
public class RabbitmqDelayedConfig {
 
    /**
     * 初始化延迟交换机
     * @return
     */
    @Bean
    public CustomExchange delayedExchangeInit() {
        Map<String, Object> args = new HashMap<>();
        // 设置类型,可以为fanout、direct、topic
        args.put("x-delayed-type", "direct");
        // 第一个参数是延迟交换机名字,第二个是交换机类型,第三个设置持久化,第四个设置自动删除,第五个放参数
        return new CustomExchange("delayed_exchange","x-delayed-message", true,false,args);
    }
 
    /**
     * 初始化短信队列
     * @return
     */
    @Bean
    public Queue delayedSmsQueueInit() {
        return new Queue("sms_delayed_queue", true);
    }
 
 
    /**
     * 短信队列绑定到交换机
     * @param delayedSmsQueueInit
     * @param customExchange
     * @return
     */
    @Bean
    public Binding delayedBindingSmsQueue(Queue delayedSmsQueueInit, CustomExchange customExchange) {
        // 延迟队列绑定延迟交换机并设置RoutingKey为sms
        return BindingBuilder.bind(delayedSmsQueueInit).to(customExchange).with("sms").noargs();
    }
}

生产者

将消息转发到"delayed_exchange"交换机上路由键为"sms"的队列中


@Component
@Log4j2
public class Producer {
 
    @Autowired
    private RabbitTemplate rabbitTemplate;
 
    /**
     * 延迟模式
     * @param msg 消息
     * @param time 延迟时间
     */
    public void delayedTest(String msg,Integer time) {
        // 第一个参数是延迟交换机名称,第二个是Routingkey,第三个是消息主题,第四个是X,并设置延迟时间,单位		是毫秒
        rabbitTemplate.convertAndSend("delayed_exchange","sms",msg,a -> {
            a.getMessageProperties().setDelay(time);
            return a;
        });
        log.info("延迟模式默认交换机已发出消息");
    }
 
}

消费者

监听指定的队列。一旦队列中有消息则立刻取出进行消费

@Component
@Log4j2
public class ConsumerDelayed {
 
    /**
     * 延迟模式短信消费者
     * @param message
     */
    @RabbitListener(queues = {"sms_delayed_queue"})
    public void getSmsConsumer(String message) {
        log.info(new Date().toLocaleString() + "延迟模式短信消费者接收到信息:" + message);
    }
 
}

发出消息并且10S后延迟队列对消息进行消费

@RabbitListener

在spring中,定义rabbitMq的消费者可以相当方便,只需要在消息处理类或者类方法加上@RabbitListener注解,指定队列名称即可。如下代码:

@Component
public class RabbitMqListener1 {
    @RabbitListener(queues = "queue1")
    public void consumer1(Message message) {

    }

    @RabbitListener(queues = "queue2")
    public void consumer2(String messsageBody) {

    }
}


@Component
@RabbitListener(queues = "queue3")
public class RabbitMqListener2 {
    @RabbitHandler(isDefault=true)
    public void consumer3() {

    }
}

RabbitMQ 图形化说明:
https://www.cnblogs.com/chenshaojun2008/p/17250864.html

springboot集成RabbitMQ

  1. 添加依赖
<dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-amqp</artifactId>
 </dependency>
  1. 配置RabbitMQ连接

application.propertiesapplication.yml中配置RabbitMQ服务器的连接参数:

# 总开关配置
spring.rabbitmq.enable=true

# 定义RabbitMQ的主机地址,这里使用的是局域网内的一个IP地址
spring.rabbitmq.host=192.168.131.130

# 指定RabbitMQ的端口号,默认情况下RabbitMQ使用5672端口
spring.rabbitmq.port=5672

# 设置RabbitMQ的用户名,这里使用的是默认的用户名guest
spring.rabbitmq.username=guest

# 设置RabbitMQ的密码,这里使用的是默认的密码guest
spring.rabbitmq.password=guest

# 配置RabbitMQ的虚拟主机,这里使用的是默认的虚拟主机"/"
spring.rabbitmq.virtual-host=/

@ConditionalOnProperty(name = "spring.rabbitmq.enable", havingValue = "true")spring.rabbitmq.enabled的值为true时,RabbitMqConfig配置类中的Bean会被创建,否则不会创建。这样你就可以根据需要开启或关闭RabbitMQ的配置。

  1. 使用

一个交换机绑定一个队列

  • 消费者
@Configuration
@ConditionalOnProperty(name = "spring.rabbitmq.enable", havingValue = "true")
public class DirectConsumer extends RabbitAutoConfiguration {
    //注册一个队列
    @Bean  //启动多次为什么不报错?启动的时候,它会根据这个名称Direct_Q01先去查找有没有这个队列,如果有什么都不做,如果没有创建一个新的
    public Queue directQueue(){
      return   QueueBuilder.durable("Direct_Q01").maxLength(100).build();
    }
    //注册交换机
    @Bean
    public DirectExchange directExchange(){
        //1.启动的时候,它会根据这个名称Direct_E01先去查找有没有这个交换机,如果有什么都不做,如果没有创建一个新的
        return  ExchangeBuilder.directExchange("Direct_E01").build();
    }
    //绑定交换机与队列关系
    @Bean
    public Binding directBinding(Queue directQueue,DirectExchange directExchange){
        return BindingBuilder.bind(directQueue).to(directExchange).with("RK01");
    }
    //启动一个消费者
    @RabbitListener(queues = "Direct_Q01")
    public void receiveMessage(String msg){
        System.out.println("Direct_Q01收到消息:"+msg);
    }
}
  • 生产者
//放入Ioc容器
@Service
public class DirectProvider {
    @Resource   
    private RabbitTemplate rabbitTemplate;
    //发送消息
    public void send(String message) {
        rabbitTemplate.convertAndSend("Direct_E01", "RK01", message);
    }
}
  • 测试
@SpringBootTest(classes = App.class)
public class TestDirect {
    @Resource
    private DirectProvider directProvider;
    @Test
    public void  directSendTest(){
        for (int i = 0; i < 10; i++) {
            directProvider.send("我嫩爹");
        }
    }
}

一个交换机对多个队列

  • 消费者
@Configuration
@ConditionalOnProperty(name = "spring.rabbitmq.enable", havingValue = "true")
public class FanoutConsumer extends RabbitAutoConfiguration {
    //注册一个队列
    @Bean  
    public Queue fanoutQueue(){
      return   QueueBuilder.durable("Fanout_Q01").maxLength(100).build();
    }
    @Bean  
    public Queue fanoutQueue2(){
        return   QueueBuilder.durable("Fanout_Q02").maxLength(100).build();
    }
    //注册交换机
    @Bean
    public FanoutExchange fanoutExchange(){
        return  ExchangeBuilder.fanoutExchange("Fanout_E01").build();
    }

    //绑定交换机与队列关系
    @Bean
    public Binding fanoutBinding(Queue fanoutQueue,FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue).to(fanoutExchange);
    }
    @Bean
    public Binding fanoutBinding2(Queue fanoutQueue2,FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
    }

    //启动一个消费者
    @RabbitListener(queues = "Fanout_Q01")
    public void receiveMessage(String msg){
        System.out.println("Fanout_Q01收到消息:"+msg);
    }
    //启动一个消费者
    @RabbitListener(queues = "Fanout_Q02")
    public void receiveMessage2(String msg){
        System.out.println("Fanout_Q02收到消息:"+msg);
    }

}
  • 生产者
@Service
public class FanoutProvider {

    @Resource
    private RabbitTemplate rabbitTemplate;

    public void send(JSONObject message) {
        rabbitTemplate.convertAndSend("Fanout_E01","",message.get("msg"));
    }
}
  • 测试
@RestController
@RequestMapping("/fanout")
public class FanoutController {
    @Resource
    private FanoutProvider fanoutProvider;
    @PostMapping("/send")
    public void send(@RequestBody JSONObject message) {
        fanoutProvider.send(message);
    }
}

一个队列对多个消费者

  • 消费者
@Configuration
@ConditionalOnProperty(name = "spring.rabbitmq.enable", havingValue = "true")
public class TopicConsumer extends RabbitAutoConfiguration {
    //注册一个队列
    @Bean  
    public Queue topicQueue(){
      return   QueueBuilder.durable("Topic_Q01").maxLength(100).build();
    }

    //注册交换机
    @Bean
    public TopicExchange topicExchange(){
        return  ExchangeBuilder.topicExchange("Topic_E01").build();
    }

    //绑定交换机与队列关系
    @Bean
    public Binding topicBinding(Queue topicQueue,TopicExchange topicExchange){
        return BindingBuilder.bind(topicQueue).to(topicExchange).with("#");
    }

    //启动一个消费者
    @RabbitListener(queues = "Topic_Q01")
    public void receiveMessage(String msg){
        System.out.println("Topic_Q01收到消息:"+msg);
    }
    //启动一个消费者
    @RabbitListener(queues = "Topic_Q01")
    public void receiveMessage2(String msg){
        System.out.println("Topic_Q02收到消息:"+msg);
    }

}
  • 生产者
@@Service
public class TopicProvider {

    @Resource
    private RabbitTemplate rabbitTemplate;

    public void send(JSONObject message) {
        rabbitTemplate.convertAndSend("Topic_E01",message.get("routingKey").toString(),message.get("msg"));
    }
}
  • 测试
@RestController
@RequestMapping("/fanout")
public class FanoutController {
    @Resource
    private TopicProvider topicProvider ;
    @PostMapping("/send")
    public void send(@RequestBody JSONObject message) {
        topicProvider.send(message);
    }
}

原文链接:
https://blog.csdn.net/weixin_40584261/article/details/106826044
https://blog.csdn.net/qq_28967139/article/details/119216362
https://blog.csdn.net/qq_40179653/article/details/125618655
https://blog.csdn.net/qq_57036151/article/details/141174303

posted @ 2023-06-21 15:47  快乐小洋人  阅读(120)  评论(0编辑  收藏  举报