Spring boot 集成 RabbitMQ

438 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

SpringBoot官方集成了RabbitMQ,所以RabbitMQSpringBoot的集成是非常简单的。不过,SpringBoot集成RabbitMQ的方式是按照Spring的一套统一的MQ模型创建的,因此SpringBoot集成插件中对于生产者、消息、消费者等重要的对象模型,与RabbitMQ原生的各个组件有对应关系,但是并不完全相同。

引入依赖

SpringBoot官方集成了RabbitMQ,只需要快速引入依赖包即可使用。RabbitMQSpringBoot集成的核心maven依赖就下面一个。

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

要特别注意下版本。我们这里采用的是SpringBoot的2.7.0版本的依赖发布包。不同版本下的配置方式会有变化。

配置application.yml

spring:
  rabbitmq:
    host: 192.168.124.81
    port: 5672
    username: admin
    password: 123456
    virtual-host: /mirror
    listener:
      simple:
        # 消费者预处理值
        prefetch: 1
        # 消费者的消费线程数量
        concurrency: 5
        # 消费者的最大线程数量
        max-concurrency: 10
        # 消息确认方式:none 无,manual 手动,auto 自动,默认auto
        acknowledge-mode: none

然后所有的基础运行环境都在application.yml中进行配置。所有配置以spring.rabbitmq开头。通常按照示例进行一些基础的必要配置就可以运行。关于详细的配置信息,可以参见RabbitProperties,源码中有各个字段说明。

声明队列

所有的exchange, queue, binding的配置,都需要以对象的方式声明。默认情况下,这些业务对象一经声明,应用就会自动到RabbitMQ上常见对应的业务对象。但是也是可以配置成绑定已有业务对象的。

//声明队列
Queue q1 = new Queue(QUEUE_ANME);
//这种方式可以设置更多参数
Queue q2 = QueueBuilder.durable(QUEUE_NAME).build();


//声明Exchange,可声明交换机CustomExchange,DirectExchange,FanoutExchange,HeadersExchange,TopicExchange
DirectExchange directExchange = new DirectExchange(EXCHANGE_NAME);

//声明Binging
Binding binding = BindingBuilder.bind(q1).to(directExchange);

使用RabbitTemplate发送消息

生产者的所有属性都已经在application.yml配置文件中进行配置。项目启动时,就会在Spring容器中初始化一个RabbitTemplate对象,然后所有的发送消息操作都通过这个对象来进行。

@Autowired
private final RabbitTemplate rabbitTemplate;

public void helloWorld() {
    String message = "hello world";
    //发消息
    rabbitTemplate.send(QUEUE_NAME, new Message(message.getBytes(StandardCharsets.UTF_8)));
}

使用RabbitListener注解声明消费者

消费者都是通过@RabbitListener注解来声明。注解中包含了声明消费者队列时所需要的重点参数。对照原生API,这些参数就不难理解了。

但是当要消费Stream队列时,还是要重点注意他的三个必要的步骤:

  • channel必须设置basicQos属性。 channel对象可以在@RabbitListener声明的消费者方法中直接引用,Spring框架会进行注入。
  • 正确声明Stream队列。 通过往Spring容器中注入Queue对象的方式声明队列。在Queue对象中传入声明Stream队列所需要的参数。
  • 消费时需要指定offset。 可以通过注入Channel对象,使用原生API传入offset属性。

SpringBoot集成后的RabbitMQ中的很多概念,虽然都能跟原生API对应上,但是这些模型中间都是做了转换的,比如Message,就不是原生RabbitMQ中的消息了。

@RabbitListener(queues = QUEUE_NAME)
public void classicConsumer(String message) {
    log.info(QUEUE_NAME + " receive " + message);
}

关于Stream队列

在目前版本下,使用RabbitMQSpringBoot框架集成,可以正常声明Stream队列,往Stream队列发送消息,但是无法直接消费Stream队列了。

关于这个问题,还是需要从Stream队列的三个重点操作入手。SpringBoot框架集成RabbitMQ后,为了简化编程模型,就把channelconnection等这些关键对象给隐藏了,目前框架下,无法直接接入这些对象的注入过程,所以无法直接使用。

如果非要使用Stream队列,那么有两种方式,一种是使用原生API的方式,在SpringBoot框架下自行封装。另一种是使用RabbitMQStream 插件。在服务端通过Strem插件打开TCP连接接口,并配合单独提供的Stream客户端使用。这种方式对应用端的影响太重了,并且并没有提供与SpringBoot框架的集成,还需要自行完善,因此选择使用的企业还比较少。

其实关于Stream队列,现在也不需要着急上手,只是把他当作一种特殊的队列类型,上手了解即可。因为一方面太新的技术,往往还需要小白鼠多多验证。另一方面,现在RabbitMQ多种队列并存的状态,在不久肯定会得到简化,到时候,应用层的使用方式也肯定会跟着变化。