Spring Boot 连接 RabbitMQ Socket Closed

简介

在使用 Spring Boot 连接 RabbitMQ 的过程中,有时候会遇到连接意外关闭的问题,本文将介绍如何解决这个问题。我们将以一个经验丰富的开发者指导一位刚入行的小白为例,教会他如何处理这个异常。

整体流程

首先,让我们来看一下整个处理过程的流程图。

journey
    title 连接 RabbitMQ Socket Closed 流程
    section 创建连接
    CreateConnection -->|配置连接参数| ConnectionFactory
    ConnectionFactory -->|创建连接| Connection
    Connection -->|创建通道| Channel
    end
    section 声明队列
    Channel -->|声明队列| QueueDeclare
    end
    section 发送消息
    Channel -->|发送消息| BasicPublish
    end
    section 接收消息
    Channel -->|接收消息| BasicConsume
    end

步骤详解

步骤一:创建连接

首先,我们需要创建一个 RabbitMQ 的连接。这里我们使用 Spring Boot 提供的 ConnectionFactory 类来配置连接参数并创建连接。

@Configuration
public class RabbitMQConfig {

    @Value("${spring.rabbitmq.host}")
    private String host;

    @Value("${spring.rabbitmq.port}")
    private int port;

    @Value("${spring.rabbitmq.username}")
    private String username;

    @Value("${spring.rabbitmq.password}")
    private String password;

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setHost(host);
        connectionFactory.setPort(port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        return connectionFactory;
    }
}

在上述代码中,我们使用 @Configuration 注解将该类声明为一个配置类,通过 @Value 注解将配置文件中的 RabbitMQ 连接参数注入到对应的变量中。然后,我们创建一个 CachingConnectionFactory 实例,并设置连接参数,最后返回该实例。

步骤二:声明队列

在创建连接之后,我们需要声明一个队列。使用 RabbitMQ 的 Channel 类来创建和管理队列。

@Component
public class RabbitMQListener {

    @Autowired
    private ConnectionFactory connectionFactory;

    @PostConstruct
    public void init() {
        try {
            Connection connection = connectionFactory.createConnection();
            Channel channel = connection.createChannel();

            String queueName = "myQueue";
            channel.queueDeclare(queueName, false, false, false, null);
        } catch (IOException | TimeoutException e) {
            e.printStackTrace();
        }
    }
}

在上述代码中,我们使用 @Component 注解将该类声明为一个 Spring Bean,并使用 @Autowired 注解将 ConnectionFactory 注入到该类中。然后,在 @PostConstruct 方法中,我们创建 ConnectionChannel 实例,并使用 channel.queueDeclare() 方法声明一个队列。

步骤三:发送消息

队列声明完成后,我们可以开始发送消息了。使用 Channel 类的 basicPublish() 方法来发送消息。

@Component
public class RabbitMQSender {

    @Autowired
    private ConnectionFactory connectionFactory;

    public void sendMessage(String message) {
        try {
            Connection connection = connectionFactory.createConnection();
            Channel channel = connection.createChannel();

            String exchangeName = "myExchange";
            String routingKey = "myRoutingKey";

            channel.basicPublish(exchangeName, routingKey, null, message.getBytes());
        } catch (IOException | TimeoutException e) {
            e.printStackTrace();
        }
    }
}

在上述代码中,我们使用 @Component 注解将该类声明为一个 Spring Bean,并使用 @Autowired 注解将 ConnectionFactory 注入到该类中。然后,在 sendMessage() 方法中,我们创建 ConnectionChannel 实例,并使用 channel.basicPublish() 方法发送消息。

步骤四:接收消息

发送消息完成后,我们可以开始接收消息了。使用 Channel 类的 basicConsume() 方法来接收消息。

@Component
public class RabbitMQReceiver {

    @Autowired
    private ConnectionFactory connectionFactory;

    @Value("${spring.rabbitmq.queue}")
    private String queueName;

    public void startReceiving() {
        try {
            Connection connection = connectionFactory.createConnection();
            Channel channel = connection.createChannel();

            channel.basicConsume(queueName, true, new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    String message =