RabbitMQ基础篇

课程资料
链接:https://pan.baidu.com/s/14ziQH62MeYmM8N6JsH5RcA
提取码:yyds

快速入门

安装RabbitMQ

在这里插入图片描述

docker load -i mq.tar #解压镜像

运行 RabbitMQ

docker run \
 -e RABBITMQ_DEFAULT_USER=user \
 -e RABBITMQ_DEFAULT_PASS=123456 \
 --name mq \
 --hostname mq1 \
 -p 15672:15672 \
 -p 5672:5672 \
 -d \
 rabbitmq:management

15672是管理台的端口!!!
在这里插入图片描述
MQ的基本结构:
在这里插入图片描述
RabbitMQ中的一些角色:

  • publisher:生产者
  • consumer:消费者
  • exchange:交换机,负责消息路由
  • queue:队列,存储消息
  • virtualHost:虚拟主机,隔离不同租户的exchange、queue、消息的隔离

依赖

pom.xml

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.9.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--AMQP依赖,包含RabbitMQ-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

yaml文件

spring:
  rabbitmq:
    host: 192.168.111.101 # 主机名
    port: 5672 # 端口
    virtual-host: / # 虚拟主机
    username: user # 用户名
    password: 123456 # 密码

@RabbitListener和@RabbitHandler的使用

@RabbitListener 标注在方法上, 直接 监听指定的队列,此时接收的参数需要 与发送时类型一致

@Component
public class PointConsumer {
	//监听的队列名
    @RabbitListener(queues = "point.to.point")
    public void processOne(String name) {
        System.out.println("point.to.point:" + name);
    }
 
}

@RabbitListener 可以标注在上面,需配合 @RabbitHandler 注解一起使用
@RabbitListener 标注在类上面表示当有收到消息的时候,就交给 @RabbitHandler 的方法处理,根据接受的参数类型进入具体的方法中

@Component
@RabbitListener(queues = "consumer_queue")
public class Receiver {
 
    @RabbitHandler
    public void processMessage1(String message) {
        System.out.println(message);
    }
 
    @RabbitHandler
    public void processMessage2(byte[] message) {
        System.out.println(new String(message));
    }
    
}

RabbitMQ消息模型

WorkQueue

让多个消费者绑定到一个队列,共同消费队列中的消息

在这里插入图片描述
当消息处理比较耗时的时候,可能生产消息的速度会远远大于消息的消费速度。长此以往,消息就会堆积越来越多,无法及时处理!!

消息发送

@Test
public void testWorkQueue() throws InterruptedException {
    // 队列名称
    String queueName = "simple.queue";
    // 消息
    String message = "hello, message_";
    for (int i = 0; i < 50; i++) {
        // 发送消息
        rabbitTemplate.convertAndSend(queueName, message + i);
        Thread.sleep(20);
    }
}

消息接收

@RabbitListener(queues = "simple.queue")
public void listenWorkQueue1(String msg) throws InterruptedException {
    System.out.println("消费者1接收到消息:【" + msg + "】" + LocalTime.now());
    Thread.sleep(20);
}

@RabbitListener(queues = "simple.queue")
public void listenWorkQueue2(String msg) throws InterruptedException {
    System.err.println("消费者2........接收到消息:【" + msg + "】" + LocalTime.now());
    Thread.sleep(200);
}

默认是平均分配给每个消费者

加快消息处理,simple代表简单队列模型

spring:
  rabbitmq:
    listener:
      simple:
        prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一个消息

发布/订阅

发布订阅的模型如图:
在这里插入图片描述

可以看到,在订阅模型中,多了一个exchange角色,而且过程略有变化:

  • Publisher:生产者,也就是要发送消息的程序,但是不再发送到队列中,而是发给X(交换机)
  • Exchange:交换机,图中的X。一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。Exchange有以下3种类型:
    • Fanout:广播,将消息交给所有绑定到交换机的队列
    • Direct:定向,把消息交给符合指定routing key 的队列
    • Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列
  • Consumer:消费者,与以前一样,订阅队列,没有变化
  • Queue:消息队列也与以前一样,接收消息、缓存消息。

Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失

Fanout

MQ中叫广播更合适
在这里插入图片描述

声明队列和交换机

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FanoutConfig {
    /**
     * 声明交换机
     * @return Fanout类型交换机
     */
    @Bean
    public FanoutExchange fanoutExchange() {
        return new FanoutExchange("myfanout");
    }
    /**
     * 第1个队列
     */
    @Bean
    public Queue queue1() {
        return new Queue("fanout.queue1");
    }
    /**
     * 第2个队列
     */
    @Bean
    public Queue queue2() {
        return new Queue("fanout.queue2");
    }

    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindQueue1(Queue queue1, FanoutExchange fanoutExchange){
        return  BindingBuilder.bind(queue1).to(fanoutExchange);
    }
    @Bean
    public Binding bindQueue2(Queue queue2, FanoutExchange fanoutExchange){
        return  BindingBuilder.bind(queue2).to(fanoutExchange);
    }

}

消息发送

	@Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testFanoutExchange() {
        // 队列名称
        String exchangeName = "myfanout";
        // 消息
        String message = "hello, everyone!";
        rabbitTemplate.convertAndSend(exchangeName, "", message);
    }

消息接收


import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;


@Component
@RabbitListener(queues = "fanout.queue1")
public class FanoutReceiver {
    @RabbitHandler
    public void  process(String message) {
        System.out.println (message);

    }
}

Direct

声明队列和交换机

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class DirectConfig {

    //Direct交换机
    @Bean
    DirectExchange directExchange() {
        return new DirectExchange ("mydirect");
    }

    //队列
    @Bean
    public Queue directQueue() {
        return new Queue ("direct.queue1", true);
    }


    //绑定
    @Bean
    Binding bindingDirect(Queue directQueue, DirectExchange directExchange) {
        return BindingBuilder.bind (directQueue).to (directExchange)
                .with ("red");
    }
    //绑定
    @Bean
    Binding bindingDirect2(Queue directQueue, DirectExchange directExchange) {
        return BindingBuilder.bind (directQueue).to (directExchange)
                .with ("yellow");
    }
}

消息发送的流程:
1、指定exchangeName交换机名称
2、指定routingKey 路由键
3、指定消息体
4、发送
5、发送到交换机后,根据routingKey 路由键找到队列
direct.queue1队列绑定了两个 routingKey(red、yellow),故yellow、red作为路由键都能发送到该队列中

Direct交换机根据RoutingKey判断路由给哪个队列

消息发送

@Autowired
private RabbitTemplate rabbitTemplate;

@Test
public void testSendDirectExchange() {
    // 交换机名称
    String exchangeName = "mydirect";
    // 消息
    String message = "红色警报!日本乱排核废水,导致海洋生物变异,惊现哥斯拉!";
    // 发送消息
    rabbitTemplate.convertAndSend(exchangeName, "red", message);
}

消息接收方

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;


@Component
@RabbitListener(queues = "direct.queue1")
public class DirectReceiver {
    @RabbitHandler
    public void process(String message) {
        System.out.println (message);

    }
}

Topic

声明队列和交换机

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TopicConfig {


    /**
     * 交换机
     *
     * @return
     */
    @Bean
    TopicExchange exchange() {
        return new TopicExchange ("mytopic");
    }

    /**
     * 队列
     *
     * @return
     */
    @Bean
    public Queue queue() {
        return new Queue ("topic.queue1");
    }


    // 绑定topic.second队列到topic.#,凡是topic.开头的routingKey消息都发送到此队列
    @Bean
    Binding bindingExchangeMessage2(Queue queue, TopicExchange exchange) {
        return BindingBuilder.bind (queue).to (exchange).with ("topic.#");
    }

}

Topic交换机根据RoutingKey判断路由给哪个队列

@Autowired
private RabbitTemplate rabbitTemplate;

@Test
public void testSendTopicExchange() {
    // 交换机名称
    String exchangeName = "mytopic";
    // 消息
    String message = "红色警报!日本乱排核废水,导致海洋生物变异,惊现哥斯拉!";

    rabbitTemplate.convertAndSend (exchangeName, "topic.hi", message);
}
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;


@Component
@RabbitListener(queues = "topic.queue1")
public class TopicReceiver {
    @RabbitHandler
    public void process(String message) {
        System.out.println (message);

    }
}

配置JSON转换器

publisher和consumer两个服务中都引入依赖

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.10</version>
</dependency>

启动类中添加一个Bean即可:

import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
@Bean
public MessageConverter jsonMessageConverter(){
    return new Jackson2JsonMessageConverter();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值