分布式中间件:RabbitMQ基于DirectExchange的直连消息传输

分布式中间件:RabbitMQ基于DirectExchange的直连消息传输

引言

在分布式系统的开发中,消息队列是一种常用的组件,它能够帮助我们实现系统间的解耦、异步通信以及流量削峰等功能。RabbitMQ 作为一款功能强大的消息队列中间件,提供了多种类型的交换机,其中 Direct Exchange(直连交换机)是一种非常基础且实用的交换机类型。本文将详细介绍如何使用 RabbitMQ 的 Direct Exchange 进行直连消息传输,并结合 Spring Boot 给出具体的代码示例。

Direct Exchange 简介

Direct Exchange 是 RabbitMQ 中最简单的一种交换机类型。它根据消息的路由键(routing key)将消息路由到与之绑定的队列中。每个队列在绑定到 Direct Exchange 时会指定一个绑定键(binding key),当消息发送到 Direct Exchange 时,Exchange 会根据消息的路由键与绑定键进行匹配,如果匹配成功,则将消息发送到对应的队列中。

配置文件

首先,我们需要在配置文件中定义交换机、路由键和队列的名称。以下是 application.yml 文件的示例配置:

basic:
  direct:
    exchange:
      name: testDirectExchange
    routing:
      key1: testDirectKey1
      key2: testDirectKey2
    queue:
      name1: testDirectQueue1
      name2: testDirectQueue2

RabbitMQ 配置类

接下来,我们需要创建一个 RabbitMQ 配置类,用于创建交换机、队列以及它们之间的绑定关系。

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

@Configuration
public class RabbitmqConfig {

    private final Environment environment;

    public RabbitmqConfig(Environment environment) {
        this.environment = environment;
    }

    // 创建交换机
    @Bean("directExchange")
    public DirectExchange directExchange() {
        return new DirectExchange(environment.getProperty("basic.direct.exchange.name"), true, false);
    }

    // 创建队列一
    @Bean("directQueue1")
    public Queue directQueue1() {
        return new Queue(environment.getProperty("basic.direct.queue.name1"), true);
    }

    // 创建队列二
    @Bean("directQueue2")
    public Queue directQueue2() {
        return new Queue(environment.getProperty("basic.direct.queue.name2"), true);
    }

    // 创建绑定一
    @Bean
    public Binding directBinding1() {
        return BindingBuilder.bind(directQueue1())
                .to(directExchange())
                .with(environment.getProperty("basic.direct.routing.key1"));
    }

    // 创建绑定二
    @Bean
    public Binding directBinding2() {
        return BindingBuilder.bind(directQueue2())
                .to(directExchange())
                .with(environment.getProperty("basic.direct.routing.key2"));
    }
}

在上述代码中,我们使用 @Bean 注解创建了一个 DirectExchange 交换机、两个 Queue 队列,并通过 BindingBuilder 将队列与交换机进行绑定,指定了相应的绑定键。

消息生产者

消息生产者负责将消息发送到 RabbitMQ 中。以下是一个简单的消息生产者类:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
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.Component;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;

@Component
public class DirectPublisher {

    private final Environment environment;
    private final ObjectMapper objectMapper;
    private final RabbitTemplate rabbitTemplate;

    public DirectPublisher(Environment environment, ObjectMapper objectMapper, RabbitTemplate rabbitTemplate) {
        this.environment = environment;
        this.objectMapper = objectMapper;
        this.rabbitTemplate = rabbitTemplate;
    }

    public void send1(String msg) {
        if (!StringUtils.isEmpty(msg)) {
            try {
                rabbitTemplate.setExchange(environment.getProperty("basic.direct.exchange.name"));
                rabbitTemplate.setRoutingKey(environment.getProperty("basic.direct.routing.key1"));
                Message message = MessageBuilder.withBody(msg.getBytes(StandardCharsets.UTF_8)).build();
                rabbitTemplate.convertAndSend(message);
                System.out.println("发送消息:" + msg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void send2(String msg) {
        if (!StringUtils.isEmpty(msg)) {
            try {
                rabbitTemplate.setExchange(environment.getProperty("basic.direct.exchange.name"));
                rabbitTemplate.setRoutingKey(environment.getProperty("basic.direct.routing.key2"));
                Message message = MessageBuilder.withBody(msg.getBytes(StandardCharsets.UTF_8)).build();
                rabbitTemplate.convertAndSend(message);
                System.out.println("发送消息:" + msg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

DirectPublisher 类中,我们定义了两个方法 send1send2,分别用于发送不同路由键的消息。在发送消息时,我们设置了交换机和路由键,并将消息转换为 Message 对象后发送。

消息消费者

消息消费者负责从 RabbitMQ 中接收消息。以下是一个简单的消息消费者类:

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
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.Component;

@Component
public class DirectConsumer {

    private final Environment environment;
    private final ObjectMapper objectMapper;
    private final RabbitTemplate rabbitTemplate;

    public DirectConsumer(Environment environment, ObjectMapper objectMapper, RabbitTemplate rabbitTemplate) {
        this.environment = environment;
        this.objectMapper = objectMapper;
        this.rabbitTemplate = rabbitTemplate;
    }

    @RabbitListener(queues = "${basic.direct.queue.name1}", containerFactory = "singleListenerContainer")
    public void receive1(@Payload JSONObject msg) {
        try {
            System.out.println("direct1收到消息:" + msg);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @RabbitListener(queues = "${basic.direct.queue.name2}", containerFactory = "singleListenerContainer")
    public void receive2(@Payload JSONObject msg) {
        try {
            System.out.println("direct2收到消息:" + msg);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

DirectConsumer 类中,我们使用 @RabbitListener 注解监听两个队列,当队列中有消息时,会调用相应的方法进行处理。

测试代码

最后,我们编写一个测试类来验证消息的发送和接收功能:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Map;

@SpringBootTest
public class Test3 {

    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private DirectPublisher directPublisher;

    @Test
    public void test1() throws Exception {
        System.out.println("测试开始");
        Map<String, Object> map1 = Map.of("name", "张三", "age", 18, "sex", "男");
        Map<String, Object> map2 = Map.of("name", "李四", "age", 18, "sex", "男");
        System.out.println(map1);
        directPublisher.send1(objectMapper.writeValueAsString(map1));
        System.out.println(map2);
        directPublisher.send2(objectMapper.writeValueAsString(map2));
        System.out.println("测试结束");
    }
}

Test3 类中,我们创建了两个 Map 对象,并将它们转换为 JSON 字符串后发送到 RabbitMQ 中。运行该测试方法,我们可以在控制台看到消息的发送和接收情况。

结果

测试开始
{age=18, sex=男, name=张三}
发送消息:{"age":18,"sex":"男","name":"张三"}
{age=18, sex=男, name=李四}
发送消息:{"age":18,"sex":"男","name":"李四"}
测试结束
消息发送成功
消息发送成功
2025-03-15 17:08:15.949  INFO 19304 --- [ntContainer#0-2] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
2025-03-15 17:08:15.951  INFO 19304 --- [ntContainer#1-2] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
2025-03-15 17:08:15.954  INFO 19304 --- [ntContainer#2-2] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
2025-03-15 17:08:15.957  INFO 19304 --- [ntContainer#3-2] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
2025-03-15 17:08:15.960  INFO 19304 --- [ntContainer#4-2] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
direct1收到消息:{"age":18,"sex":"男","name":"张三"}
direct2收到消息:{"age":18,"sex":"男","name":"李四"}

总结

通过本文的介绍,我们了解了 RabbitMQ 的 Direct Exchange 的基本原理,并结合 Spring Boot 实现了基于 Direct Exchange 的直连消息传输。Direct Exchange 适用于根据消息的路由键进行精确匹配的场景,能够帮助我们实现消息的精准投递。在实际开发中,我们可以根据具体的业务需求选择合适的交换机类型,以满足不同的消息处理需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顾北辰20

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值