RabbitMQ 相关整合实战项目(完结)

本文详细介绍了如何使用RabbitMQ整合PD商城项目,实现订单流量削峰,解耦应用。通过SpringBoot整合RabbitMQ,创建生产者与消费者,进行消息的发送和接收,包括简单模式、工作模式、发布/订阅模式、路由模式和主题模式的测试。还涵盖了RPC模式的源码测试,涉及Client、Server和Blocking Queue的实现。
摘要由CSDN通过智能技术生成

RabbitMQ 整合 PD 商城实战项目流程总结

一、订单流量削峰(解耦)

简单模式,若多添加几个消费者则用工作模式。

导入商城项目

将 step5 课前资料里面 /elasticsearch/pd商城.zip 解压。

第二层目录下 pd-web 文件夹解压到 rabbitmq 工程目录下面。

在这里插入图片描述

修改 pom.xml 文件中的 SpringBoot 版本为 2.3.2.RELEASE(可拖拽至 idea 内更改)。

在这里插入图片描述

在 rabbitmq 工程中导入模块(若之前在 idea 内更改则可以直接右键 Add As Maven 导入)。
或者打开工程结构 Project Structures 手动添加也可。

使用 sqlyog 导入项目目录中的 pd.sql:

在这里插入图片描述

右键复制脚本文件的路径,在 sqlyog 里面右键连接,从 SQL 转储文件导入数据库。

如果导入失败,可以增大 mysql 缓存区
set global max_allowed_packet=100000000;
set global net_buffer_length=100000;
SET GLOBAL  interactive_timeout=28800000;
SET GLOBAL  wait_timeout=28800000

因为大环境变化,MySQL 5.5 以下版本的用起来会很费劲,请至少更新至5.7。MariaDB 要 10.4 以上。

确认工程 JDK 的配置(吐槽:坑爹的涛哥这里准备的项目是 GBK 编码的,属实难顶)。

在这里插入图片描述

为了本项目的运行,首先将数据库 pd_store 的 user、order、order_item 表清空:

delete from pd_user
delete from pd_order
delete from pd_order_item

找到主启动类 RunPdApp ,运行,然后更改启动配置中的工作目录为本项目,改完重新启动。

在这里插入图片描述

打开 localhost 进入模拟拼多商城,注册一个新用户(随意填写,注意格式即可)。

在这里插入图片描述

注册成功以后,点击地址管理,添加一个收货地址(只填必填项即可)。

在这里插入图片描述

返回起始页,选择一个商品,加入购物车并下订单(无需支付,订单会添加到数据库内)。

在这里插入图片描述

查看数据库是否正确存储数据。

在这里插入图片描述

生产者 - 发送订单

修改订单,把订单发送到 rabbitmq

返回 pd-web 项目,打开 service 下的 OrderServiceImpl 实现类,注释掉 64-89 行关于数据库操作的代码。这里是为了不直接操作数据库,而是发送到 rabbitmq 以后再继续操作。

pom.xml 添加 rabbitmq 依赖。

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

application.yml 添加 rabbitmq 连接。

spring:  
  rabbitmq:
    host: 192.168.64.140  # wht6.cn
    port: 5672
    username: admin
    password: admin
    # virtual-host: 自己的空间名

启动类(或者新建自动配置类)

  • 提供使用的队列参数:
    orderQueue,持久队列(订单不能丢),不独占(并行处理效率高),不自动删除。

  • 创建 spring 的 Queue 对象,用来封装队列的参数。RabbitAutoConfiguration 自动配置类,会自动发现 Queue 实例,使用这里的参数,连接服务器在服务器上创建队列。
    1)通过方法创建一个 Queue 队列,注意引包要用 amqp 核心包。
    import org.springframework.amqp.core.Queue
    2)直接返回一个 Queue 对象,参数为上述参数(队列名,true,false,false)。
    3)最后将方法交给 Spring 容器管理。

package com.pd;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.amqp.core.Queue;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@MapperScan("com.pd.mapper")
public class RunPdAPP{
   
	
	public static void main(String[] args) {
   
		SpringApplication.run(RunPdAPP.class, args);
	}

	@Bean
	public Queue orderQueue(){
   
		return new Queue("orderQueue",true,false,false);
	}
}

修改 OrderServiceImpl,向 Rabbitmq 发送订单。

  • saveOrder 方法上添加自动注入 AmqpTemplate 对象,该对象为 Spring 提供的用来发送消息的工具对象。

  • 在注释的方法里,要求将 pdOrder 发送到 orderQueue 队列: t.convertAndSend("orderQueue",pdOrder);

  • 这里的 convertAndSend 方法是转换并发送,先转成 byte[],再发送,订单对象会被自动序列化成 byte[]。

在这里插入图片描述

重启启动类,重新下订单进行测试:

  • 下订单以后,会发现数据库里没有新订单。
    此时查看 Rabbitmq 服务器,在 orderQueue 队列会发现有一条就绪的消息。
    点开 orderQueue 队列,查看下方的 Get messages 会有很长的一串代码(消息):

在这里插入图片描述

有消息即可。

订单 - 消费者

1.找到项目目录,复制一份 pd-web 起名为 pd-web-consumer 作为消费者端。

2.修改 pom.xml 文件:

  • 将 artifactId 改为 pd-web-consumer(可直接拖拽 pom 文件至 idea)。

在这里插入图片描述

3.修改 application.yml 文件:

  • 因为之前的生产者端已经占用了 80 端口,所以这里将 server.port 改为 81。

4.添加依赖、添加连接、队列参数:前面做过了所以省略。

5.新建消费者类(OrderConsumer),从 orderQueue 接收消息:

  • 在 pd 包内创建 OrderConsumer 类。

  • 添加 @Component 注解自动创建实例,添加 @RabbitListener 注解指定接收消息的队列。

  • 在接收订单时,需要调用 OrderService 对象来接收,因此添加自动注入 OrderService 对象。

  • 创建 receive 方法,参数为 PdOrder 对象,并添加 @RabbitHandler 注解。

    @RabbitHandler 注解是用来配合 @RabbitListener 注解的。

    因此指定处理消息的方法的类中,只能有一个 @RabbitHandler 注解。

6.调用原来的业务代码,存储订单

  • 通过 OrderService 对象调用 saveOrder 方法接收订单,最后输出提示 “订单已存储” 。
  • Spring 会自动创建实例,自动启动消费者,自动开始从队列获取消息,自动执行处理消息的方法。
package com.pd;

import com.pd.pojo.PdOrder;
import com.pd.service.OrderService;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "orderQueue")
public class OrderConsumer {
   

    @Autowired
    private OrderService orderService;
    @RabbitHandler
    public void receive(PdOrder pdOrder) throws Exception {
   
        orderService.saveOrder(pdOrder);
        System.out.println("-----------------------------------订单已存储!wow!");
    }
}

7.修改 OrderServiceImpl,还原成原来的数据库操作的代码即可。

  • 将注入的 AmqpTemplate 对象删掉,saveOrder 前面自动序列化的代码也删掉,数据库注释部分还原。

  • 因为之前的是随机生成的 orderId,现在因为前面已经获取了 PdOrder 的对象。

    所以直接添加一行代码:获取 pdOrder 的 orderId。
    String orderId = pdOrder.getOrderId();

8.消息传递测试:

  • 由于之前发送的订单对象需要序列化,所以这里需要重新下一个订单来测试传递。
  • 重新下完订单以后,启动 81 端口的 RunPdApp 服务,消息会自动传递到消费者这里。
  • 控制台显示 “订单已存储” 即可。

在这里插入图片描述

9.合理分发相关:

  • ack – spring 封装的 rabbitmq,已经是手动 ack 模式了,spring 会自动发送回执。

  • qos=1 – spring 默认设置的 qos 是250,yml 中 可以添加 prefetch = 1 把 qos 设置成 1。

spring:  
  rabbitmq:  
	listener:
      simple:
        prefetch: 1

10.持久化相关:

队列持久化参数设定为 true;

生产者发送的消息默认是持久消息(即生产者利用 AmqpTemplate 调用 convertAndSend 的方法)。

二、SpringBoot 整合 RabbitMQ

创建项目

  • 在 rabbitmq 目录下创建 SpringBoot 工程模块:rabbitmq-spring,只添加 rabbitmq 依赖即可。

  • 修改 pom.xml 文件:Spring Boot 版本改为 2.3.2.RELEASE

  • 修改 application.yml 文件:添加 rabbitmq 连接

    spring:
      rabbitmq:
        host: 192.168.64.140  # wht6.cn
        port: 5672
        username: admin
        password: admin
        # virtual-host:你的空间名
    

项目结构

  • 创建结构和之前类似,虽然项目为我们自动创建了一个启动类(RabbitmqSpringApplication),但是我们想同时启动多个模式下的生产者和消费者时会起冲突,因此为了方便测试运行我们每个包内单独创建一个启动类(Main)来运行该包下的测试程序。
  • 分别创建 m1/m2/m3/m4/m5 包,目录下创建 Main 启动类、Producer 生产者类和 Consumer 消费者类。

简单模式测试(M1)

M1 项目为默认模式的测试,即只有一个消费者使用一个队列接收一个生产者的模式。

Producer 类

首先我们完成生产者类,生产者类负责向某个队列发送消息,通过对象转换并发送自己想发送的信息。

  • 添加 @Component 注解自动创建实例。

  • 自动注入 AmqpTemplate 对象。

  • 自定义一个发送方法(send),用 AmqpTemplate 对象调用 convertAndSend 方法将信息发送。

    方法参数为:( 队列名,具体信息内容 )这里该方法会自动转换字符串内容。

  • 这里同意规定测试队列名为 ”helloworld“,发送信息随意。

package cn.tedu.rabbitmqspring.m1;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Producer {
   
    @Autowired
    private AmqpTemplate t;

    public void send(){
   
        t.convertAndSend("helloworld","Hello-THE-FKING-World");
    }
}

Consumer 类

  • 添加 @Component 注解自动创建实例。

  • 通常我们在消费者端写接收方法时会在类上添加 @RabbitListener 注解,并在接收方法上添加 @RabbitHandler 注解来配合。

    这里我们选择直接在方法上添加 @RabbitListener 注解来表示接收。

    每个 @RabbitListener 注解,都会注册启动一个消费者。

    直接加在方法上面表示该队列只有这一个方法用来接收。

    这样做的好处是接收代码可以集中,维护起来更加方便。

  • 自定义一个接收方法(receive),上面通过 @RabbitListener 注解限定接收的队列。

    方法参数为 String 对象(发送过来的数据),并输出 “收到: ” + 内容。

package cn.tedu.rabbitmqspring.m1;

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

@Component
public class Consumer {
   
    @RabbitListener(queues = "helloworld")
    public void receive(String str){
   
        System.out.println("收到: "+str);
    }
}

Main 启动类

  • 完成 Spring 启动类的基本配置。

  • 创建一个 Queue 实例,封装队列参数:

    定义一个方法(helloWorldQueue),返回 Queue 队列,该队列设定为非持久队列,并交给容器管理。

  • 添加测试代码,调用生产者发送消息:

    为了调用生产者,所以进行 Producer 的注入。

    定义测试方法(test),利用 Producer 对象调用 send 方法发送信息。

    这里可以添加 @PostConstruct 注解,该注解用于初始化资源,可以事先将这些文件加载到内存里,需要时直接从内存调用。

  • spring 的执行流程:
    包扫描创建所有实例 --> 完成所有依赖的注入 --> @PostConstruct --> 后续流程

  • 这里执行代码时,自动配置类有可能还没有创建队列,消费者可能也还没有启动第一次,执行可能丢失信息。

package cn.tedu.rabbitmqspring.m1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import javax.annotation.PostConstruct;

@SpringBootApplication
public class Main {
   
    public static void main(
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值