RabbitMQ的两个简单示例

在实际应用中,消息队列常用于实现异步通信和解耦。例如,当商品上架时,将商品信息发送到消息队列,并由消费者处理这些消息。这可以用来完成各种任务,如更新库存、通知用户或记录日志等。

下面是一个详细的简单收发的示例,展示了如何在商品上架时使用 RabbitMQ 发送消息,包括生产者和消费者的实现。

步骤概述

  1. 添加 Maven 依赖。
  2. 配置 RabbitMQ。
  3. 实现生产者:当商品上架时发送消息。
  4. 实现消费者:从队列中接收并处理消息。

1. 添加 Maven 依赖

pom.xml 文件中添加 RabbitMQ 客户端依赖:

<dependencies>
    <!-- RabbitMQ Java client -->
    <dependency>
        <groupId>com.rabbitmq</groupId>
        <artifactId>amqp-client</artifactId>
        <version>5.12.0</version>
    </dependency>
    <!-- SLF4J for logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.30</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.30</version>
    </dependency>
</dependencies>

2. RabbitMQ 配置

application.ymlapplication.properties 中配置 RabbitMQ 连接属性(可选)。

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

3. 实现生产者

商品上架事件类

首先定义一个商品上架事件类,用于传递商品信息:

public class Product {
    private String id;
    private String name;
    private double price;

    // Constructors, Getters, Setters

    public Product(String id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Product{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}
生产者类

实现一个生产者类,当有商品上架时发送消息到 RabbitMQ:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ProductProducer {

    private final static String EXCHANGE_NAME = "product_exchange";
    private final static String ROUTING_KEY = "product.add";

    public static void main(String[] argv) throws Exception {
        // 创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");

        // 创建连接和频道
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {
            // 声明交换机
            channel.exchangeDeclare(EXCHANGE_NAME, "topic");

            // 创建商品并发送上架消息
            Product product = new Product("123", "Laptop", 1200.00);
            String message = new ObjectMapper().writeValueAsString(product);

            // 发送消息到交换机
            channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, null, message.getBytes());
            System.out.println(" [x] Sent '" + message + "'");
        }
    }
}

4. 实现消费者

消费者从 RabbitMQ 队列中接收并处理消息:

import com.rabbitmq.client.*;

public class ProductConsumer {

    private final static String QUEUE_NAME = "product_queue";
    private final static String EXCHANGE_NAME = "product_exchange";
    private final static String ROUTING_KEY = "product.add";

    public static void main(String[] argv) throws Exception {
        // 创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");

        // 创建连接和频道
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {
            // 声明队列
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);
            // 绑定队列到交换机
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);

            System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

            // 回调方法,当有消息到达时调用
            DeliverCallback deliverCallback = (consumerTag, delivery) -> {
                String message = new String(delivery.getBody(), "UTF-8");
                System.out.println(" [x] Received '" + message + "'");
                // 可以在这里处理接收到的消息,例如更新库存、通知用户等
            };
            channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
        }
    }
}

解释

  1. Exchange 和 Routing Key:使用交换机(EXCHANGE_NAME)和路由键(ROUTING_KEY)将消息从生产者发送到指定队列。

  2. ObjectMapper:使用 Jackson 的 ObjectMapper 将商品对象序列化为 JSON 字符串,在发送和接收消息时进行转换。

  3. Queue 和 Binding:在消费者中声明队列并将其绑定到交换机,确保能够收到相应的消息。

测试

  1. 启动 RabbitMQ 服务,你可以使用 Docker 启动:

    docker run -d --hostname my-rabbit --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
    
  2. 启动消费者。

  3. 启动生产者,上架商品并发送消息。

消费者将会接收到来自生产者的消息,并在控制台进行打印:

[*] Waiting for messages. To exit press CTRL+C
[x] Received '{"id":"123","name":"Laptop","price":1200.0}'

通过这种方式,可以将商品上架的事件异步发送到 RabbitMQ 消息队列进行处理,从而实现系统之间的解耦和异步通信。

另外RabbitMQ 还能实现延时消费的功能。如实现订单过期未付款的处理示例,可以用RabbitMQ的延时队列或者死信队列(Dead-Letter Queue,简称DLQ)功能。下面是一个详细的示例,展示了如何使用RabbitMQ创建一个延时队列来处理订单过期未付款的情况。

思路概述

  1. 创建一个普通队列,用于接收订单创建的消息。
  2. 创建一个死信交换机和死信队列,用于接收延时队列中未被及时处理的消息,即过期未付款的订单。
  3. 在普通队列中设置消息的TTL(Time to Live)。
  4. 当消息在普通队列中超时后,会被转发到死信队列。

实现生产者

订单类

首先定义一个订单类,用于传递订单信息:

public class Order {
    private String orderId;
    private String product;
    private double amount;

    // Constructors, Getters, Setters

    public Order(String orderId, String product, double amount) {
        this.orderId = orderId;
        this.product = product;
        this.amount = amount;
    }

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public double getAmount() {
        return amount;
    }

    public void setAmount(double amount) {
        this.amount = amount;
    }

    @Override
    public String toString() {
        return "Order{" +
                "orderId='" + orderId + '\'' +
                ", product='" + product + '\'' +
                ", amount=" + amount +
                '}';
    }
}
生产者类

实现一个生产者类,当有新订单创建时发送消息到RabbitMQ:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.HashMap;
import java.util.Map;

public class OrderProducer {

    private final static String EXCHANGE_NAME = "order_exchange";
    private final static String QUEUE_NAME = "order_queue";
    private final static String DLX_EXCHANGE_NAME = "dlx_order_exchange";
    private final static String DLX_QUEUE_NAME = "dlx_order_queue";

    public static void main(String[] args) throws Exception {
        // 创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");

        // 创建连接和频道
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {

            // 声明死信交换机和死信队列
            channel.exchangeDeclare(DLX_EXCHANGE_NAME, "direct");
            channel.queueDeclare(DLX_QUEUE_NAME, false, false, false, null);
            channel.queueBind(DLX_QUEUE_NAME, DLX_EXCHANGE_NAME, "dlx_order");

            // 声明交换机和队列,并设置生存时间和死信交换机
            Map<String, Object> argsMap = new HashMap<>();
            argsMap.put("x-message-ttl", 60000); // 设置消息TTL为60秒
            argsMap.put("x-dead-letter-exchange", DLX_EXCHANGE_NAME); // 设置死信交换机
            argsMap.put("x-dead-letter-routing-key", "dlx_order");

            channel.exchangeDeclare(EXCHANGE_NAME, "direct");
            channel.queueDeclare(QUEUE_NAME, false, false, false, argsMap);
            channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "order");

            // 创建订单并发送消息到普通队列
            Order order = new Order("123", "Laptop", 1200.00);
            String message = new ObjectMapper().writeValueAsString(order);

            // 发送消息到交换机
            channel.basicPublish(EXCHANGE_NAME, "order", null, message.getBytes());
            System.out.println(" [x] Sent '" + message + "'");
        }
    }
}

实现消费者

消费者从死信队列中接收并处理过期未付款的订单:

import com.rabbitmq.client.*;
import com.fasterxml.jackson.databind.ObjectMapper;

public class OrderConsumer {

    private final static String DLX_QUEUE_NAME = "dlx_order_queue";

    public static void main(String[] argv) throws Exception {
        // 创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        factory.setPort(5672);
        factory.setUsername("guest");
        factory.setPassword("guest");

        // 创建连接和频道
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {

            System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

            // 回调方法,当有消息到达时调用
            DeliverCallback deliverCallback = (consumerTag, delivery) -> {
                String message = new String(delivery.getBody(), "UTF-8");

                // 反序列化消息内容
                ObjectMapper objectMapper = new ObjectMapper();
                Order order = objectMapper.readValue(message, Order.class);

                System.out.println(" [x] Received '" + order + "'");
                // 处理过期未付款的订单,例如取消订单、通知用户等
                handleExpiredOrder(order);
            };

            channel.basicConsume(DLX_QUEUE_NAME, true, deliverCallback, consumerTag -> { });
        }
    }

    // 模拟处理过期未付款的订单
    private static void handleExpiredOrder(Order order) {
        System.out.println("Handling expired order: " + order.getOrderId());
        // 这里可以添加取消订单、通知用户等逻辑
    }
}

解释

  1. 交换机和死信机制

    • 创建了一个普通队列 order_queue,并为其设置了TTL(Time to Live)属性。
    • 当消息在普通队列中超时后,会转发到死信队列 dlx_order_queue 中进行处理。
  2. 生产者发送消息

    • 将订单消息发送到普通交换机 order_exchange,通过路由键 order 转发到普通队列 order_queue
    • 设置消息TTL为60秒,即消息在队列中存活60秒后,如果没有被消费,会转发到死信队列。
  3. 消费者处理消息

    • 消费者从死信队列 dlx_order_queue 中接收过期未付款的订单。
    • 反序列化订单消息,并在控制台输出并处理。

测试

  1. 启动RabbitMQ服务,可以使用Docker进行启动:

    docker run -d --hostname my-rabbit --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
    
  2. 启动消费者。

  3. 启动生产者,创建订单并发送消息。

消费者将会在消息TTL过期后,从死信队列中接收到过期未付款的订单,并在控制台进行日志输出:

[*] Waiting for messages. To exit press CTRL+C
[x] Received 'Order{orderId='123', product='Laptop', amount=1200.0}'
Handling expired order: 123

通过这种方式,可以有效地管理和处理订单过期未付款的情况。

  • 19
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用 Java 实现 RabbitMQ 发送两个数字的示例代码: ```java import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import java.io.IOException; import java.util.concurrent.TimeoutException; public class RabbitMQSender { private static final String QUEUE_NAME = "numbers_queue"; public static void main(String[] args) throws IOException, TimeoutException { // 创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); factory.setUsername("guest"); factory.setPassword("guest"); // 创建连接 Connection connection = factory.newConnection(); // 创建通道 Channel channel = connection.createChannel(); // 声明队列 channel.queueDeclare(QUEUE_NAME, false, false, false, null); // 发送消息 int num1 = 10; int num2 = 20; String message = num1 + "," + num2; channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8")); System.out.println(" [x] Sent '" + message + "'"); // 关闭通道和连接 channel.close(); connection.close(); } } ``` 在上面的示例中,我们创建了一个名为 "numbers_queue" 的队列,并向队列发送了两个数字 10 和 20。我们把这两个数字连接成一个字符串 "10,20",然后将其转换为字节数组并发送到队列中。 注意,在实际应用中,我们需要根据具体需求为队列设置更多的参数,例如持久化、自动删除等。同时,我们还需要为队列设置消费者,以便从队列中获取数据并进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值