Java学习第17天 - 消息队列与异步处理

学习时间: 4-5小时
学习目标: 掌握消息队列的使用,学会使用RabbitMQ和Kafka,理解异步处理模式


详细学习清单


✅ 第一部分:消息队列基础概念(60分钟)

1. 消息队列的作用与优势

消息队列基础分析

java 复制代码
// MessageQueueBasics.java
package com.example.demo.messagequeue;

import java.util.ArrayList;
import java.util.List;

public class MessageQueueBasics {
    
    public static class QueueAdvantage {
        private String name;
        private String description;
        private String example;
        private String benefit;
        
        public QueueAdvantage(String name, String description, String example, String benefit) {
            this.name = name;
            this.description = description;
            this.example = example;
            this.benefit = benefit;
        }
        
        // Getter方法
        public String getName() { return name; }
        public String getDescription() { return description; }
        public String getExample() { return example; }
        public String getBenefit() { return benefit; }
    }
    
    public static void main(String[] args) {
        List<QueueAdvantage> advantages = new ArrayList<>();
        
        // 异步处理
        advantages.add(new QueueAdvantage(
            "异步处理",
            "发送方不需要等待接收方处理完成",
            "用户下单后立即返回成功,库存扣减在后台异步进行",
            "提高系统响应速度,改善用户体验"
        ));
        
        // 解耦服务
        advantages.add(new QueueAdvantage(
            "服务解耦",
            "服务间通过消息通信,不直接依赖",
            "订单服务发送消息,库存服务、支付服务独立消费",
            "降低系统耦合度,便于独立开发和部署"
        ));
        
        // 流量削峰
        advantages.add(new QueueAdvantage(
            "流量削峰",
            "突发流量通过队列缓冲,平滑处理",
            "双11秒杀活动,大量请求进入队列,系统按能力处理",
            "保护系统稳定性,避免过载崩溃"
        ));
        
        // 可靠性保证
        advantages.add(new QueueAdvantage(
            "可靠性保证",
            "消息持久化,确保不丢失",
            "支付成功后发送通知,即使系统重启也能保证通知发送",
            "提高系统可靠性,保证数据完整性"
        ));
        
        System.out.println("=== 消息队列主要优势 ===");
        for (QueueAdvantage advantage : advantages) {
            System.out.println("\n优势名称: " + advantage.getName());
            System.out.println("详细描述: " + advantage.getDescription());
            System.out.println("具体示例: " + advantage.getExample());
            System.out.println("带来好处: " + advantage.getBenefit());
        }
    }
}

2. 消息队列模式分析

消息队列模式详解

java 复制代码
// MessageQueuePatterns.java
package com.example.demo.messagequeue;

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

public class MessageQueuePatterns {
    
    public static class QueuePattern {
        private String name;
        private String description;
        private String useCase;
        private String implementation;
        
        public QueuePattern(String name, String description, String useCase, String implementation) {
            this.name = name;
            this.description = description;
            this.useCase = useCase;
            this.implementation = implementation;
        }
        
        // Getter方法
        public String getName() { return name; }
        public String getDescription() { return description; }
        public String getUseCase() { return useCase; }
        public String getImplementation() { return implementation; }
    }
    
    public static void main(String[] args) {
        Map<String, QueuePattern> patterns = new HashMap<>();
        
        // 点对点模式
        patterns.put("P2P", new QueuePattern(
            "点对点模式 (Point-to-Point)",
            "一个生产者对应一个消费者,消息被消费后从队列中移除",
            "订单处理、邮件发送、短信通知",
            "使用Queue,消息只能被一个消费者处理"
        ));
        
        // 发布订阅模式
        patterns.put("PubSub", new QueuePattern(
            "发布订阅模式 (Publish-Subscribe)",
            "一个生产者对应多个消费者,每个消费者都能收到消息副本",
            "系统通知、日志收集、事件广播",
            "使用Topic,消息被广播到所有订阅者"
        ));
        
        // 请求响应模式
        patterns.put("RequestResponse", new QueuePattern(
            "请求响应模式 (Request-Response)",
            "生产者发送请求,消费者处理并返回响应",
            "RPC调用、任务分发、查询请求",
            "使用临时队列和关联ID实现双向通信"
        ));
        
        // 工作队列模式
        patterns.put("WorkQueue", new QueuePattern(
            "工作队列模式 (Work Queue)",
            "多个消费者竞争处理队列中的任务",
            "图片处理、文件转换、批量计算",
            "使用轮询或公平分发策略分配任务"
        ));
        
        System.out.println("=== 消息队列主要模式 ===");
        for (Map.Entry<String, QueuePattern> entry : patterns.entrySet()) {
            QueuePattern pattern = entry.getValue();
            System.out.println("\n模式类型: " + entry.getKey() + " - " + pattern.getName());
            System.out.println("模式描述: " + pattern.getDescription());
            System.out.println("使用场景: " + pattern.getUseCase());
            System.out.println("实现方式: " + pattern.getImplementation());
        }
    }
}

✅ 第二部分:RabbitMQ集成与使用(90分钟)

1. RabbitMQ配置与依赖

Maven依赖配置

xml 复制代码
<!-- pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>message-queue-demo</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>rabbitmq-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

RabbitMQ配置

yaml 复制代码
# application.yml
server:
  port: 8080

spring:
  application:
    name: rabbitmq-service
  
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual-host: /
    
    # 连接池配置
    connection-timeout: 15000
    requested-heart-beat: 30
    
    # 发布确认
    publisher-confirm-type: correlated
    publisher-returns: true
    
    # 消费者配置
    listener:
      simple:
        acknowledge-mode: manual
        prefetch: 1
        retry:
          enabled: true
          initial-interval: 1000
          max-attempts: 3
          max-interval: 10000
          multiplier: 1.0
        default-requeue-rejected: false

# 自定义配置
rabbitmq:
  exchange:
    order: order.exchange
    notification: notification.exchange
    dead-letter: dead.letter.exchange
  
  queue:
    order-created: order.created.queue
    order-paid: order.paid.queue
    order-cancelled: order.cancelled.queue
    notification: notification.queue
    dead-letter: dead.letter.queue
  
  routing-key:
    order-created: order.created
    order-paid: order.paid
    order-cancelled: order.cancelled
    notification: notification

2. RabbitMQ配置类

RabbitMQ配置类

java 复制代码
// RabbitMQConfig.java
package com.example.rabbitmq.config;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {

    @Value("${rabbitmq.exchange.order}")
    private String orderExchange;
    
    @Value("${rabbitmq.exchange.notification}")
    private String notificationExchange;
    
    @Value("${rabbitmq.exchange.dead-letter}")
    private String deadLetterExchange;
    
    @Value("${rabbitmq.queue.order-created}")
    private String orderCreatedQueue;
    
    @Value("${rabbitmq.queue.order-paid}")
    private String orderPaidQueue;
    
    @Value("${rabbitmq.queue.order-cancelled}")
    private String orderCancelledQueue;
    
    @Value("${rabbitmq.queue.notification}")
    private String notificationQueue;
    
    @Value("${rabbitmq.queue.dead-letter}")
    private String deadLetterQueue;

    /**
     * 消息转换器
     */
    @Bean
    public MessageConverter jsonMessageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    /**
     * RabbitTemplate配置
     */
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        template.setMessageConverter(jsonMessageConverter());
        
        // 发布确认回调
        template.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                System.out.println("消息发送成功: " + correlationData);
            } else {
                System.err.println("消息发送失败: " + cause);
            }
        });
        
        // 返回回调
        template.setReturnsCallback(returned -> {
            System.err.println("消息被退回: " + returned);
        });
        
        return template;
    }

    /**
     * 订单交换机
     */
    @Bean
    public DirectExchange orderExchange() {
        return new DirectExchange(orderExchange);
    }

    /**
     * 通知交换机
     */
    @Bean
    public FanoutExchange notificationExchange() {
        return new FanoutExchange(notificationExchange);
    }

    /**
     * 死信交换机
     */
    @Bean
    public DirectExchange deadLetterExchange() {
        return new DirectExchange(deadLetterExchange);
    }

    /**
     * 订单创建队列
     */
    @Bean
    public Queue orderCreatedQueue() {
        return QueueBuilder.durable(orderCreatedQueue)
                .withArgument("x-dead-letter-exchange", deadLetterExchange)
                .withArgument("x-dead-letter-routing-key", "dead.letter")
                .withArgument("x-message-ttl", 300000) // 5分钟过期
                .build();
    }

    /**
     * 订单支付队列
     */
    @Bean
    public Queue orderPaidQueue() {
        return QueueBuilder.durable(orderPaidQueue)
                .withArgument("x-dead-letter-exchange", deadLetterExchange)
                .withArgument("x-dead-letter-routing-key", "dead.letter")
                .build();
    }

    /**
     * 订单取消队列
     */
    @Bean
    public Queue orderCancelledQueue() {
        return QueueBuilder.durable(orderCancelledQueue)
                .withArgument("x-dead-letter-exchange", deadLetterExchange)
                .withArgument("x-dead-letter-routing-key", "dead.letter")
                .build();
    }

    /**
     * 通知队列
     */
    @Bean
    public Queue notificationQueue() {
        return QueueBuilder.durable(notificationQueue)
                .withArgument("x-dead-letter-exchange", deadLetterExchange)
                .withArgument("x-dead-letter-routing-key", "dead.letter")
                .build();
    }

    /**
     * 死信队列
     */
    @Bean
    public Queue deadLetterQueue() {
        return QueueBuilder.durable(deadLetterQueue).build();
    }

    /**
     * 绑定订单创建队列到交换机
     */
    @Bean
    public Binding orderCreatedBinding() {
        return BindingBuilder.bind(orderCreatedQueue())
                .to(orderExchange())
                .with("order.created");
    }

    /**
     * 绑定订单支付队列到交换机
     */
    @Bean
    public Binding orderPaidBinding() {
        return BindingBuilder.bind(orderPaidQueue())
                .to(orderExchange())
                .with("order.paid");
    }

    /**
     * 绑定订单取消队列到交换机
     */
    @Bean
    public Binding orderCancelledBinding() {
        return BindingBuilder.bind(orderCancelledQueue())
                .to(orderExchange())
                .with("order.cancelled");
    }

    /**
     * 绑定通知队列到交换机
     */
    @Bean
    public Binding notificationBinding() {
        return BindingBuilder.bind(notificationQueue())
                .to(notificationExchange());
    }

    /**
     * 绑定死信队列到交换机
     */
    @Bean
    public Binding deadLetterBinding() {
        return BindingBuilder.bind(deadLetterQueue())
                .to(deadLetterExchange())
                .with("dead.letter");
    }
}

3. 消息实体类

订单消息实体

java 复制代码
// OrderMessage.java
package com.example.rabbitmq.model;

import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;

@Data
public class OrderMessage {
    
    private String messageId;
    private String orderNumber;
    private Long userId;
    private Long productId;
    private Integer quantity;
    private BigDecimal amount;
    private String status;
    private LocalDateTime createTime;
    private String source;
    private String traceId;
    
    public OrderMessage() {
        this.messageId = java.util.UUID.randomUUID().toString();
        this.createTime = LocalDateTime.now();
    }
    
    public OrderMessage(String orderNumber, Long userId, Long productId, 
                       Integer quantity, BigDecimal amount, String status) {
        this();
        this.orderNumber = orderNumber;
        this.userId = userId;
        this.productId = productId;
        this.quantity = quantity;
        this.amount = amount;
        this.status = status;
    }
}

通知消息实体

java 复制代码
// NotificationMessage.java
package com.example.rabbitmq.model;

import lombok.Data;
import java.time.LocalDateTime;
import java.util.Map;

@Data
public class NotificationMessage {
    
    private String messageId;
    private String type; // EMAIL, SMS, PUSH, WEBHOOK
    private String title;
    private String content;
    private String recipient; // 邮箱、手机号、用户ID等
    private Map<String, Object> data;
    private Integer priority; // 1-低, 2-中, 3-高
    private LocalDateTime createTime;
    private LocalDateTime scheduledTime;
    private String status; // PENDING, SENT, FAILED
    
    public NotificationMessage() {
        this.messageId = java.util.UUID.randomUUID().toString();
        this.createTime = LocalDateTime.now();
        this.status = "PENDING";
        this.priority = 2;
    }
    
    public NotificationMessage(String type, String title, String content, String recipient) {
        this();
        this.type = type;
        this.title = title;
        this.content = content;
        this.recipient = recipient;
    }
}

✅ 第三部分:消息生产者与消费者(90分钟)

1. 消息生产者服务

订单消息生产者

java 复制代码
// OrderMessageProducer.java
package com.example.rabbitmq.producer;

import com.example.rabbitmq.model.OrderMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Slf4j
@Service
public class OrderMessageProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    @Value("${rabbitmq.exchange.order}")
    private String orderExchange;
    
    @Value("${rabbitmq.exchange.notification}")
    private String notificationExchange;

    /**
     * 发送订单创建消息
     */
    public void sendOrderCreated(OrderMessage orderMessage) {
        try {
            String routingKey = "order.created";
            rabbitTemplate.convertAndSend(orderExchange, routingKey, orderMessage);
            log.info("订单创建消息发送成功: {}", orderMessage.getOrderNumber());
        } catch (Exception e) {
            log.error("订单创建消息发送失败: {}", orderMessage.getOrderNumber(), e);
            throw new RuntimeException("消息发送失败", e);
        }
    }

    /**
     * 发送订单支付消息
     */
    public void sendOrderPaid(OrderMessage orderMessage) {
        try {
            String routingKey = "order.paid";
            rabbitTemplate.convertAndSend(orderExchange, routingKey, orderMessage);
            log.info("订单支付消息发送成功: {}", orderMessage.getOrderNumber());
        } catch (Exception e) {
            log.error("订单支付消息发送失败: {}", orderMessage.getOrderNumber(), e);
            throw new RuntimeException("消息发送失败", e);
        }
    }

    /**
     * 发送订单取消消息
     */
    public void sendOrderCancelled(OrderMessage orderMessage) {
        try {
            String routingKey = "order.cancelled";
            rabbitTemplate.convertAndSend(orderExchange, routingKey, orderMessage);
            log.info("订单取消消息发送成功: {}", orderMessage.getOrderNumber());
        } catch (Exception e) {
            log.error("订单取消消息发送失败: {}", orderMessage.getOrderNumber(), e);
            throw new RuntimeException("消息发送失败", e);
        }
    }

    /**
     * 发送延迟消息
     */
    public void sendDelayedMessage(OrderMessage orderMessage, long delayMillis) {
        try {
            // 使用死信队列实现延迟消息
            String routingKey = "order.delayed";
            rabbitTemplate.convertAndSend(orderExchange, routingKey, orderMessage, message -> {
                message.getMessageProperties().setExpiration(String.valueOf(delayMillis));
                return message;
            });
            log.info("延迟消息发送成功: {}, 延迟: {}ms", orderMessage.getOrderNumber(), delayMillis);
        } catch (Exception e) {
            log.error("延迟消息发送失败: {}", orderMessage.getOrderNumber(), e);
            throw new RuntimeException("延迟消息发送失败", e);
        }
    }

    /**
     * 发送批量消息
     */
    public void sendBatchMessages(List<OrderMessage> messages) {
        try {
            for (OrderMessage message : messages) {
                String routingKey = "order.batch";
                rabbitTemplate.convertAndSend(orderExchange, routingKey, message);
            }
            log.info("批量消息发送成功,数量: {}", messages.size());
        } catch (Exception e) {
            log.error("批量消息发送失败", e);
            throw new RuntimeException("批量消息发送失败", e);
        }
    }
}

通知消息生产者

java 复制代码
// NotificationMessageProducer.java
package com.example.rabbitmq.producer;

import com.example.rabbitmq.model.NotificationMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;

@Slf4j
@Service
public class NotificationMessageProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    @Value("${rabbitmq.exchange.notification}")
    private String notificationExchange;

    /**
     * 发送通知消息
     */
    public void sendNotification(NotificationMessage notification) {
        try {
            rabbitTemplate.convertAndSend(notificationExchange, "", notification);
            log.info("通知消息发送成功: {}", notification.getMessageId());
        } catch (Exception e) {
            log.error("通知消息发送失败: {}", notification.getMessageId(), e);
            throw new RuntimeException("通知消息发送失败", e);
        }
    }

    /**
     * 发送批量通知
     */
    public void sendBatchNotifications(List<NotificationMessage> notifications) {
        try {
            for (NotificationMessage notification : notifications) {
                rabbitTemplate.convertAndSend(notificationExchange, "", notification);
            }
            log.info("批量通知发送成功,数量: {}", notifications.size());
        } catch (Exception e) {
            log.error("批量通知发送失败", e);
            throw new RuntimeException("批量通知发送失败", e);
        }
    }

    /**
     * 发送优先级通知
     */
    public void sendPriorityNotification(NotificationMessage notification) {
        try {
            // 根据优先级设置不同的路由键
            String routingKey = "notification.priority." + notification.getPriority();
            rabbitTemplate.convertAndSend(notificationExchange, routingKey, notification);
            log.info("优先级通知发送成功: {}, 优先级: {}", notification.getMessageId(), notification.getPriority());
        } catch (Exception e) {
            log.error("优先级通知发送失败: {}", notification.getMessageId(), e);
            throw new RuntimeException("优先级通知发送失败", e);
        }
    }
}

2. 消息消费者服务

订单消息消费者

java 复制代码
// OrderMessageConsumer.java
package com.example.rabbitmq.consumer;

import com.example.rabbitmq.model.OrderMessage;
import com.example.rabbitmq.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Service;

import com.rabbitmq.client.Channel;
import java.io.IOException;

@Slf4j
@Service
public class OrderMessageConsumer {

    @Autowired
    private OrderService orderService;

    /**
     * 消费订单创建消息
     */
    @RabbitListener(queues = "${rabbitmq.queue.order-created}")
    public void consumeOrderCreated(OrderMessage orderMessage, 
                                  Message message, 
                                  Channel channel,
                                  @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        try {
            log.info("收到订单创建消息: {}", orderMessage.getOrderNumber());
            
            // 处理订单创建逻辑
            orderService.processOrderCreated(orderMessage);
            
            // 手动确认消息
            channel.basicAck(deliveryTag, false);
            log.info("订单创建消息处理成功: {}", orderMessage.getOrderNumber());
            
        } catch (Exception e) {
            log.error("订单创建消息处理失败: {}", orderMessage.getOrderNumber(), e);
            
            try {
                // 消息处理失败,拒绝消息并重新入队
                channel.basicNack(deliveryTag, false, true);
            } catch (IOException ioException) {
                log.error("消息拒绝失败", ioException);
            }
        }
    }

    /**
     * 消费订单支付消息
     */
    @RabbitListener(queues = "${rabbitmq.queue.order-paid}")
    public void consumeOrderPaid(OrderMessage orderMessage, 
                                Message message, 
                                Channel channel,
                                @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        try {
            log.info("收到订单支付消息: {}", orderMessage.getOrderNumber());
            
            // 处理订单支付逻辑
            orderService.processOrderPaid(orderMessage);
            
            // 手动确认消息
            channel.basicAck(deliveryTag, false);
            log.info("订单支付消息处理成功: {}", orderMessage.getOrderNumber());
            
        } catch (Exception e) {
            log.error("订单支付消息处理失败: {}", orderMessage.getOrderNumber(), e);
            
            try {
                // 消息处理失败,拒绝消息并重新入队
                channel.basicNack(deliveryTag, false, true);
            } catch (IOException ioException) {
                log.error("消息拒绝失败", ioException);
            }
        }
    }

    /**
     * 消费订单取消消息
     */
    @RabbitListener(queues = "${rabbitmq.queue.order-cancelled}")
    public void consumeOrderCancelled(OrderMessage orderMessage, 
                                    Message message, 
                                    Channel channel,
                                    @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        try {
            log.info("收到订单取消消息: {}", orderMessage.getOrderNumber());
            
            // 处理订单取消逻辑
            orderService.processOrderCancelled(orderMessage);
            
            // 手动确认消息
            channel.basicAck(deliveryTag, false);
            log.info("订单取消消息处理成功: {}", orderMessage.getOrderNumber());
            
        } catch (Exception e) {
            log.error("订单取消消息处理失败: {}", orderMessage.getOrderNumber(), e);
            
            try {
                // 消息处理失败,拒绝消息并重新入队
                channel.basicNack(deliveryTag, false, true);
            } catch (IOException ioException) {
                log.error("消息拒绝失败", ioException);
            }
        }
    }
}

通知消息消费者

java 复制代码
// NotificationMessageConsumer.java
package com.example.rabbitmq.consumer;

import com.example.rabbitmq.model.NotificationMessage;
import com.example.rabbitmq.service.NotificationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Service;

import com.rabbitmq.client.Channel;
import java.io.IOException;

@Slf4j
@Service
public class NotificationMessageConsumer {

    @Autowired
    private NotificationService notificationService;

    /**
     * 消费通知消息
     */
    @RabbitListener(queues = "${rabbitmq.queue.notification}")
    public void consumeNotification(NotificationMessage notification, 
                                  Message message, 
                                  Channel channel,
                                  @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        try {
            log.info("收到通知消息: {}, 类型: {}", notification.getMessageId(), notification.getType());
            
            // 处理通知逻辑
            notificationService.processNotification(notification);
            
            // 手动确认消息
            channel.basicAck(deliveryTag, false);
            log.info("通知消息处理成功: {}", notification.getMessageId());
            
        } catch (Exception e) {
            log.error("通知消息处理失败: {}", notification.getMessageId(), e);
            
            try {
                // 消息处理失败,拒绝消息并重新入队
                channel.basicNack(deliveryTag, false, true);
            } catch (IOException ioException) {
                log.error("消息拒绝失败", ioException);
            }
        }
    }

    /**
     * 消费死信消息
     */
    @RabbitListener(queues = "${rabbitmq.queue.dead-letter}")
    public void consumeDeadLetter(Message message, 
                                 Channel channel,
                                 @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        try {
            log.warn("收到死信消息: {}", message);
            
            // 处理死信消息逻辑
            notificationService.processDeadLetter(message);
            
            // 手动确认消息
            channel.basicAck(deliveryTag, false);
            log.info("死信消息处理成功");
            
        } catch (Exception e) {
            log.error("死信消息处理失败", e);
            
            try {
                // 死信消息处理失败,拒绝消息
                channel.basicNack(deliveryTag, false, false);
            } catch (IOException ioException) {
                log.error("死信消息拒绝失败", ioException);
            }
        }
    }
}

✅ 第四部分:异步处理与任务调度(60分钟)

1. 异步任务配置

异步配置类

java 复制代码
// AsyncConfig.java
package com.example.rabbitmq.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableAsync
public class AsyncConfig {

    /**
     * 异步任务执行器
     */
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        
        // 核心线程数
        executor.setCorePoolSize(10);
        
        // 最大线程数
        executor.setMaxPoolSize(20);
        
        // 队列容量
        executor.setQueueCapacity(500);
        
        // 线程空闲时间
        executor.setKeepAliveSeconds(60);
        
        // 线程名前缀
        executor.setThreadNamePrefix("AsyncTask-");
        
        // 拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        
        // 等待时间
        executor.setAwaitTerminationSeconds(60);
        
        executor.initialize();
        return executor;
    }

    /**
     * 消息处理执行器
     */
    @Bean("messageExecutor")
    public Executor messageExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(200);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("MessageTask-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        
        executor.initialize();
        return executor;
    }
}

2. 异步任务服务

异步订单处理服务

java 复制代码
// AsyncOrderService.java
package com.example.rabbitmq.service;

import com.example.rabbitmq.model.OrderMessage;
import com.example.rabbitmq.producer.OrderMessageProducer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Service
public class AsyncOrderService {

    @Autowired
    private OrderMessageProducer orderMessageProducer;
    
    @Autowired
    private NotificationService notificationService;

    /**
     * 异步处理订单创建
     */
    @Async("taskExecutor")
    public CompletableFuture<String> processOrderAsync(OrderMessage orderMessage) {
        try {
            log.info("开始异步处理订单: {}", orderMessage.getOrderNumber());
            
            // 模拟处理时间
            Thread.sleep(2000);
            
            // 发送订单创建消息
            orderMessageProducer.sendOrderCreated(orderMessage);
            
            // 发送通知
            notificationService.sendOrderCreatedNotification(orderMessage);
            
            log.info("订单异步处理完成: {}", orderMessage.getOrderNumber());
            
            return CompletableFuture.completedFuture("SUCCESS");
            
        } catch (Exception e) {
            log.error("订单异步处理失败: {}", orderMessage.getOrderNumber(), e);
            return CompletableFuture.completedFuture("FAILED");
        }
    }

    /**
     * 异步批量处理订单
     */
    @Async("taskExecutor")
    public CompletableFuture<Integer> processBatchOrdersAsync(List<OrderMessage> orders) {
        try {
            log.info("开始异步批量处理订单,数量: {}", orders.size());
            
            int successCount = 0;
            for (OrderMessage order : orders) {
                try {
                    // 处理单个订单
                    orderMessageProducer.sendOrderCreated(order);
                    successCount++;
                } catch (Exception e) {
                    log.error("订单处理失败: {}", order.getOrderNumber(), e);
                }
            }
            
            log.info("批量订单处理完成,成功: {}, 失败: {}", successCount, orders.size() - successCount);
            
            return CompletableFuture.completedFuture(successCount);
            
        } catch (Exception e) {
            log.error("批量订单处理失败", e);
            return CompletableFuture.completedFuture(0);
        }
    }

    /**
     * 异步处理订单支付
     */
    @Async("messageExecutor")
    public CompletableFuture<Boolean> processPaymentAsync(OrderMessage orderMessage) {
        try {
            log.info("开始异步处理订单支付: {}", orderMessage.getOrderNumber());
            
            // 模拟支付处理时间
            Thread.sleep(3000);
            
            // 发送支付成功消息
            orderMessageProducer.sendOrderPaid(orderMessage);
            
            // 发送支付成功通知
            notificationService.sendPaymentSuccessNotification(orderMessage);
            
            log.info("订单支付处理完成: {}", orderMessage.getOrderNumber());
            
            return CompletableFuture.completedFuture(true);
            
        } catch (Exception e) {
            log.error("订单支付处理失败: {}", orderMessage.getOrderNumber(), e);
            return CompletableFuture.completedFuture(false);
        }
    }
}

3. 定时任务服务

定时任务配置

java 复制代码
// ScheduledTaskService.java
package com.example.rabbitmq.service;

import com.example.rabbitmq.producer.OrderMessageProducer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service
public class ScheduledTaskService {

    @Autowired
    private OrderMessageProducer orderMessageProducer;
    
    @Autowired
    private OrderService orderService;

    /**
     * 定时清理过期订单(每分钟执行一次)
     */
    @Scheduled(fixedRate = 60000)
    public void cleanExpiredOrders() {
        try {
            log.info("开始清理过期订单,时间: {}", LocalDateTime.now());
            
            // 获取过期订单
            List<OrderMessage> expiredOrders = orderService.getExpiredOrders();
            
            if (!expiredOrders.isEmpty()) {
                // 发送订单取消消息
                for (OrderMessage order : expiredOrders) {
                    orderMessageProducer.sendOrderCancelled(order);
                }
                
                log.info("过期订单清理完成,数量: {}", expiredOrders.size());
            } else {
                log.info("没有过期订单需要清理");
            }
            
        } catch (Exception e) {
            log.error("清理过期订单失败", e);
        }
    }

    /**
     * 定时发送提醒消息(每天上午9点执行)
     */
    @Scheduled(cron = "0 0 9 * * ?")
    public void sendDailyReminders() {
        try {
            log.info("开始发送每日提醒消息,时间: {}", LocalDateTime.now());
            
            // 获取需要提醒的订单
            List<OrderMessage> reminderOrders = orderService.getOrdersNeedingReminder();
            
            if (!reminderOrders.isEmpty()) {
                // 发送提醒消息
                for (OrderMessage order : reminderOrders) {
                    // 发送延迟提醒消息
                    orderMessageProducer.sendDelayedMessage(order, 300000); // 5分钟后发送
                }
                
                log.info("每日提醒消息发送完成,数量: {}", reminderOrders.size());
            } else {
                log.info("没有需要提醒的订单");
            }
            
        } catch (Exception e) {
            log.error("发送每日提醒消息失败", e);
        }
    }

    /**
     * 定时统计消息队列状态(每5分钟执行一次)
     */
    @Scheduled(fixedRate = 300000)
    public void monitorQueueStatus() {
        try {
            log.info("开始监控消息队列状态,时间: {}", LocalDateTime.now());
            
            // 获取队列统计信息
            QueueStats stats = getQueueStats();
            
            log.info("队列状态监控 - 总消息数: {}, 待处理: {}, 处理中: {}, 已完成: {}", 
                    stats.getTotalMessages(), 
                    stats.getPendingMessages(), 
                    stats.getProcessingMessages(), 
                    stats.getCompletedMessages());
            
        } catch (Exception e) {
            log.error("监控消息队列状态失败", e);
        }
    }

    /**
     * 队列统计信息
     */
    private QueueStats getQueueStats() {
        // 这里应该调用RabbitMQ管理API获取实际统计信息
        // 为了演示,返回模拟数据
        QueueStats stats = new QueueStats();
        stats.setTotalMessages(1000);
        stats.setPendingMessages(150);
        stats.setProcessingMessages(50);
        stats.setCompletedMessages(800);
        return stats;
    }

    /**
     * 队列统计信息类
     */
    public static class QueueStats {
        private int totalMessages;
        private int pendingMessages;
        private int processingMessages;
        private int completedMessages;

        // Getter和Setter方法
        public int getTotalMessages() { return totalMessages; }
        public void setTotalMessages(int totalMessages) { this.totalMessages = totalMessages; }

        public int getPendingMessages() { return pendingMessages; }
        public void setPendingMessages(int pendingMessages) { this.pendingMessages = pendingMessages; }

        public int getProcessingMessages() { return processingMessages; }
        public void setProcessingMessages(int processingMessages) { this.processingMessages = processingMessages; }

        public int getCompletedMessages() { return completedMessages; }
        public void setCompletedMessages(int completedMessages) { this.completedMessages = completedMessages; }
    }
}

🎯 今日学习总结

1. 掌握的核心技能

  • ✅ 消息队列基础概念与优势
  • ✅ RabbitMQ配置与集成
  • ✅ 消息生产者与消费者实现
  • ✅ 异步任务处理与调度
  • ✅ 消息队列监控与管理

2. 消息队列核心概念

  • 异步处理:提高系统响应速度
  • 服务解耦:降低系统耦合度
  • 流量削峰:保护系统稳定性
  • 可靠性保证:消息持久化存储

3. RabbitMQ主要特性

  • 多种交换机类型:Direct、Fanout、Topic
  • 消息确认机制:发布确认、消费者确认
  • 死信队列:处理失败消息
  • 延迟消息:定时任务支持
  • 优先级队列:重要消息优先处理

4. 异步处理模式

  • @Async注解:Spring异步任务支持
  • 线程池配置:自定义执行器
  • CompletableFuture:异步结果处理
  • 定时任务:@Scheduled注解使用

5. 下一步学习方向

  • Kafka消息队列使用
  • 消息幂等性处理
  • 分布式锁实现
  • 缓存策略优化
  • 性能监控与调优

学习建议

  1. 环境搭建:安装RabbitMQ,配置开发环境
  2. 基础练习:实现简单的消息发送和接收
  3. 模式理解:深入理解不同消息队列模式
  4. 异常处理:学会处理消息处理失败的情况
  5. 性能优化:理解消息队列的性能调优策略
相关推荐
zzywxc7877 小时前
深入对比分析SpringCloud和Dubbo两大微服务框架的核心架构与特性。
java·spring·spring cloud·缓存·微服务·架构·dubbo
zfoo-framework7 小时前
死锁检测 及其测试用例
java
颜如玉7 小时前
谈谈SerializedLambda
java·后端·源码
带刺的坐椅7 小时前
Solon 权限认证之 Sa-Token 的使用与详解
java·sa-token·web·solon
麦兜*8 小时前
MongoDB 源码编译与调试:深入理解存储引擎设计 内容详细
java·数据库·spring boot·mongodb·spring
编啊编程啊程8 小时前
响应式编程框架Reactor【9】
java·网络·python·spring·tomcat·maven·hibernate
evolution_language8 小时前
LintCode第401题-排序矩阵中的从小到大第k个数
java·算法·矩阵·排序算法·堆排序·练码精选100题
_Jimmy_8 小时前
java讲解自己对业务架构、数据架构、应用架构的理解
java
资源开发与学习8 小时前
Java大模型工程能力必修课,LangChain4j 入门到实践
java