SpringBoot 整合 RabbitMQ(三)

1,394 阅读5分钟

日积月累,水滴石穿 😄

前言

前面已经用俩篇文章来介绍 RabbitMQ 了。本篇呢,就带大家一起看看在 SpringBoot 中如何去使用RabbitMQ

环境搭建

导入依赖

image.png

pom

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

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

配置配置文件

在配置文件中配置 RabbitMQ的基本信息,ip、port、username、password、virtual-host。各位如果看过第一篇的,应该对这些会感到很熟悉的。

spring:
  application:
    name: rabbitmq-boot
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    virtual-host: /test-1
    username: ***
    password: ****

SpringBoot使用RabbitTemplate简化对RabbitMQ操作,使用时候直接在项目中注入即可使用。

使用

接下来呢,就介绍一下在 SpringBoot 如何去使用 RabbitMQ中的消息模型。

hello world 模型

image.png 一个生产者对应一个消费者。

1、开发生产者

@Autowired
RabbitTemplate rabbitTemplate;

@Test
void testHello(){
    /**
     * 参数一:队列名称
     * 参数二:消息内容
     */
    rabbitTemplate.convertAndSend("hello-boot","hello boot");
}

注:由于我们还没有编写消费者,单独运行上述生产者并不会产生队列,队列是由消费者创建的

2、开发消费者

@Component
public class HelloCustomer {

 // 通过注解创建 hello-boot 队列
    @RabbitListener(queuesToDeclare = {
        @Queue(value = "hello-boot",durable = "false",
        autoDelete = "false")
        })
    public void consumptionStr(String message){
        System.out.println("消费消息:" + message);
    }
}

@RabbitListener注解标注的方法,会被作为消费消息的方法,也就是消费者;我们可以通过注解参数指定所监听的队列或者 Binding。

@Queue注解可以设置队列属性,例如:

然后运行生产者所在的 testHello方法。

结果:消费消息:hello boot

work模型

image.png 一个生产者对应多个消费者。

1、开发生产者

@Test
void testWork(){
    /**
     * 参数一:队列名称
     * 参数二:消息内容
     */
    for (int i = 0; i < 10; i++) {
        rabbitTemplate.convertAndSend("work-boot","work boot");
    }
}

2、开发消费者

@Component
public class WorkCustomer {
 // 通过注解创建 work-boot 队列
    @RabbitListener(queuesToDeclare = @Queue("work-boot"))
    public void work1(String message){
        System.out.println("消费消息-1:" + message);
    }

    @RabbitListener(queuesToDeclare = @Queue("work-boot"))
    public void work2(String message){
        System.out.println("消费消息-2:" + message);
    }
}

结果:
消费消息-1:work boot
消费消息-1:work boot
消费消息-2:work boot
消费消息-2:work boot
消费消息-2:work boot
消费消息-2:work boot
消费消息-2:work boot
消费消息-1:work boot
消费消息-1:work boot
消费消息-1:work boot

我们根据结果可以发现:两个消费者分别消费了 5 条消息。可以说明:默认在Spring AMQP中实现Work这种方式就是公平调度的。如果需要实现能者多劳需要额外配置

fanout模型

image.png 这个模型,加入了一个新成员,名为交换机。消息由 mq 分发给交换机,然后由交换机发送给队列。

1、开发生产者

@Test
void testfanout(){
    /**
     * 参数一:交换机名称
     * 参数二:路由名称(在fanout模式下,该参数无作用)
     * 参数三:消息内容
     * 
     */
 rabbitTemplate.convertAndSend("fanout-boot-exchange",
 "","fanout boot");

}

2、开发消费者

@RabbitListener(bindings = {
        @QueueBinding(
                value = @Queue,  //创建临时队列
                exchange = @Exchange(value = "fanout-boot-exchange",
                type = "fanout")  //绑定交换机
        )
})
public void fanoutStr(String message){
    System.out.println("消费消息-1:" + message);
}

@RabbitListener(bindings = {
        @QueueBinding(
                value = @Queue,  //创建临时队列
                exchange = @Exchange(value = "fanout-boot-exchange",
                type = "fanout")  //绑定交换机
        )
})
public void fanoutStr2(String message){
    System.out.println("消费消息-2:" + message);
}
结果:
消费消息-2:fanout boot
消费消息-1:fanout boot

@QueueBinding注解用来绑定队列和交换机。

@Exchange注解用来声明交换机。

根据打印的结果可以发现,队列的消费者都能拿到了消息。实现一条消息被多个消费者消费。

Route 模型

在 Fanout 模式中,一条消息,会被所有订阅的队列都消费。但是,在某些场景下,我们希望不同的消息被不同的队列消费。这时就要用到 Direct 类型的 Exchange。 image.png

1、开发生产者

@Test
void testDirect(){
    /**
     * 参数一:交换机名称
     * 参数二:路由名称
     * 参数三:消息内容
     *
     */
    rabbitTemplate.convertAndSend("direct-boot-exchange",
    "error","direct boot error");

}

2、开发消费者

import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class directCustomer {

    @RabbitListener(bindings = {
            @QueueBinding(value = @Queue,  //创建临时队列
             exchange = @Exchange(value = "direct-boot-exchange",
             //绑定交换机名称和类型,默认类型就为direct
             type = "direct"),  
             key = {"info"})  //路由key

    })
    public void directStr(String message){
        System.out.println("消费消息-1:" + message);
    }

    @RabbitListener(bindings = {
            @QueueBinding(value = @Queue, 
                exchange = @Exchange(value = "direct-boot-exchange",
                type = "direct"),
                key={"info","error"})  //路由key

    })
    public void directStr2(String message){
        System.out.println("消费消息-2:" + message);
    }
}

发送路由 key 为 error

消费消息-2:direct boot error

发送路由 key 为 info

消费消息-1:direct boot info
消费消息-2:direct boot info

Topic模型

Topic 类型的 ExchangeDirect相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型的Exchange可以让队列在绑定Routing key 的时候使用通配符!这种模型Routingkey 一般都是由一个或多个单词组成,多个单词之间以”.”分割,例如: user.insert image.png 统配符有两

* :匹配 1 个词

# : 匹配一个或多个词

如:

  • audit.# 匹配 audit.irs.corporate 或者 audit.irs 等
  • audit.* 只能匹配 audit.irs

1、开发生产者

@Test
void testTopic(){
    /**
     * 参数一:交换机名称
     * 参数二:路由名称
     * 参数三:消息内容
     *
     */
    rabbitTemplate.convertAndSend("topic-boot-exchange",
    "user.role.query","topic boot user.role.query");
}

2、开发消费者

import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class TopicCustomer {

@RabbitListener(bindings = {
        @QueueBinding(value = @Queue,
                exchange = @Exchange(value = "topic-boot-exchange",
                type = "topic"),
                key ={"user.*"})

})
public void topicStr(String message){
    System.out.println("消费消息-1:" + message);
}

@RabbitListener(bindings = {
        @QueueBinding(value = @Queue,
                exchange = @Exchange(value = "topic-boot-exchange",
                type = "topic"),
                key ={"user.#"})

})
public void topicStr2(String message){
    System.out.println("消费消息-2:" + message);
}
}

发送路由key为user.role.query

消费消息-2:topic boot user.role.query

发送路由key为user.query

消费消息-2:topic boot user.query
消费消息-1:topic boot user.query

  • 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞 + 收藏。