Rabbitmq的介绍、安装及使用

消息队列的用户和虚拟机

用户: 赋予操作rabbitmq权限的登录名和密码添加独立的登录用户
在这里插入图片描述
在这里插入图片描述
虚拟机(virtual host):每个用户需要绑定一个虚拟机使用(资源, 内存,cpu等划分的一个取余),不同的虚拟机虽然在同一个rabbitmq中存在,但是绑定的用户不同,管理的内容也不同;在不绑定虚拟机的情况下无法操作rabbitmq。
在这里插入图片描述

虚拟机和用户的绑定:

登录用户会自动和新建虚拟机绑定;
/jt和jtadmin绑定
点击虚拟机,绑定用户jtadmin
在这里插入图片描述


rabbitmq的核心概念


生产者

连接rabbitmq操作队列,存放发送消息的客户端.这个客户端可以是不同的语言编写的逻辑;需要编写代码逻辑的;

消费者

连接rabbitmq操作队列的代码客户端,监听队列,从中获取消息 消费,拿到消息后执行消费的逻辑代码

交换机

rabbitmq作为消息队列,解耦,消峰限流,需要并发能力极高(大量的客户端连接并发使用rabbitmq,消息也需要大量的并发完成发送);并不会允许客户端来完成这种并发的需求.基于erlang 开发的rabbitmq核心组件;根据配置和要求,连接生产者,将大量的消息并发发送到绑定的队列;
绑定
在使用rabbitmq时存在绑定的关系,队列与交换机绑定,没有与 这个交换机绑定的队列时不可能从交换机里获取消息的;
生产者与交换机也进行绑定(使用关系) 连接
客户端链接rabbitmq的消息队列技术,底层需要一个基于TCP 长链接的对象 connection
信道
基于底层tcp场链接的短连接,信道channel 队列
queue,所有的消息经过交换机发送存储在队列中,队列的另一 头绑定消费者;消费逻辑可以由代码确定,例如消费的一条消息什么时候删除.

RabbitMQ的工作模式

1.simple 简单模式

在这里插入图片描述

P:消息的生产者;代码连接时(任何支持的代码python,java,c#),将需要传递的消息,放到一个默认的交换机里,这个交换机在rabbitmq 中绑定所有的队列;
AMQP DEFAULT
The default exchange is implicitly bound to every queue, with a routing key equal to the queue name.
C:消息的消费者,异步监听队列,一旦发现任何新的消息,获取消息消费
应用场景:短信消息,qq,

2.work工作模式(资源竞争)

在这里插入图片描述
生产者P:将消息发送到队列
队列被多个消息消费者监听,一旦发现新的消息生成,将会根据自己的能力(性能,资源空闲率);
应用场景:秒杀,抢红包,大型项目的资源调度
在这里插入图片描述

3.发布订阅模式(publish/fanout共享资源)

在这里插入图片描述
x:代表rabbitmq一种核心组件交换机;
P:生产者不在直接将消息发送到队列中
交换机分发消息性能更高,是基于erlang语言开发的一条消息,在交换机中,被复制同时发送到多个队列; 应用场景:群发,广告.

4.routing路由模式

在这里插入图片描述
生产者发送消息,消息携带一个路由key
每个队列在绑定交换机时也有一个路由key
X交换机,根据消息携带的路由key,匹配具有相同路由key的queue队列
使用场景:错误消息的监听;

5.topic 主题模式

在这里插入图片描述

生产者发送携带具体的路由key的消息
假设:路由key haha.orange.haha 发送q1
haha. haha.haha.rabbit.haha 在交换机保留(ready)
lazy.haah.haha.lazy 发送q2
lazy.orange.lazy 1,2全发

*号:匹配一个单词(没有特殊符号的字符串) #号:匹配所有(所有字符串)

应用场景:转发路由过程中,携带的信息非常具体,可以将信息分类处理
jt.selete.item.unback(具体的路由key,消息携带的) jt.#:这个队列的路由key表示当前队列接收与jt项目有关的所有消息
jt.selete.#:表示与京淘项目的所有查询有关的消息
如何进行分类处理消息,需要根据系统需求,业务需求处理。

Rabbitmq的api简单模式

pom的依赖,需要依赖amqp

<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.boot<groupId>
<artifactId>spring-boot-starter-amqp<artifactId>
<dependency>

1 简单模式

生产者

package com.jt.amqp.rabbitmq; import java.io.IOException;
import java.util.concurrent.TimeoutException; import org.junit.Test;
import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; public class SimpleTest {
//利用一个方法测试生产者代码如何编写逻辑
//无论是生产端还是消费端都需要连接rabbitmq

@Test
public void sender() throws Exception{
//获取连接获取信道
/*1 创建连接工厂
*2 从连接工厂获取connection
*3 获取信道
*4 绑定queue
*5 发送消息
*6 释放资源
*/
//创建工厂
ConnectionFactory factory=new ConnectionFactory();
//连接工厂配置参数factory.setHost("106.75.120.140"); factory.setPort(5672); factory.setUsername("jtadmin"); factory.setPassword("123456"); factory.setVirtualHost("/jt");
//获取连接
Connection conn = factory.newConnection();
//获取信道对象短连接
Channel channel = conn.createChannel();
//利用短连接信息对象来操作rabbitmq
String queue_name="simple";

/*
*queue:String,即将生命创建的队列名称,可操作范围内已有同名队列
*就会直接绑定使用,没有就创建一个queue
*durable: Boolean 表示当前队列是否具有持久化的特性;
*exclusive:Boolean 表示queue是否专属.当前连接如果需要单独操作queue
*需要对queue进行专属的设定,true表示只有当前创建的连接可以操作queue,false表示
*所有连接都可以操作队列
*autoDelete:Boolean,是否自动删除,当前连接使 用完队列后是否删除
*arguments:Map,表示队列的其他属性;
*null表示使用默认的属性,包括消息超时,消息长度,队列的访问优先级
*/ 
channel.queueDeclare (queue_name, false, false, false, null);
//发送消息,利用channel发送,发送给默认交换机,""
String msg="hello simple model";

/*
*exchange: String 交换机名称,当前简单模式,没有交换机使用默认的
*routingKey:String 队列名称
*props:BasicProps 消息的属性内
容,BasicProps.deliveryMode值可以是
*0 持久化,1不持久化,配合durable存在
*body:byte[] 消息的二进制    
*/
channel.basicPublish("", queue_name, null, msg.getBytes());
//释放资源channel.close(); conn.close();}}

连接工具类

 public static Channel getResource(){ try{
    ConnectionFactory factory=new ConnectionFactory();
    //连接工厂配置参数factory.setHost("106.75.120.140"); factory.setPort(5672); factory.setUsername("jtadmin"); factory.setPassword("123456"); factory.setVirtualHost("/jt");
    //获取连接
    Connection conn = factory.newConnection();
    //获取信道对象短连接
    Channel channel = conn.createChannel(); return channel;
    }catch(Exception e){ e.printStackTrace(); return null;
    }
    
    }

消费者逻辑

 @Test
    public void receiver() throws Exception{
    //拿到信道
    Channel channel = ChannelUtil.getResource(); String queue_name="simple"; channel.queueDeclare(queue_name, false, false, false, null);
    //创建一个消费者对象QueueingConsumer consumer=new QueueingConsumer(channel);
    //绑定消费者和队列
    /*
    *queue:队列名称
    *autoAck:ack(acknowledge 确认) Boolean是否自动确认,当前消费逻辑到底是
    *那完了就回执,消费逻辑还没运行.还是等待消费 逻辑执行完毕后手动回执;代码编写回执的方法
    * channel.ack,channel.nack.channel.basicReject
    *callback:绑定的消费者对象
    */
    channel.basicConsume(queue_name, true, consumer);
    //接收消息,编写一个监听逻辑,在测试当中使用
    
    while死循环
    while(true){
    //获取一个下个消息的携带者,delivery Delivery delivery = consumer.nextDelivery();
    String msg=new String(delivery.getBody());//byte数组System.out.println("成功消费消息:"+msg);
    }
    }

工作模式(争抢资源)

package com.jt.amqp.rabbitmq; import java.io.IOException; import org.junit.Test;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.QueueingConsumer.Delivery;

public class WorkTest {
private static final String queue_name="work";
//生产端逻辑
@Test
public void sender() throws Exception{
Channel channel = ChannelUtil.getResource(); channel.queueDeclare
(queue_name, false, false, false, null); String msg="hello work model";
//利用for循环模拟海量消息的发送
for(int i=0;i<100;i++){
String msgDelive=msg+i; channel.basicPublish("", queue_name, null, msgDelive.getBytes());      System.out.println("生产者发送消息"+i+"条");
}

channel.close();
}

//消费逻辑,模拟资源处理速度不一样,添加模拟消费时间的 代码Thread.sleep();

@Test
public void rec01() throws Exception{
     Channel channel = ChannelUtil.getResource(); channel.queueDeclare(queue_name, false, false, false, null);
//限制当前消费者的获取消息的数量,表示在回执之前只能消费接收一条消息
channel.basicQos(1);
//创建一个消费者对象QueueingConsumer consumer=new QueueingConsumer(channel);
channel.basicConsume(queue_name, false, consumer);
//为了添加消费时间的逻辑有效,必须手动回执;
while(true){
Delivery delivery = consumer.nextDelivery(); String msg=new String(delivery.getBody()); System.out.println("消费者01接收消息:"+msg);
//没有手动添加回执的情况下,队列认为你没有消 费完,下一条消息不发送
Thread.sleep(50); channel.basicAck
(delivery.getEnvelope().getDeliveryTag(),

false);

}
}

@Test
public void rec02() throws Exception{
Channel channel = ChannelUtil.getResource(); channel.queueDeclare(queue_name, false, false, false, null);
//限制当前消费者的获取消息的数量,表示在回执之前只能消费接收一条消息
channel.basicQos(1);
//创建一个消费者对象QueueingConsumer consumer=new QueueingConsumer(channel);
channel.basicConsume(queue_name, false, consumer);
//为了添加消费时间的逻辑有效,必须手动回执;
while(true){
Delivery delivery = consumer.nextDelivery(); String msg=new String(delivery.getBody()); System.out.println("消费者02接收消息:"+msg);
//没有手动添加回执的情况下,队列认为你没有消 费完,下一条消息不发送
Thread.sleep(10); 
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
    }
   }
 }

发布订阅模式

package cn.china;

import java.io.IOException;

import org.junit.Test;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;

public class PublishTest {
    private static final String exchange_name = "publish1805";
    private static final String queue01 = "pqueue01";
    private static final String queue02 = "pqueue02";
//生产端
@Test
public void sender() throws Exception {
    //自定义交换机名称
    Channel channel = ChannelUtil.getResource();
    //声明交换机,生产者只需要与交换机互动,声明队列可以不 再生产端完成
    //交换机类型4种:fanout发布订阅,direct路由,topic主题模 式 ,header rpc channel.exchangeDeclare(exchange_name, "fanout"); for(int i=0;i<100;i++){

    String msg = "hello publish mode" + i;
    // 发 布 订 阅 的 路 由 key,"" channel.basicPublish(exchange_name, "", null, msg.getBytes());
}


@Test
public void rec01() throws Exception {
    Channel channel = ChannelUtil.getResource();
    //声明队列
    channel.queueDeclare(queue01, false, false, false, null);
    //声明交换机
    channel.exchangeDeclare(exchange_name, "fanout");
    //绑定关系,交换机和队列也需要绑定
    channel.queueBind(queue01, exchange_name, "");
    //消费者
    QueueingConsumer consumer = new QueueingConsumer(channel);
    //绑定消费者队列
    channel.basicConsume(queue01, true, consumer);
    //while 接收消费消息
    while (true) {
        Delivery delivery = consumer.nextDelivery();
        String msg = new String(delivery.getBody());
        System.out.println("消费者01接收消息:" + msg);
    }
}

@Test
public void rec02() throws Exception {

    Channel channel = ChannelUtil.getResource();
    //声明队列
    channel.queueDeclare(queue02, false, false, false, null);
    //声明交换机
    channel.exchangeDeclare(exchange_name, "fanout");
    //绑定关系,交换机和队列也需要绑定
    channel.queueBind(queue02, exchange_name, "");
    //消费者
    QueueingConsumer consumer = new QueueingConsumer(channel);
    //绑定消费者队列
    channel.basicConsume(queue02, true, consumer);
    //while 接收消费消息
    while (true) {
        Delivery delivery = consumer.nextDelivery();
        String msg = new String(delivery.getBody());
        System.out.println("消费者02接收消息:" + msg);
    }
}

}

路由模式和主题模式

package com.jt.amqp.rabbitmq;

import org.junit.Test;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;

public class RoutingTest {
    private static final String exchange_name = "direct1805";
    private static final String queue01 = "dqueue01";
    private static final String queue02 = "dqueue02";

//生产端
@Test
public void sender() throws Exception {
//自定义交换机名称
    Channel channel = ChannelUtil.getResource();
//声明交换机,生产者只需要与交换机互动,声明队列可以不 再生产端完成
//交换机类型4种:fanout发布订阅,direct路由,topic主题模 式 ,header rpc channel.exchangeDeclare(exchange_name, "direct"); String msg=" 我 要 新 增 一 条 商 品 "; channel.basicPublish(exchange_name, "item.add", null, msg.getBytes());

}

@Test
public void rec01() throws Exception {
    Channel channel = ChannelUtil.getResource();
    //声明队列
    channel.queueDeclare(queue01, false, false, false, null);
    //声明交换机
    channel.exchangeDeclare(exchange_name, "direct");
    //绑定关系,交换机和队列也需要绑定channel.queueBind(queue01, exchange_name, "item.update");
    //消费者
    QueueingConsumer consumer = new QueueingConsumer(channel);
    //绑定消费者队列
    channel.basicConsume(queue01, true, consumer);
    //while 接收消费消息
    while (true) {
        Delivery delivery = consumer.nextDelivery();
        String msg = new String(delivery.getBody());
        System.out.println("消费者01接收消息:" + msg);
    }
}

@Test
public void rec02() throws Exception {

    Channel channel = ChannelUtil.getResource();
    //声明队列

    channel.queueDeclare(queue02, false, false, false, null);
    //声明交换机
    channel.exchangeDeclare(exchange_name, "direct");
    //绑定关系,交换机和队列也需要绑定channel.queueBind(queue02, exchange_name, "item.add");
    //消费者
    QueueingConsumer consumer = new QueueingConsumer(channel);
    //绑定消费者队列
    channel.basicConsume(queue02, true, consumer);
    //while 接收消费消息
    while (true) {
        Delivery delivery = consumer.nextDelivery();
        String msg = new String(delivery.getBody());
        System.out.println("消费者02接收消息:" + msg);
    }
  }
}

springboot整合rabbitmq

package com.jt.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;


@Configuration
public class RabbitmqConfiguration {

//根据需要创建交换机,创建队列,一个交换机,2 个队列
@Bean
public Queue getQueue01() {
    return new Queue("itemUpdateQueue");
}

@Bean
public Queue getQueue02() {
    return new Queue("itemAddQueue");
}

//声明交换机,路由模式
@Bean
public DirectExchange getExchange() {
    return new DirectExchange("1805directSpringboot")
            ;

}

//单独做绑定
@Bean
public Binding binding01() {
    return
            BindingBuilder.bind(getQueue01()).to(getExchange()).with("item.upd ate");
}

@Bean
public Binding binding02() {
    return
            BindingBuilder.bind(getQueue02()).to(getExchange()).with("item.add ");
}

3.编写生产者代码

/**
 * 生产者发送消息,可以注入一个rabbitTemplate的 对象,利用这个对象将消息发送给交换机;
 */
@Autowired
private RabbitTemplate rabbitmq;

@RequestMapping("send/{msg}")
@ResponseBody
public String sendMsg(@PathVariable String msg) {
    //接收的消息参数就会被绑定item.add 的路由key,发送到指定交换机
    rabbitmq.convertAndSend("1805directSpringboot ", " item.add ", msg);
    return " success ";
}

4.消费者代码

/**
 * 利用注解底层实现异步监听@RabbitListener 绑定监听队列
 */

@Component
public class RabbitMqReceiver {
    //消费逻辑的方法,其中的参数就是我们传递的消息
    @RabbitListener(queues = "itemAddQue ue")
    public void process01(String msg) {
        System.out.println("增加的消费端收到消息:" + msg);
    }

    @RabbitListener(queues = "itemUpdateQ ueue")
    public void process02(String msg) {
        System.out.println("更新的消费端收到消息:" + msg);
    }
  }
}

springboot收集连接信息之后,帮你完成了对象的创建.只需要注入模板对象即可操作rabbitmq(整合时依赖的jar包starter-amqp)

1配 置 application.properties spring.rabbitmq.host=106.75.120.140 spring.rabbitmq.port=5672 spring.rabbitmq.username=jt spring.rabbitmq.password=123456 spring.rabbitmq.virtualHost=/jt
框架创建管理一个rabbitmqTemplate的模板对象,底 层都是获取连接,生成信道对象操作的.可以完成amqp的一些手动对象的封装来实现交换机的创建, 队列的创建
2利用注解Bean和方法来创建我们需要的内容(交换机和队列)–路由模式为例
在一个Configuration的类上添加队列情况的配置;

整合的过程中,框架管理维护了大部分底层各种连接绑定的关系内容,开发人员只需要根据业务逻辑配置rabbitmq中队列,交换机等的结构,类型,把大量精力放 到业务执行上;如果我们需要对template的对象进行

二次封装,也可以完成生产,消费的逻辑;

消费端不止可以在与生产端同工程的代码编写,还可以在任何一个连接相同rabbitmq的工程中完成监听;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值