消息队列专题(实战篇):SpringBoot 集成 RabbitMQ 入门级实战

最近的学习劲头越来越足了,昨晚刚写完了 RabbitMQ 介绍与环境搭建篇,今天就开始更新实战篇了,想起原来同事对我的形容:生产队的驴都没你勤快,哈哈哈哈哈哈,说得可真对!

言归正传,本篇博客参考了慕课网的 RabbitMQ 课程,在此基础上进行了简化,提供了一个最简单的无存储功能的消息队列实现,课程链接如下,感兴趣的小伙伴可自行进行学习:

https://www.imooc.com/video/17845


配置消息队列

打开并登录消息队列的管理界面,首先来配置 exchange:
消息队列专题(实战篇):SpringBoot 集成 RabbitMQ 入门级实战_第1张图片
图中有三个参数,分别是 exchange 的名称,类型和是否持久化。

之后配置队列:
消息队列专题(实战篇):SpringBoot 集成 RabbitMQ 入门级实战_第2张图片
最后来配置 exchange 和 queue 之间的绑定:
消息队列专题(实战篇):SpringBoot 集成 RabbitMQ 入门级实战_第3张图片
完成基本配置之后,就可以开始写代码了。


我们知道,在消息队列中,生产者是消息的提供方,消费者是消息的消费方,所以我们需要创建两个项目,分别是 生产者项目 rabbitmq-producer消费者项目 rabbitmq-consumer

创建生产者项目

生产者项目 rabbitmq-producer 目录结构如下:
消息队列专题(实战篇):SpringBoot 集成 RabbitMQ 入门级实战_第4张图片
1. 创建项目结构

在 java 文件夹下新建 com.rabbitmq 包,然后在包中建立子包:

entity:用于存放实体对象;
producer:用于实现生产者生产消息的服务;

2. 引入依赖和配置

需要添加的依赖项:


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>org.examplegroupId>
    <artifactId>rabbitmq-producerartifactId>
    <version>1.0-SNAPSHOTversion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.1.5.RELEASEversion>
        <relativePath/> 
    parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starterartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-amqpartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        
        <dependency>
            <groupId>org.apache.commonsgroupId>
            <artifactId>commons-lang3artifactId>
            <version>3.8.1version>
        dependency>
        <dependency>
            <groupId>commons-iogroupId>
            <artifactId>commons-ioartifactId>
            <version>2.4version>
        dependency>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>fastjsonartifactId>
            <version>1.2.49version>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>

project>

系统配置:

server:
  servlet:
    context-path: /
  port: 8605
spring:
  application:
    name: rabbitmq-producer
  rabbitmq:
    host: 服务器IP
    port: 5672
    username: admin
    password: admin
    virtual-host: /
    publisher-confirms: true #confirm模式
    publisher-returns: true #return机制
    template:
      mandatory: true #与return机制结合配置次属性
    connection-timeout: 5000

3. 创建实体类

Order.java

package com.rabbitmq.entity;

import java.io.Serializable;

// 订单实体类
public class Order implements Serializable {
    // 订单id
    private String id;
    // 订单编号
    private String code;
    // 消息发送的唯一标识id
    private String messageId;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessageId() {
        return messageId;
    }

    public void setMessageId(String messageId) {
        this.messageId = messageId;
    }
}

由于消息队列中的消息需要在网络中传输,所以这个实体类必须实现序列化接口;

4.创建生产消息服务类

OrderSender.java

package com.rabbitmq.producer;

import com.rabbitmq.entity.Order;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class OrderSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendOrder(Order order) throws Exception{
        CorrelationData correlationData = new CorrelationData();
        correlationData.setId(order.getMessageId());
        rabbitTemplate.convertAndSend("order-exchange","order.abcd", order, correlationData);
    }
}

这个类是非常重要的,通过自动注入用于操作消息队列的模板实例,调用它的 convertAndSend 方法进行消息的发送。

这里的 order-exchange 是我们提前设置好的 exchange 名称,order.abcd 可以匹配上我们设置的 Routing Key,可以写个测试用例来测试下消息的发布。

5.测试消息发布

在 test 包中新建子包,新增开发类 ApplicationTest.java:
消息队列专题(实战篇):SpringBoot 集成 RabbitMQ 入门级实战_第5张图片
ApplicationTest.java

package com.rabbitmq;

import com.rabbitmq.entity.Order;
import com.rabbitmq.producer.OrderSender;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.UUID;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTest {
    @Autowired
    OrderSender orderSender;

    @Test
    public void test() throws Exception {
        Order order = new Order();
        order.setId("1");
        order.setCode("订单编号001");
        order.setMessageId(System.currentTimeMillis() + "_" + UUID.randomUUID());
        orderSender.sendOrder(order);
    }

}

测试类的代码非常简单,就是新建一个订单并设置属性,之后调用消息发布方法将消息存储到消息队列。

测试通过后,此时在管理面板可以查看到消息队列里面出现了一条未消费消息:
消息队列专题(实战篇):SpringBoot 集成 RabbitMQ 入门级实战_第6张图片
既然消息队列里面已经有了消息,接下来我们来开发消费者项目进行消费。


创建消费者项目

新建消费者项目 rabbitmq-consumer,结构如下:
消息队列专题(实战篇):SpringBoot 集成 RabbitMQ 入门级实战_第7张图片
其中的实体类 Order.java 保持不变,但是需要修改配置文件。

1.修改配置文件

pom.xml 和生产者项目相比,需要修改端口号并新增配置项:
消息队列专题(实战篇):SpringBoot 集成 RabbitMQ 入门级实战_第8张图片
新增配置项如下:

	listener:
      simple:
        concurrency: 5 #初始并发数
        max-concurrency: 10 #最大并发数
        acknowledge-mode: manual #手动签收模式
        prefetch: 1 #限流处理(同一时间只能有一条消息,消费完了才能处理下一条)

2.开发消息消费类

OrderConsumer.java

package com.rabbitmq.consumer;

import com.rabbitmq.client.Channel;
import com.rabbitmq.entity.Order;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Map;

@Component
public class OrderConsumer {

    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(value = "order-queue", durable = "true"),
                    exchange = @Exchange(name = "order-exchange", durable = "true", type = "topic"),
                    key = "order.#"
            )
    )
    @RabbitHandler
    public void onOrderMessage(@Payload Order order, @Headers Map<String, Object> headers, Channel channel) throws IOException {
        // 消费者进行消费操作
        System.out.println("-------------收到消息,开始消费------------");
        System.out.println("订单编号为:" + order.getCode());
        Long deliverTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
        // 由于我们开启了手动确认,所以这里消费者必须进行确认操作
        channel.basicAck(deliverTag,false);
    }
}

我们之前在配置文件里面配置了手动确认消息,所以需要传入一个 Channel 类型的对象去进行确认,一定要注意这个 Channel 并不是 NIO 中的,而是 com.rabbitmq.client 包下的,不要搞错。

在处理完成正常的业务逻辑后,需要进行手动确认:

channel.basicAck(deliverTag,false);

还有一个需要注意的地方是,@RabbitListener 不止实现了消费者和对应的消息队列、exchange 以及路由关键字的绑定,同时还具有默认创建的功能。也就是说,如果我们之前没有提前在控制台手动创建 exchange,queue,routing key,代码可以自动为我们创建。

3.运行程序进行消息消费

运行消费者项目,可以看到输出了消息消费的记录:
消息队列专题(实战篇):SpringBoot 集成 RabbitMQ 入门级实战_第9张图片
查看控制台界面,发现消息队列中的消息已经被消费了:
消息队列专题(实战篇):SpringBoot 集成 RabbitMQ 入门级实战_第10张图片
至此,一个最简单的消息队列实战就完成了,不过在实际生产环境中,这样的实现是远远不够的,我们还需要考虑消息的可靠性投递与消费,以及保证传输过程的可靠性,不然消息丢了可是要被祭天的,今天写不动了,下一篇博客再见!

你可能感兴趣的:(消息队列,消息队列,实战,rabbitmq)