【RabbitMQ】基于Spring Boot + RabbitMQ 完成应用通信

文章目录

  • 需求描述
  • 创建项目
  • 订单系统(生产者)
    • 完善配置
    • 声明队列
    • 下单接口
    • 启动服务
  • 物流系统(消费者)
    • 完善配置
    • 监听队列
    • 启动服务
  • 格式化发送消息对象
    • SimpleMessageConverter
      • 定义一个对象
      • 生产者代码
      • 消费者
      • 运行程序
    • JSON
      • 定义一个对象
      • 生产者代码
      • 定义转换器
      • 消费者代码
      • 运行程序

需求描述

用户下单成功之后,通知物流系统,进行发货(只涉及到应用通信,不做具体功能实现)
image.png

  • 订单系统——生产者
  • 物流系统——消费者

创建项目

通常情况下,订单系统和物流系统是不同团队来开发的,是两个独立的应用

  • 为了方便演示,就把两个项目创建到一个文件夹下

image.png|291

  • 图标没有发生变化,启动类也没有被识别出来
    • 因为 Maven 没有被识别出来
    • 我们手动加入 Maven
      • 在项目目录中右键点击 pom.xml 文件,选择:Add as Maven Projectimage.png|191

订单系统(生产者)

完善配置

image.png

spring.application.name=order-service
server.port=8080  
#amqp://username:password@Ip:port/virtual-host  
spring.rabbitmq.addresses=amqp://order:order@127.0.0.1:5672/order

声明队列

package org.example.order.config;  import org.springframework.amqp.core.Queue;  
import org.springframework.amqp.core.QueueBuilder;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  @Configuration  
public class RabbitMQConfig {  // 使用简单模式来完成消息发送  @Bean  public Queue orderQueue(){  return QueueBuilder.durable("order.create").build();  }  
}

下单接口

package org.example.order.controller;  import org.springframework.amqp.rabbit.core.RabbitTemplate;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RestController;  import java.util.UUID;  @RequestMapping("/order")  
@RestController  
public class OrderController {  // 注入RabbitMQ的客户端  @Autowired  private RabbitTemplate rabbitTemplate;  // 下单的接口  @RequestMapping("/create")  public String create(){  // 参数校验、数据库保存等等...业务代码省略  // 发送消息  // 交换机、队列是什么routingKey就是什么、字符串信息  String orderId = UUID.randomUUID().toString();  rabbitTemplate.convertAndSend("", "order.create", "订单信息,订单ID: " + orderId);  return "下单成功";  }  
}
  • 下单成功之后,发送订单消息

启动服务

  1. 访问接口,模拟下单请求: http://127.0.0.1:8080/order/create

查看消息:image.png

物流系统(消费者)

RabbitMQ 中接收消息

完善配置

8080 端口号已经被订单系统占用了,修改物流系统的端口号为 9090

spring.application.name=logistics-service  
# 两边的端口号不能一样,他们是同时运行的  
server.port=9090  
#amqp://username:password@Ip:port/virtual-host  
spring.rabbitmq.addresses=amqp://guest:guest@127.0.0.1:5672/order

监听队列

package org.example.logistics.listener;  import org.springframework.amqp.rabbit.annotation.RabbitListener;  
import org.springframework.stereotype.Component;  @Component  
public class OrderListener {  @RabbitListener(queues = "order.create") // 指出需要监听的队列的名称  public void handMessage(String orderInfo) {  System.out.println("接收到订单消息: " + orderInfo);  // 收到消息后的处理,代码省略}  
}

启动服务

访问订单系统的接口,模拟下单请求: http://127.0.0.1:8080/order/create

在物流系统的日志中,可以观察到,通过 RabbitMQ,成功把下单信息传递给了物流系统image.png

格式化发送消息对象

如果通过 RabbitTemplate 发送⼀个对象作为消息, 我们需要对该对象进⾏序列化

SimpleMessageConverter

默认使用的是 SimpleMessageConverter 进行序列化

定义一个对象

package org.example.order.model;  import lombok.Data;  import java.io.Serializable;  @Data  
public class OrderInfo implements Serializable {  private String orderId;  private String name;  
}
  • 在发送消息的时候,信息需要经过 MessageConverter 进行转换 (默认是 SimpleMessageConverter)
  • SimpleMessageConverter 只支持 Stringbyte[]Serializable
  • 此接口将 OrderInfo 序列化,之后才能被正常接收 (OrderInfo 类型不被支持,会报 500 错误)

生产者代码

package org.example.order.controller;  import org.example.order.model.OrderInfo;  
import org.springframework.amqp.rabbit.core.RabbitTemplate;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RestController;  import java.util.Random;  
import java.util.UUID;  @RequestMapping("/order")  
@RestController  
public class OrderController {  // 注入RabbitMQ的客户端  @Autowired  private RabbitTemplate rabbitTemplate;  // 下单的接口  @RequestMapping("/create2")  public String create2(){  // 发送对象  OrderInfo orderInfo = new OrderInfo();  orderInfo.setOrderId(UUID.randomUUID().toString());  orderInfo.setName("商品" + new Random().nextInt(100));  rabbitTemplate.convertAndSend("", "order.create", orderInfo);  return "下单成功";  }  
}

消费者

package org.example.logistics.listener;  import org.example.order.model.OrderInfo;  
import org.springframework.amqp.rabbit.annotation.RabbitHandler;  
import org.springframework.amqp.rabbit.annotation.RabbitListener;  
import org.springframework.stereotype.Component;  @Component  
@RabbitListener(queues = "order.create") // 指出需要监听的队列的名称  
public class OrderListener {  @RabbitHandler  public void handMessage(String orderInfo) {  System.out.println("接收到订单消息String: " + orderInfo);  // 收到消息后的处理,代码省略  }  
}

运行程序

访问订单系统的接口,模拟下单请求: http://127.0.0.1:8080/order/create2

观察发送的消息image.png

  • 可以看到消息的可读性太差
  • 所以我们使用 JSON 序列化

JSON

使用 SimpleMessageConverter 序列化可读性太差,Spring AMQP 推荐使用 JSON 序列化

  • Spring AMQP 提供了 Jsckson2JsonMessageConverterMappingJackson2MessageConverter 等转换器
  • 我们需要把一个 MessageConverter 设置到 RabbitTemplate

定义一个对象

package org.example.order.model;  import lombok.Data;  @Data  
public class OrderInfo  {  private String orderId;  private String name;  
}

生产者代码

package org.example.order.controller;  import org.example.order.model.OrderInfo;  
import org.springframework.amqp.rabbit.core.RabbitTemplate;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RestController;  import java.util.Random;  
import java.util.UUID;  @RequestMapping("/order")  
@RestController  
public class OrderController {  // 注入RabbitMQ的客户端  @Autowired  private RabbitTemplate rabbitTemplate;  // 下单的接口  @RequestMapping("/create2")  public String create2(){  // 发送对象  OrderInfo orderInfo = new OrderInfo();  orderInfo.setOrderId(UUID.randomUUID().toString());  orderInfo.setName("商品" + new Random().nextInt(100));  rabbitTemplate.convertAndSend("", "order.create", orderInfo);  return "下单成功";  }  
}
  • 和前面的使用默认转换器代码一样

定义转换器

package org.example.order.config;  import org.springframework.amqp.core.Queue;  
import org.springframework.amqp.core.QueueBuilder;  
import org.springframework.amqp.rabbit.connection.ConnectionFactory;  
import org.springframework.amqp.rabbit.core.RabbitTemplate;  
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  @Configuration  
public class RabbitMQConfig {  // 使用简单模式来完成消息发送  @Bean  public Queue orderQueue(){  return QueueBuilder.durable("order.create").build();  }  /**  * 创建一个 rabbitTemplate 对象  * @return  */  @Bean  public Jackson2JsonMessageConverter jsonMessageConverter(){  return new Jackson2JsonMessageConverter();  }  @Bean  public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, Jackson2JsonMessageConverter jsonMessageConverter) {  RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);  rabbitTemplate.setMessageConverter(jsonMessageConverter);  return rabbitTemplate;  }  
}
  • 创建出一个 rabbitTemplate 对象进行使用
  • 生产者(order-service)和消费者(logistics-service)都需要
    • 不然还是拿不到消息

消费者代码

package org.example.logistics.listener;  import org.example.order.model.OrderInfo;  
import org.springframework.amqp.rabbit.annotation.RabbitHandler;  
import org.springframework.amqp.rabbit.annotation.RabbitListener;  
import org.springframework.stereotype.Component;  @Component  
@RabbitListener(queues = "order.create") // 指出需要监听的队列的名称  
public class OrderListener {  @RabbitHandler  public void handMessage2(OrderInfo orderInfo) {  System.out.println("接收到订单消息OrderInfo: " + orderInfo);  // 收到消息后的处理,代码省略  }  
}

@RabbitListener(queues = "order.create") 可以加在类上,也可以加在方法上,用于定义一个类或者方法作为消息的监听器
@RabbitHandler 是一个方法级别的注解,当使用 @RabbitHandler 注解时,这个方法将被调用处理特定的消息

  • 根据调用的类型,调用相关方法

运行程序

访问订单系统的接口,模拟下单请求: http://127.0.0.1:8080/order/create2

image.png

前面的 String 也还可以接收到,只要模拟下单请求: http://127.0.0.1:8080/order/create 即可image.png

  • 归功于 @RabbitHandler指哪打哪

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/81408.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenGL Chan视频学习-7 Writing a Shader inOpenGL

bilibili视频链接: 【最好的OpenGL教程之一】https://www.bilibili.com/video/BV1MJ411u7Bc?p5&vd_source44b77bde056381262ee55e448b9b1973 函数网站: docs.gl 说明: 1.之后就不再整理具体函数了,网站直接翻译会更直观也会…

Vue 3.0中复杂状态如何管理

在现代前端应用中,状态管理扮演着至关重要的角色。一个良好的状态管理方案能够: 1. 保持应用数据的一致性和可预测性; 2. 简化组件间的通信和数据共享; 3. 提高代码的可维护性和可测试性; 4. 优化应用性能&#xf…

AGI大模型(33):LangChain之Memory

大多数的 LLM 应用程序都会有一个会话接口,允许我们和 LLM 进行多轮的对话,并有一定的上下文记忆能力。但实际上,模型本身是不会记忆任何上下文的,只能依靠用户本身的输入去产生输出。而实现这个记忆功能,就需要额外的模块去保存我们和模型对话的上下文信息,然后在下一次…

leetcode513. 找树左下角的值:层序遍历中的深度与顺序控制之道

一、题目深度解析与核心诉求 在二叉树的众多问题中,寻找最深层最左节点的值是一个兼具趣味性与代表性的问题。题目要求我们在给定的二叉树中,找到深度最大的那一层中最左边的节点值。如果存在多个最深层,只需返回最左边节点的值即可。 这个…

制作一款打飞机游戏54:子弹编辑UI

今天,我们将继续工作在我们的子弹模式系统上,创建一些简单的子弹,并为其设计用户界面(UI)。 自动保存功能的重要性 首先,我想提一下自动保存功能。这个功能在编辑器中非常重要,因为我们经常犯…

线程封装与互斥

目录 线程互斥 进程线程间的互斥相关背景概念 互斥量mutex 互斥量的接口 初始化互斥量有两种方法: 销毁互斥量 互斥量加锁和解锁 改进售票系统 互斥量实现原理探究 互斥量的封装 线程互斥 进程线程间的互斥相关背景概念 临界资源:多线程执行流共…

【系统设计】2WTPS生产级数据处理系统设计Review

欢迎来到啾啾的博客🐱。 记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 有很多很多不足的地方,欢迎评论交流,感谢您的阅读与评论😄。 目录 反正能用的系统问题分析方案一:简单多…

历年北京理工大学保研上机真题

2025北京理工大学保研上机真题 2024北京理工大学保研上机真题 2023北京理工大学保研上机真题 在线测评链接:https://pgcode.cn/problem?classification1 判断身份证校验位是否正确 题目描述 给定一个身份证号码,判断其最后一位校验位是否正确。 如果…

uni-app学习笔记十--vu3综合练习

巩固提升前面学习的知识点,主要涉及下面这方面的运用: 1.v-for运用; 2.v-model双向绑定; 3.confirm确认事件; 4.click点击事件; 5.控制按钮的可点击和不可点击; 6.集合删除和追加元素,获取集合元素的…

AI时代新词-AI芯片(AI - Specific Chip)

一、什么是AI芯片? AI芯片(AI - Specific Chip)是指专为人工智能(AI)计算任务设计的芯片。与传统的通用处理器(如CPU)相比,AI芯片针对深度学习、机器学习等AI应用进行了优化&#x…

华为云Astro前端页面数据模型选型及绑定IoTDA物联网数据实施指南

目录 1. 选择合适的数据模型类型及推荐理由 自定义模型: 对象模型: 服务模型: 事件模型: 推荐方案: 2. 数据模型之间的逻辑关系说明 服务模型获取数据: 对象模型承接数据: 前端组件绑定显示: 数据保存与反馈(可选): (可选)事件模型实时更新: 小结 …

因重新安装python新版本,pycharm提示找不到python.exe(No Python at“c:\python.exe“)问题解决方法

1、安装新版本python后提示错误如下: 2、打开设置 3、添加Interpreter 4、配置程序的安装路径 5、问题完美解决。

一文带你彻底理清C 语言核心知识 与 面试高频考点:从栈溢出到指针 全面解析 附带笔者手写2.4k行代码加注释

引言:C 语言的魅力与挑战 从操作系统内核到嵌入式系统,从高性能计算到网络编程,C 语言高效、灵活和贴近硬件的特性,始终占据着不可替代的地位。然而,C 语言的强大也伴随着较高的学习曲线,尤其是指针、内存管…

GitHub 趋势日报 (2025年05月22日)

本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1microsoft/WSLLinux的Windows子系统⭐ 2524⭐ 26627C2HeyPuter/puter&#x1…

AI智能混剪核心技术解析(一):字幕与标题生成的三大支柱-字幕与标题生成-优雅草卓伊凡

AI智能混剪核心技术解析(一):字幕与标题生成的三大支柱-字幕与标题生成-优雅草卓伊凡 引言:文字到画面的桥梁工程 在AI视频混剪系统中,字幕与标题生成是连接语言表达与视觉呈现的核心枢纽。优雅草卓伊凡团队将该功能拆…

如何通过PHPMyadmin对MYSQL数据库进行管理?

管理MySQL数据库时,使用PHPMyAdmin是一种常见且方便的方式。PHPMyAdmin是一个基于Web的数据库管理工具,提供了许多功能,如数据库创建、表管理、数据查询、用户权限设置等。本文将介绍如何通过PHPMyAdmin对MySQL数据库进行管理,包括…

如何解决大模型返回的JSON数据前后加上```的情况

环境说明 springboot 应用使用dashscope-sdk-java对接阿里百练 deepseek v3模型 问题表现 已经指定了输出json格式,但指令不明确,输出JSON格式的写法如下 注:提示词一开始是能正常功能的,但过了几天就出现了异常,原…

uniapp实现H5、APP、微信小程序播放.m3u8监控视频

目录 1.APP播放.m3u8监控视频 2.H5播放.m3u8监控视频 3.微信小程序播放.m3u8监控视频 最近在写一个uniapp实现h5、app、微信小程序兼容三端的播放监控视频功能,我原本以为一套代码多处运行,但事实并非如此,h5可以运行,微信小程…

萤石云实际视频实时接入(生产环境)

萤石云视频接入 本示例可用于实际接入萤石云开放平台视频,同时支持音频输入和输出。 实际优化内容 1.动态获取token 2.切换各公司和车间时,自动重新初始化播放器 let EZUIKit null; // 第三方库引用 let EZUIKitPlayers []; // 播放器实例数组 le…

【Dify平台】使用Dify API 实现网页内嵌式AI助手

使用 Dify API 实现网页内嵌式 AI 助手 一. 引言二. Dify API 概述三. 实现网页内嵌式 AI 助手的技术架构四. 前端实现五. 后端实现六. 功能扩展与优化七. 测试与部署一. 引言 随着 AI 技术的不断发展,越来越多的企业希望将智能助手集成到自己的网页中,实现用户自动接待、问…