RabbitMQ入门学习

由于传统的RabbitMQ使用起来较为麻烦,这里便直接使用SpringAMQP这套模板。
先创建一个名为mq-study的SpringCloud项目,该项目下有两个子模块,consumer和publisher。分别对应消息的消费者和消息的生产者。

在mq-study的pom文件中引入SpringAMQP的依赖

点击查看代码
<!--AMQP依赖,包含RabbitMQ-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

在consumer和publisher的application.yml文件中添加配置信息

点击查看代码
spring:
  rabbitmq:
    host: 192.168.136.50 # 主机名
    port: 5672 # 端口
    virtual-host: / # 虚拟主机
    username: wzh# 用户名
    password: 1234 # 密码

简单队列模型---Basic Queue
在publisher服务中编写测试类

点击查看代码
@SpringBootTest
@RunWith(SpringRunner.class)
public class SimpleQueue {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void SimpleQueue(){
        //队列名称
        String queueName="simple.queue";
        //消息
        String msg="Hello,wzh!";
        //发送消息
        rabbitTemplate.convertAndSend(queueName,msg);
    }
}
在consumer服务中声明交换机和队列,并绑定。
点击查看代码
@Configuration
public class SimpleConfig {
    //声明交换机
    @Bean
    public FanoutExchange simpleExchange(){
        return new FanoutExchange("wzh.simple");
    }
    //声明队列
    @Bean
    public Queue simpleQueue(){
        return new Queue("simple.queue");
    }
    //绑定交换机和队列
    @Bean
    public Binding bindingSimple(FanoutExchange simpleExchange,Queue simpleQueue){
        return BindingBuilder.bind(simpleQueue).to(simpleExchange);
    }
}

在consumer服务中编写监听消息的类

点击查看代码
@Component
public class SimpleListener {
    @RabbitListener(queues = "simple.queue")
    public void listenSimpleQueueMessage(String msg) throws InterruptedException {
        System.out.println("spring 消费者接收到消息:【" + msg + "】");
    }
}

最终先启动consumer服务的启动类,之后启动测试方法,可收到对应信息。
image


任务模型---WorkQueues
WorkQueues又称为TaskQueues,简单来说就是让多个消费者绑定到同一个队列,共同消费队列中的信息。当生产消息的速度大于消费速度是可以使用该模型。
在consumer服务中声明交换机和队列,并绑定。

点击查看代码
@Configuration
public class WorkConfig {
    //声明交换机
    @Bean
    public FanoutExchange workExchange(){
        return new FanoutExchange("wzh.work");
    }
    //声明队列
    @Bean
    public Queue workQueue(){
        return new Queue("work.queue");
    }
    //绑定交换机和队列
    @Bean
    public Binding bindingWork(FanoutExchange workExchange,Queue workQueue){
        return BindingBuilder.bind(workQueue).to(workExchange);
    }
}

在consumer服务中编写监听消息的类

点击查看代码
@Component
public class WorkListener {
    @RabbitListener(queues = "work.queue")
    public void workListener1(String msg) throws Exception{
        System.out.println("消费者1接收到消息:【" + msg + "】" + LocalTime.now());
        Thread.sleep(20);
    }

    @RabbitListener(queues = "work.queue")
    public void workListener2(String msg) throws Exception{
        System.err.println("消费者2接收到消息:【" + msg + "】" + LocalTime.now());
        Thread.sleep(200);
    }
}
在publisher中编写测试类
点击查看代码
@SpringBootTest
@RunWith(SpringRunner.class)
public class WorkQueue {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void workQueue() throws Exception{
        //队列名称
        String queueName="work.queue";
        //消息
        String msg="Hello,RabbitMQ---";
        //发送消息
        for (int i = 1; i <= 50; i++) {
            rabbitTemplate.convertAndSend(queueName,msg+i);
            Thread.sleep(20);
        }
    }
}

启动项目,查看效果。
image
从图中可以发现这两个消费者消费完消息耗时约5秒。消费者2明显拖慢了消息消费的速度。因为WorkQueues是平均分配消息的,如果想让消费者1多消费就要配置一下文件了。

点击查看代码
spring:
  rabbitmq:
    listener:
      simple:
        prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一个消息
之后重新运行就会发现消费完信息耗时约1秒。 总结WorkQueues模型的使用 1.多个消费者绑定到一个队列,同一条消息只会被一个消费者处理 2.通过设置prefetch来控制消费者预取的消息数量

广播模型---Fanout
在生产者与队列之间配置一个交换机,生产者将产生的消息发送到交换机,交换机在根据规则将消息发送到不同的队列中。

在consumer服务中声明交换机和队列,并绑定。

点击查看代码
@Configuration
public class FanoutConfig {
    //声明一个FanoutExchange
    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange("wzh.fanout");
    }
    //声明两个队列
    @Bean
    public Queue queue1(){
        return new Queue("fanout.queue1");
    }
    @Bean
    public Queue queue2(){
        return new Queue("fanout.queue2");
    }
    //将两个队列绑定到FanoutExchange
    @Bean
    public Binding bindingQ1(FanoutExchange fanoutExchange,Queue queue1){
        return BindingBuilder.bind(queue1).to(fanoutExchange);
    }
    @Bean
    public Binding bindingQ2(FanoutExchange fanoutExchange,Queue queue2){
        return BindingBuilder.bind(queue2).to(fanoutExchange);
    }
}

在publisher服务中编写测试方法
点击查看代码
@SpringBootTest
@RunWith(SpringRunner.class)
public class FanoutQueue {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void fanoutQueue(){
        //队列名称
        String exchangeName="wzh.fanout";
        //消息
        String message = "Hello, RabbitMQ!";
        //发送消息
        rabbitTemplate.convertAndSend(exchangeName,"",message);
    }
}
在consumer服务中编写监听消息的类
点击查看代码
@Component
public class FanoutListener {
    @RabbitListener(queues = "fanout.queue1")
    public void fanoutQ1(String msg){
        System.out.println("消费者1接收到Fanout消息:【" + msg + "】");
    }

    @RabbitListener(queues = "fanout.queue2")
    public void fanoutQ2(String msg){
        System.err.println("消费者2接收到Fanout消息:【" + msg + "】");
    }
}
启动项目,consumer两个队列都会接收到消息

image


Direct模型
如果我们希望不同的消息被不同的队列消费。这时就要用到Direct类型的Exchange。
通过注解的方式声明交换机并绑定队列

点击查看代码
@Component
public class DirectListener {
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue1"),
            exchange = @Exchange(name = "wzh.direct",type = ExchangeTypes.DIRECT),
            key = {"miku","luka"}
    ))
    public void direct1(String msg){
        System.out.println("消费者1接收到direct.queue1的消息:【" + msg + "】");
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue2"),
            exchange = @Exchange(name = "wzh.direct",type = ExchangeTypes.DIRECT),
            key = {"miku","luka"}
    ))
    public void direct2(String msg){
        System.err.println("消费者2接收到direct.queue2的消息:【" + msg + "】");
    }
}
在publisher服务中编写测试方法
点击查看代码
@SpringBootTest
@RunWith(SpringRunner.class)
public class DirectQueue {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void direct(){
        //队列名称
        String exhangeName="wzh.direct";
        //消息
        String msg="Hello,RabbitMQ";
        //发送消息
        rabbitTemplate.convertAndSend(exhangeName,"luka",msg);
    }
}

启动项目
image


Topic模型
该模型和Direct模型使用起来差不多,但是新加了RoutingKey的通配符共功能。
通配符规则:
“#”:匹配一个或多个词
“* ”:匹配一个词
举例:
item.#:可以匹配item.sup.insert或item.sup
item.*:只可以匹配item.sup

在publisher服务中编写测试方法

点击查看代码
@SpringBootTest
@RunWith(SpringRunner.class)
public class TopicQueue {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void topicQueue(){
        // 交换机名称
        String exchangeName = "wzh.topic";
        // 消息
        String message = "喜报!孙悟空大败哥斯拉!";
        // 发送消息
        rabbitTemplate.convertAndSend(exchangeName, "news", message);
    }
}
在consumer服务中编写监听消息的类
点击查看代码
@Component
public class TopicListener {
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue1"),
            exchange = @Exchange(name = "wzh.topic",type = ExchangeTypes.TOPIC),
            key = "china.#"
    ))
    public void topic1(String msg){
        System.out.println("消费者1接收到topic.queue1的消息:【" + msg + "】");
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue2"),
            exchange = @Exchange(name = "wzh.topic",type = ExchangeTypes.TOPIC),
            key = "#.news"
    ))
    public void topic2(String msg){
        System.err.println("消费者2接收到topic.queue2的消息:【" + msg + "】");
    }
}
启动项目

image


消息转换器
当我们发送消息的时候,Spring辉将消息进行序列化发送给MQ,接收时又会将信息反序列化成Java对象。但是默认情况下Spring采用默认的JDK序列化方式序列化。但是JDK序列化存在数据体积大,不够安全和可读性性差的问题。所以一般使用Json字符串的方式进行序列化。
使用方法:
引入依赖

点击查看代码
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.10</version>
</dependency>
在生产者和消费者的启动类上添加一个Bean
点击查看代码
@Bean
    public MessageConverter jsonMessageConverter(){
        return new Jackson2JsonMessageConverter();
    }

最后测试一下
consumer

点击查看代码
@Component
public class ObjectListener {
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "object.queue"),
            exchange = @Exchange(name = "wzh.object",type = ExchangeTypes.DIRECT),
            key = "wife"
    ))
    public void object(Map<String, Object> wife){
        System.out.println("my wife is"+wife);
    }
}

publisher

点击查看代码
@SpringBootTest
@RunWith(SpringRunner.class)
public class ObjectQueue {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void objectQueue(){
        //创建一个map类型的对象,该对象作为消息传递
        Map<String, Object> wife = new HashMap<>();
        wife.put("name","miku");
        wife.put("age",18);
        wife.put("sex","girl");
        //声明队列
        String exchangeName="wzh.object";
        //发送消息
        rabbitTemplate.convertAndSend(exchangeName,"wife",wife);
    }
}
最终效果

image

posted @   wzh_Official  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示