RabbitMQ中java实现队列和交换机的声明

java实现队列和交换机的声明

在之前我们都是基于RabbitMQ控制台来创建队列、交换机。但是在实际开发时,队列和交换机是程序员定义的,将来项目上线,又要交给运维去创建。那么程序员就需要把程序中运行的所有队列和交换机都写下来,交给运维。在这个过程中是很容易出现错误的。
因此推荐的做法是由程序启动时检查队列和交换机是否存在,如果不存在自动创建。

在这里插入图片描述

3.8.1.基本API

SpringAMQP提供了一个Queue类,用来创建队列:
image.png

SpringAMQP还提供了一个Exchange接口,来表示所有不同类型的交换机:
image.png
在这里插入图片描述
我们可以自己创建队列和交换机,不过SpringAMQP还提供了ExchangeBuilder来简化这个过程:
image.png
而在绑定队列和交换机时,则需要使用BindingBuilder来创建Binding对象:
image.png

3.8.2.fanout示例(基于Bean声明)

在这里插入图片描述

在consumer中创建一个类,声明队列和交换机:

package com.itheima.consumer.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FanoutConfig {
    /**
     * 声明交换机
     * @return Fanout类型交换机
     */
    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange("hmall.fanout");
    }

    /**
     * 第1个队列
     */
    @Bean
    public Queue fanoutQueue1(){
        return new Queue("fanout.queue1");
    }

    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindingQueue1(Queue fanoutQueue1, FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
    }

    /**
     * 第2个队列
     */
    @Bean
    public Queue fanoutQueue2(){
        return new Queue("fanout.queue2");
    }

    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindingQueue2(Queue fanoutQueue2, FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
    }
}

实际测试:

在这里插入图片描述

package com.itheima.consumer.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FanoutConfiguration {

    /**
     * 声明fanout类型交换机
     * @return
     */
    @Bean
    public FanoutExchange fanoutExchange(){
        // 两种声明方法都可以
        // return ExchangeBuilder.fanoutExchange("hmall.fanout2").build();
        return new FanoutExchange("hmall.fanout2");
    }

    /**
     * 声明默认持久化的fanout.queue3队列
     * @return
     */
    @Bean
    public Queue fanoutQueue3(){
        // 两种声明方法都可以
        // return QueueBuilder.durable("fanout.queue3").build();
        return new Queue("fanout.queue3");
    }

    /**
     * 绑定队列和交换机
     * @param fanoutExchange
     * @param fanoutQueue3
     * @return
     */
    @Bean
    public Binding fanoutBinding3(FanoutExchange fanoutExchange,Queue fanoutQueue3){
        return BindingBuilder.bind(fanoutQueue3).to(fanoutExchange);

    }

    /**
     * 声明默认持久化的fanout.queue4队列
     * @return
     */
    @Bean
    public Queue fanoutQueue4(){
        // 两种声明方法都可以
         return QueueBuilder.durable("fanout.queue4").build();
//        return new Queue("fanout.queue4");
    }


    /**
     * 绑定队列和交换机
     * @return
     */
    @Bean
    public Binding fanoutBinding4(){
        return BindingBuilder.bind(fanoutQueue4()).to(fanoutExchange());

    }
}

3.8.2.direct示例(基于Bean声明)

direct模式由于要绑定多个KEY,会非常麻烦,每一个Key都要编写一个binding:

package com.itheima.consumer.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DirectConfig {

    /**
     * 声明交换机
     * @return Direct类型交换机
     */
    @Bean
    public DirectExchange directExchange(){
        return ExchangeBuilder.directExchange("hmall.direct").build();
    }

    /**
     * 第1个队列
     */
    @Bean
    public Queue directQueue1(){
        return new Queue("direct.queue1");
    }

    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindingQueue1WithRed(Queue directQueue1, DirectExchange directExchange){
        return BindingBuilder.bind(directQueue1).to(directExchange).with("red");
    }
    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindingQueue1WithBlue(Queue directQueue1, DirectExchange directExchange){
        return BindingBuilder.bind(directQueue1).to(directExchange).with("blue");
    }

    /**
     * 第2个队列
     */
    @Bean
    public Queue directQueue2(){
        return new Queue("direct.queue2");
    }

    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindingQueue2WithRed(Queue directQueue2, DirectExchange directExchange){
        return BindingBuilder.bind(directQueue2).to(directExchange).with("red");
    }
    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindingQueue2WithYellow(Queue directQueue2, DirectExchange directExchange){
        return BindingBuilder.bind(directQueue2).to(directExchange).with("yellow");
    }
}

3.8.4.基于注解声明

基于@Bean的方式声明队列和交换机比较麻烦,Spring还提供了基于注解方式来声明。

注意声明的文件是Listener下的,在监听者位置声明

在这里插入图片描述

例如,我们同样声明Direct模式的交换机和队列:

@RabbitListener(bindings = @QueueBinding(
    value = @Queue(name = "direct.queue1"),
    exchange = @Exchange(name = "hmall.direct", type = ExchangeTypes.DIRECT),
    key = {"red", "blue"}
))
public void listenDirectQueue1(String msg){
    System.out.println("消费者1接收到direct.queue1的消息:【" + msg + "】");
}

@RabbitListener(bindings = @QueueBinding(
    value = @Queue(name = "direct.queue2"),
    exchange = @Exchange(name = "hmall.direct", type = ExchangeTypes.DIRECT),
    key = {"red", "yellow"}
))
public void listenDirectQueue2(String msg){
    System.out.println("消费者2接收到direct.queue2的消息:【" + msg + "】");
}

是不是简单多了。
再试试Topic模式:

@RabbitListener(bindings = @QueueBinding(
    value = @Queue(name = "topic.queue1"),
    exchange = @Exchange(name = "hmall.topic", type = ExchangeTypes.TOPIC),
    key = "china.#"
))
public void listenTopicQueue1(String msg){
    System.out.println("消费者1接收到topic.queue1的消息:【" + msg + "】");
}

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

小结

在这里插入图片描述

RabbitMQ是一个开源的消息代理,它允许你通过发布/订阅模型来处理消息传递。动态创建队列和监听是RabbitMQ的一种高级功能,通常用于处理异步任务和事件驱动的应用场景。 在Java,我们可以使用`AMQP`客户端库(如`Spring AMQP`、`Pika`或`Hammock`)来动态创建队列并监听。以下是一个简单的示例,展示了如何使用`Spring AMQP`: ```java import org.springframework.amqp.core.*; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.listener.ChannelAwareMessageListener; public class DynamicQueueExample { private final ConnectionFactory connectionFactory; public DynamicQueueExample(ConnectionFactory connectionFactory) { this.connectionFactory = connectionFactory; } // 创建并绑定动态队列 public void createAndBind(String queueName) { try (Connection connection = connectionFactory.newConnection(); Channel channel = connection.createChannel()) { // 使用交换机创建并绑定队列 String exchangeName = "myExchange"; channel.queueDeclare(queueName, false, false, true, null); channel.queueBind(queueName, exchangeName, routingKey(queueName)); } catch (Exception e) { // 处理异常 e.printStackTrace(); } } // 使用消费者监听队列 public void startListening(ChannelAwareMessageListener listener) { try (Connection connection = connectionFactory.newConnection()) { // 创建消费者并监听指定队列 Channel channel = connection.createChannel(); channel.basicConsume(queueName, true, listener, consumerTag -> {}); } catch (Exception e) { e.printStackTrace(); } } // 动态生成路由键(queueName) private String routingKey(String queueName) { return "#" + queueName; } } // 实现ChannelAwareMessageListener public class MyMessageHandler implements ChannelAwareMessageListener { @Override public void onMessage(Message message, Channel channel) throws Exception { // 处理接收到的消息 String body = new String(message.getBody()); System.out.println("Received message: " + body); } } ``` 在这个例子,我们首先创建了一个连接工厂,然后创建并绑定动态队列。当需要消费队列的消息时,我们创建一个监听器,并启动监听。`MyMessageHandler`实现了`ChannelAwareMessageListener`,以便在接收到消息时可以处理它们。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值