SpringBoot整合RabbitMQ

图片来自百战尚学堂 

目录

RabbitMQ的优点

SpringBoot整合RabbitMQ

        简单模式

        工作队列模式

        发布订阅模式

        路由模式

        通配符模式

消息的可靠性传递

        确认模式

        返回模式

        Ack模式


 

RabbitMQ的优点

1、削峰填谷

在电商平台中,尝尝会有一些大型的活动,例如:双十一,618等等,这种活动会使服务器的工作量瞬间提升,但是平时点击量却是呈现出一种平原的样子,只有在有活动的时候突然点击量飙升,那么服务器有可能会因为处理不过来而崩溃 ,所以RabbitMQ的优点之一就是削峰填谷

2、应用解耦

一个电商平台项目会用很多各种系统,例如用户下单会调用订单系统,订单系统会调用库存系统、支付系统、物流系统完成业务,此时会产生两个问题:

        1、如果其中某一个系统发生了故障,就会导致整个平台崩溃

        2、如果我们需要添加一个系统,此时就必须更改源代码

如果在系统中引入MQ,即订单系统将消息先发送到MQ中,MQ再转发到其他系统,则会解决以下问题:

  1. 由于订单系统只发消息给MQ,不直接对接其他系统,如果库存系统出现故障,不影响整个订单。
  2. 如果需求修改,新增了一个X系统,此时无需修改订单系统的代码,只需修改MQ将消息发送给X系统即可。

3、异步提速

如果订单系统同步访问每个系统,则用户下单等待时长如下:

如果引入MQ,则用户下单等待时长如下:

 

SpringBoot整合RabbitMQ

RabbitMQ有很多种交换机,不同的交换机有不同的模式:简单模式,工作队列模式,发布订阅模式,路由模式,通配符模式,下面我们就来讲讲最常用的通配符模式。

        通配符模式

通配符模式(Topic)是在路由模式的基础上,给队列绑定带通配符的路由关键字,只要消息的RoutingKey能实现通配符匹配,就会将消息转发到该队列。通配符模式比路由模式更灵活,使用topic交换机

 

通配符规则:

  1. 消息设置RoutingKey时,RoutingKey由多个单词构成,中间以.分割。
  2. 队列设置RoutingKey时,#可以匹配任意多个单词,*可以匹配任意一个单词。
  3. 路由关键字的特点为由多个单词组成,中间以.()隔开

 

 1、通过配置类将交换机和队列创建出来并绑定

@Configuration
public class RabbitConfig {
    private final String NORMAL_EXCHANGE="normal_exchange";//普通交换机
    private final String NORMAL_QUEUE="normal_queue";//普通队列


    //普通交换机
    @Bean("normal_exchange")
    public Exchange Exchange(){
        //topicExchange代表这是一个通配符交换机
        //durable代表消息持久化,rabbitmq重启消息不回丢失
        return ExchangeBuilder.topicExchange(NORMAL_EXCHANGE).durable(true).build();
    }

    //普通队列绑定死信交换机以及死信路由关键字
    @Bean("normal_queue")
    public Queue Queue(){
        //durable代表消息持久化
        //ttl代表消息事件,1000ms=1s
        //maxLength代表队列最大长度
        return QueueBuilder.durable(NORMAL_QUEUE).ttl(10000).maxLength(10).build();
    }

    //普通交换机绑定普通队列
    @Bean
    public Binding bingQueue(@Qualifier("normal_exchange") Exchange exchange,@Qualifier("normal_queue") Queue queue){
        //bind队列to交换机with路由关键字
        return BindingBuilder.bind(queue).to(exchange).with("normal_routing").noargs();
    }

}

2、在测试类中生产消息

@SpringBootTest
class BlograbbitApplicationTests {

    //SpringBoot整合RabbitMQ可以使用RabbitTemplate省略创建连接和信道的过程
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void publisher(){
        /**
         * 参数一:交换机名
         * 参数二:路由关键字
         * 参数三:消息内容
         */
        rabbitTemplate.convertAndSend("normal_exchange","normal_routing","你好,消费者!");
    }

}

 打开RabbitMQ的管控台插件查看队列中是否有消息

3、编写消费者代码

@Component
public class RabbitConsumer {

    //监听队列消费信息
    @RabbitListener(queues = "normal_queue")//监听的队列名
    public void listen(String message){
        System.out.println(message);
    }
    
}

4、当我们运行启动类即可消费消息(注意因为我们在定义的时候定义了队列中消息的存活时间为10s,所以需要尽快消费,否则就会过期无法消费)

 

消息的可靠性传递

RabbitMQ消息投递的路径为:

生产者--->交换机--->队列--->消费者

在RabbitMQ工作的过程中,每个环节消息都可能传递失败,那么RabbitMQ是如何监听消息是否成功投递的呢?

  • 确认模式(confirm):可以监听消息是否从生产者成功传递到交换机。
  • 退回模式(return):可以监听消息是否从交换机成功传递到队列。
  • 消费者消息确认(Consumer Ack):可以监听消费者是否成功处理消息。

通过更改之前已经写好的类实现消息的可靠性传递 

        确认模式

        返回模式

@SpringBootTest
class BlograbbitApplicationTests {

    //SpringBoot整合RabbitMQ可以使用RabbitTemplate省略创建连接和信道的过程
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void publisher(){

        //确认模式回调方法
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean b, String s) {
                if (b){
                    System.out.println("confirm接收成功");
                }else{
                    System.out.println("confirm接受失败");
                }
            }
        });

        //返回模式只有在交换机失败发送消息给队列时才会调用
        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
            @Override
            public void returnedMessage(ReturnedMessage returned) {
                System.out.println("消息对象:"+returned.getMessage());
                System.out.println("错误码:"+returned.getReplyCode());
                System.out.println("错误信息:"+returned.getReplyText());
                System.out.println("交换机:"+returned.getExchange());
                System.out.println("路由键:"+returned.getRoutingKey());
                // 处理消息...
            }
        });
        /**
         * 参数一:交换机名
         * 参数二:路由关键字
         * 参数三:消息内容
         */
        rabbitTemplate.convertAndSend("normal_exchange","normal_routing","你好,消费者!");
    }

}

        Ack模式

在RabbitMQ中,消费者接收到消息后会向队列发送确认签收的消息,只有确认签收的消息才会被移除队列。这种机制称为消费者消息确认(Consumer Acknowledge,简称Ack)。类似快递员派送快递也需要我们签收,否则一直存在于快递公司的系统中。

消息分为自动确认和手动确认。自动确认指消息只要被消费者接收到,无论是否成功处理消息,则自动签收,并将消息从队列中移除。但是在实际开发中,收到消息后可能业务处理出现异常,那么消息就会丢失。此时需要设置手动签收,即在业务处理成功再通知签收消息,如果出现异常,则拒签消息,让消息依然保留在队列当中。(默认为手动签收)

  • 自动确认:spring.rabbitmq.listener.simple.acknowledge="none"
  • 手动确认:spring.rabbitmq.listener.simple.acknowledge="manual"
@Component
public class RabbitConsumer {

    //监听队列消费信息
    @RabbitListener(queues = "normal_queue")//监听的队列名
    public void listen(Message message, Channel channel) throws IOException, InterruptedException {
        //获取消息投递序号,消息每次投递序号+1
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        try{
            //模拟发生错误
            int i = 1/0;
            //签收消息
            /**
             * 参数一:消息投递序号
             * 参数二:是否一次签收多条消息
             */
            channel.basicAck(deliveryTag,true);
        }catch (Exception ex){
            System.out.println("消息消费失败!");
            Thread.sleep(2000);
            // 拒签消息
            /**
             * 参数1:消息投递序号
             * 参数2:是否一次可以拒签多条消息
             * 参数3:拒签后消息是否重回队列
             */
            channel.basicNack(deliveryTag,true,true);

        }

        System.out.println(message);
    }

}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值