RabbitMQ的五种模式的实现

配置

环境java11+SpringCloud+Springboot

spring:
#基础配置
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual-host: /
    #发送端配置
    publisher-confirms: true
    publisher-returns: true
    template:
      mandatory: false
    #接收端配置
    listener:
      simple:
        #手动应答
        acknowledge-mode: manual
        #每次接受一条
        prefetch: 1
      direct: 
        acknowledge-mode: manual
        prefetch: 1

创建一些bean,类似的省略

    @Autowired
    private RabbitTemplate rabbitTemplate;
    /*---------------------------注入6个队列--------------------*/
    @Lazy
    @Resource(name="queue1")
    private Queue queue1;
    /*---------------------------注入3种交换机--------------------*/
    //无key
    @Lazy
    @Resource(name="fanoutExchange")
    private FanoutExchange fanoutExchange;
    
    //key模糊匹配
    @Lazy
    @Resource(name="topicExchange")
    private TopicExchange topicExchange;
    
    //key直接匹配
    @Lazy
    @Resource(name="directExchange")
    private DirectExchange directExchange;

    /*---------------------------bean的创建部分--------------------*/
    /**
     * 创建6个队列交给spring管理
     */
    @Bean(autowire = Autowire.BY_NAME, name = "queue1")
    private Queue queue1() {
        // 第一个参数是队列名字, 第二个参数是指是否持久化
        return new Queue(QUEUE1, false);
    }

    @Bean(autowire = Autowire.BY_NAME, name = "queue6")
    private Queue queue6() {
        return new Queue(QUEUE6, false);
    }

    //Topic交换器
    @Bean(autowire = Autowire.BY_NAME, name = "topicExchange")
    public TopicExchange topicExchange() {
        return new TopicExchange(TOPIC_EXCHANGE);
    }

    //绑定,把队列交给交换器管理
    @Bean(autowire = Autowire.BY_NAME, name = "bind1")
    public Binding bind1() {
        return BindingBuilder.bind(queue1).to(topicExchange).with("asdf.zs");
    }

    @Bean(autowire = Autowire.BY_NAME, name = "bind3")
    public Binding topicBinding3() {
        return BindingBuilder.bind(queue3).to(directExchange).with("hh.zs");
    }

    /**
     * fanout交换机
     */
    @Bean(autowire = Autowire.BY_NAME, name = "fanoutExchange")
    public FanoutExchange fanoutExchange() {
        return new FanoutExchange(FANOUT_EXCHANGE);
    }

    @Bean(autowire = Autowire.BY_NAME, name = "bind4")
    public Binding topicBinding4() {
        return BindingBuilder.bind(queue4).to(fanoutExchange);
    }

    /**
     * direct交换机
     */
    @Bean(autowire = Autowire.BY_NAME, name = "directExchange")
    public DirectExchange directExchange(){
        return new DirectExchange(DIRECT_EXCHANGE);
    }

Springboot启动时,对rabbitTemlate的配置

	@PostConstruct
    public void setApplicationContext(){
        // 消息发送失败返回到队列中, yml需要配置 publisher-returns: true
        rabbitTemplate.setMandatory(true);

        // 消息返回, yml需要配置 publisher-returns: true
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            String correlationId = message.getMessageProperties().getCorrelationId();
            System.out.println(correlationId);
        });

        // 消息确认, yml需要配置 publisher-confirms: true
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                System.out.println("消息发送到成功");
            } else {
                System.out.println("消息发送到exchange失败,原因: {}"+cause);
            }
        });
    }

实现

简单模式

生产者和消费者一对一,一条消息被消费一次

生产者
队列
消费者

生产者

	/**
     * 简单传输,单个生产者+单个队列+单个消费者
     */
    public void simpleSend(String doc){
        rabbitTemplate.convertAndSend(RabbitMQConfig.QUEUE1,doc);
    }

消费者

@RabbitListener(queues = RabbitMQConfig.QUEUE1)
    public void receiverQueue2(String json, Channel channel, Message message) {
        try {
            //告诉服务器收到这条消息已经被消费了
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            System.out.println("监听A"+json);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("receiver fail");
        }
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

工作模式

生产者和消费者一对多,

生产者
队列
消费者
消费者

生产者一样,消费者有多个监听同一个队列,在接受端配置了每次从消息队列接收一个,处理完了响应,告诉队列可以消息已经被消费可以被销毁了,然后再接受下一个,多个消费者可以均匀分配,不会让一个一直工作另一个一直闲置。

发布订阅模式

用到FanoutExchange交换机,生产者和消费者一对多,一条消息被每个队列消费一次

生产者
FanoutExchange
队列
队列
队列
消费者
消费者
消费者
    /**
     * 发布订阅
     */
    public void sendFanoutExchangeQueue(String json) {
        rabbitTemplate.convertAndSend(RabbitMQConfig.FANOUT_EXCHANGE,null,json);
    }

我绑定4和5,所以这两个队列收到消息

    @Bean(autowire = Autowire.BY_NAME, name = "bind4")
    public Binding topicBinding4() {
        return BindingBuilder.bind(queue4).to(fanoutExchange);
    }

    @Bean(autowire = Autowire.BY_NAME, name = "bind5")
    public Binding topicBinding5() {
        return BindingBuilder.bind(queue5).to(fanoutExchange);
    }

路由模式

用到DirectExchange交换机,生产者和消费者一对多,一条消息被指定每个队列消费一

X
X
生产者
DirectExchange key=kka
队列 key=zz
队列 key=kka
队列 key=kk
消费者
消费者
消费者
    /**
     * 路由模式
     */
    public void sendDirectExchangeQueue(String json) {
        rabbitTemplate.convertAndSend(RabbitMQConfig.DIRECT_EXCHANGE,"ni",json);
    }

发送的key必须和绑定的key完全一样才能匹配到

    @Bean(autowire = Autowire.BY_NAME, name = "bind4")
    public Binding topicBinding4() {
        return BindingBuilder.bind(queue4).to(directExchange).with("hao");
    }

    @Bean(autowire = Autowire.BY_NAME, name = "bind5")
    public Binding topicBinding5() {
        return BindingBuilder.bind(queue5).to(directExchange).with("nihao");
    }

    @Bean(autowire = Autowire.BY_NAME, name = "bind6")
    public Binding topicBinding6() {
        return BindingBuilder.bind(queue6).to(directExchange).with("ni");
    }

话题模式

用到了TopicExchange交换机,生产者和消费者一对多,一条消息被符合规则的每个队列消费一次

生产者
TopicExchange key
队列 key=zs.zz
队列 key=gold.zs.zz
队列 key=tt.zs.zz
队列 key=zs.kk
消费者
消费者
消费者
消费者

先设置这三个绑定

    //三个绑定,吧队列交给交换器管理
    @Bean(autowire = Autowire.BY_NAME, name = "bind1")
    public Binding bind1() {
        return BindingBuilder.bind(queue1).to(topicExchange).with("*.*.zs");
    }

    @Bean(autowire = Autowire.BY_NAME, name = "bind2")
    public Binding topicBinding2() {
        return BindingBuilder.bind(queue2).to(topicExchange).with("as.*.*");
    }

    @Bean(autowire = Autowire.BY_NAME, name = "bind3")
    public Binding topicBinding3() {
        return BindingBuilder.bind(queue3).to(topicExchange).with("#.zs");
    }

结果是三个都匹配到了,单词之间用.分割,*匹配一个单词,#匹配多个单词。

    /**
     * 话题
     */
    public void sendTopicExchangeQueue(String json) {
        rabbitTemplate.convertAndSend(RabbitMQConfig.TOPIC_EXCHANGE,"as.tt.zs",json);
    }

在试三个不一样的

"as.*.zs"
"*.tt.*"
"#.*.zs"
"as.tt.zs"

和前面理解的一样,#支持0个,*可以在中间或两边

最后补充

测试的时候每次启动生产者都会新建绑定,改了绑定的key再启动,旧的也没删除,影响测试结果,可以在rabbitMQ的界面点开相应的交换器查看,确认失败的消息再下次启动生产者会重新进入发送队列,配置了work模式,消费端没确认,队列会阻塞,因为work模式受到确认才给他下一个消息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值