消息队列-RabbitMQ

百度云笔记:RabbitMQ.pdf 提取码:1111

消息队列-RabbitMQ

一.消息中间件

1.简介

消息队列的两种模式
消息队列(mq)是什么?

消息队列MQ:message Queue
消息队列分:RabbitMQ、RocketMQ、Kafka 
本质都是:**一发一存一消费**,也就是**转发器**
模型: 队列模型(点对点模式)、发布-订阅模型
作用:生产者和消费者的通信问题
MQ 的应用场景:
	系统解耦、异步通信、流量削峰。除此之外,还有延迟通知、最终一致性保证、顺序消息、流式处理等等
原理:两次 RPC + 消息转储
MQ 的雏形
	a、直接利用成熟的 RPC 框架(Dubbo 或者 Thrift),实现两个接口:发消息和读消息。
	b、消息放在本地内存中即可,数据结构可以用 JDK 自带的 ArrayBlockingQueue 。

其他请看:消息队列(mq)是什么?

2.应用场景

异步处理

在这里插入图片描述

应用解耦、流量控制

在这里插入图片描述

其他,还有延迟通知、最终一致性保证、顺序消息、流式处理等等

3.概述

1. 大多应用中,可通过消息服务中间件来提升系统异步通信、扩展解耦能力
2. 消息服务中两个重要概念:
消息代理(message broker)和目的地(destination)
当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目的地。
3. 消息队列主要有两种形式的目的地
	• 队列(queue):点对点消息通信(point-to-point)
	• 主题(topic):发布(publish)/订阅(subscribe)消息通信
4. 点对点式:
	• 消息发送者发送消息,消息代理将其放入一个队列中,消息接收者从队列中获
取消息内容,消息读取后被移出队列
	• 消息只有唯一的发送者和接受者,但并不是说只能有一个接收者
5. 发布订阅式:
	• 发送者(发布者)发送消息到主题,多个接收者(订阅者)监听(订阅)这个
主题,那么就会在消息到达时同时收到消息
6. JMS(Java Message Service)JAVA消息服务:
	• 基于JVM消息代理的规范。ActiveMQ、HornetMQ是JMS实现
7. AMQP(Advanced Message Queuing Protocol)
	• 高级消息队列协议,也是一个消息代理的规范,兼容JMS
	• RabbitMQ是AMQP的实现	

在这里插入图片描述

8. Spring支持
	• spring-jms提供了对JMS的支持
	• spring-rabbit提供了对AMQP的支持
	• 需要ConnectionFactory的实现来连接消息代理
	• 提供JmsTemplate、RabbitTemplate来发送消息
	• @JmsListener(JMS)、@RabbitListener(AMQP)注解在方法上监听消息
	代理发布的消息
	• @EnableJms、@EnableRabbit开启支持
9. Spring Boot自动配置
	• JmsAutoConfiguration
	• RabbitAutoConfiguration
10、市面的MQ产品
	• ActiveMQ、RabbitMQ、RocketMQ、Kafka

3、RabbitMQ概念

1).RabbitMQ简介:

RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue Protocol)的开源实现。

2).核心概念

Message消息

消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,
这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可
能需要持久性存储)等。

Publisher消息的生产者

消息的生产者,也是一个向交换器发布消息的客户端应用程序。

Exchange交换器

交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。
Exchange有4种类型:direct(默认),fanout, topic, 和headers,不同类型的Exchange转发消息的策略有所区别

Queue消息队列

消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直
在队列里面,等待消费者连接到这个队列将其取走。

Binding绑定

绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交
换器理解成一个由绑定构成的路由表。
Exchange 和Queue的绑定可以是多对多的关系。

Connection网络连接

网络连接,比如一个TCP连接。

Channel信道

信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内的虚拟连接,AMQP 命令都是通过信道
发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁 TCP 都
是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。

Consumer消息的消费者

消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。

Virtual Host虚拟主机

虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加
密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥
有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时
指定,RabbitMQ 默认的 vhost 是 / 。

Broker消息队列 服务器

表示消息队列服务器实体
在这里插入图片描述
在这里插入图片描述

4、Docker安装RabbitMQ

RabbitMQ官方文档:https://www.rabbitmq.com/networking.html
https://hub.docker.com

1).安装RabbitMQ

自动下载镜像、启动容器

docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:management

4369, 25672 (Erlang发现&集群端口)
5672, 5671 (AMQP端口)
15672 (web管理后台端口)
61613, 61614 (STOMP协议端口)
1883, 8883 (MQTT协议端口)

设置开机启动RabbitMQ,a2fe98e84aca 为RabbitMQ的容器id
	docker update a2fe98e84aca  --restart=always
	或者 
	docker update rabbitmq --restart=always

2).测试、访问RabbitMQ首页

http://192.168.56.10:15672/
账号、密码: guest

5、RabbitMQ运行机制

AMQP 中的消息路由
• AMQP 中消息的路由过程和 Java 开发者熟悉的 JMS 存在一些差别,
AMQP 中增加了 ExchangeBinding 的角色。
生产者把消息发布到 Exchange 上,消息最终到达队列。
并被消费者接收,而 Binding 决定交换器的消息应该发送到那个队列。
在这里插入图片描述

1).Exchange 类型

• Exchange分发消息时根据类型的不同分发策略有区别,目前共四种类型:direct、
fanout、topic、headers 。headers 匹配 AMQP 消息的 header 而不是路由键,
headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了,所以直接
看另外三种类型:

a. Direct Exchange(点对点)

在这里插入图片描述
消息中的路由键(routing key)如果和Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中。
路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为“dog”,则只转发 routing
key 标记为“dog”的消息,不会转发“dog.puppy”,也不会转发“dog.guard” 等等。
它是完全匹配、单播的模式。

b. fanout Exchange(广播)

在这里插入图片描述
每个发到 fanout 类型交换器的消息都会分到所有绑定的队列上去。
fanout 交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。
很像子网广播,每台子网内的主机都获得了一份复制的消息。
fanout 类型转发消息是最快的。

c. topic Exchange(订阅)

在这里插入图片描述
topic 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上。
它将路由键和绑定键的字符串切分成单词,这些单词之间用点隔开。
它同样也会识别两个通配符:符号“#”和符号“*”。#匹配0个或多个单词,*匹配一个单词。

2).创建交换机、队列,绑定队列

在这里插入图片描述

a.创建四个队列

在这里插入图片描述

b.创建3个交换机

在这里插入图片描述

c.交换机绑定队列、交换机–direct直接类型
给交换机绑定队列

在这里插入图片描述

给交换机发送消息

在这里插入图片描述

查看发送消息结果–完全匹配才能获得消息

在这里插入图片描述

获得\消息

在这里插入图片描述
在这里插入图片描述

c2.交换机绑定队列、交换机–fanout扇形类型(广播)
给交换机绑定队列

在这里插入图片描述

给交换机发送消息

在这里插入图片描述

查看发送消息结果–所有队列都能获得消息

在这里插入图片描述

获得消息,与direct一样
c3.交换机绑定队列、交换机–topic主题类型(订阅)
给交换机绑定队列

在这里插入图片描述

给交换机发送消息-路由key:hello.news

在这里插入图片描述

查看发送消息结果–交换机对应的队列绑定策略才能收到消息–实现网关作用

策略:*.news
在这里插入图片描述

获得消息,与direct一样

6.RabbitMQ整合–订单服务order

RabbitMQ官方文档:https://www.rabbitmq.com/networking.html

1. 引入 spring-boot-starter-amqp

    <!--消息队列MQ的依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>

2. application.yml配置

#配合消息队列MQ
spring.rabbitmq.host=192.168.56.10
spring.rabbitmq.port=5672
spring.rabbitmq.virtual-host=/

3. 启动类开启RabbitMQ-- @EnableRabbit

/**RabbitMQ
1.引入amqp场景, RabbitAutoConfiguration就会自动生效
2.对容器自动配置了
	RabbitTemplate、amqpAdmin、CachingConnectionFactory、RabbitMessagingTemplate
	所有属性都是
	@ConfigurationProperties(prefix = "spring.rabbitmq")  RabbitProperties
3.配置文件配置spring.rabbitmq
4.@EnableRabbit,开启Rabbit消息队列

4. 测试

	 1). AmqpAdmin:管理组件
	 2). RabbitTemplate:消息发送处理组件
	 3). @RabbitListener 监听消息的方法可以有三种参数(不分数量,顺序)
		• Object content, Message message, Channel channel

4.测试代码RabbitMQ

0.流程+原理

RabbitMQ
 1.引入amqp场景, RabbitAutoConfiguration就会自动生效
 2.对容器自动配置了
 	  RabbitTemplate、amqpAdmin、CachingConnectionFactory、RabbitMessagingTemplate
  	 所有属性都是
       @ConfigurationProperties(prefix = "spring.rabbitmq")  RabbitProperties
3.配置文件配置spring.rabbitmq
4.启动类@EnableRabbit,开启Rabbit消息队列
5.监听消息:使用@RabbitListener.必须有@EnableRabbit
   @RabbitListener,加在类+方法上(监听哪些队列)
   @RabbitHandler,加在方法上(重载区分不同的消息)

1.如何创建Exchange、Queue、Binding

 	* 1).使用amqpAdmin
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class GulimallOrderApplicationTests {
    @Autowired
    AmqpAdmin amqpAdmin;
    
    //1.创建交换机
    @Test
    public void createExchange() {
        //String name, boolean durable, boolean autoDelete, Map<String, Object> arguments
        DirectExchange directExchange = new DirectExchange("hello-java-exchange", true, false);
        amqpAdmin.declareExchange(directExchange);
        log.info("Exchange [{}] 交换机创建成功", "hello-java-exchange");
    }

    //2.创建队列
    @Test
    public void createQueue() {
        //String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
        Queue queue = new Queue("hello-java-queue",true,false,false);
        amqpAdmin.declareQueue(queue);
        log.info("Queue [{}] 队列创建成功", "hello-java-queue");
    }
    
    //3.创建绑定关系
    @Test
    public void createBinding() {
        //String destination, Binding.DestinationType destinationType, String exchange, String routingKey, Map<String, Object> arguments
       //将exchange指定交换机 绑定 destination指定的队列,使用routingKey作为指定路由键
        Binding binding = new Binding("hello-java-queue", Binding.DestinationType.QUEUE,
                "hello-java-exchange","hello.java", null);
        amqpAdmin.declareBinding(binding);
        log.info("Binding [{}] 队列创建成功", "hello-java-Binding");
    }
}

2.如何发送信息

1).消息是字符串
//发送消息
@Test
public void sendMessage() {
 
   String  msg="hello world";
    //String exchange, String routingKey, Object object
    rabbitTemplate.convertAndSend("hello-java-exchange","hello.java",msg);
    log.info("发送消息成功: [{}]", msg);
}
2).如果发送的消息是对象,对象必须序列化。必须有rabbitConfig
    //发送消息:对象
    @Test
    public void sendMessageEntity() {
        //1.如果发送的消息是对象,对象必须序列化
            OrderItemEntity orderItem = new OrderItemEntity();
            orderItem.setSpuName("手机 ");
            orderItem.setSkuName("华为p30");
            //2.把对象转换为JSON数据。需要MyRabbitConfig
            rabbitTemplate.convertAndSend("hello-java-exchange","hello.java",orderItem);
            log.info("发送消息成功: [{}]", orderItem);
    }

    //发送多个消息:对象
    @Test
    public void sendMessageEntity2() {
        //1.如果发送的消息是对象,对象必须序列化
        for (int i = 0; i <10 ; i++) {
            OrderItemEntity orderItem = new OrderItemEntity();
            orderItem.setSpuName("手机 ");
            orderItem.setSkuName("华为p30"+i);
            //2.把对象转换为JSON数据。需要MyRabbitConfig
            rabbitTemplate.convertAndSend("hello-java-exchange","hello.java",orderItem);
            log.info("发送消息成功: [{}]", orderItem);
        }
    }
    //发送多种消息:对象
    @Test
    public void sendMessageEntity3() {
        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0) {
                OrderReturnReasonEntity orderItem = new OrderReturnReasonEntity();
                orderItem.setId((long) i);
                rabbitTemplate.convertAndSend("hello-java-exchange", "hello.java", orderItem);
            } else {
                OrderEntity order = new OrderEntity();
                order.setId((long) i);
                rabbitTemplate.convertAndSend("hello-java-exchange", "hello.java", order);
            }
            log.info("发送消息成功: ");
        }
    }
@Configuration
public class MyRabbitConfig {
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }
    }

3.如何接收信息-OrderItemServiceImpl

 @Service("orderItemService")
@RabbitListener(queues = {"hello-java-queue"})
public class OrderItemServiceImpl extends ServiceImpl<OrderItemDao, OrderItemEntity> implements OrderItemService {

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderItemEntity> page = this.page(
                new Query<OrderItemEntity>().getPage(params),
                new QueryWrapper<OrderItemEntity>()
        );

        return new PageUtils(page);
    }

    //queues:声明要监听的所有队列
//    @RabbitListener(queues = {"",""})
//    @RabbitListener(queues = {"hello-java-queue"})
    public void recieveMessage(Object message) {
        System.out.println("接收的消息: " + message + "===>类型: " + message.getClass());
    }

    /**
     * 参数类型
     * 1.Message :原生消息详细信息。头+体。org.springframework.amqp.core.Message;
     * 2.T<发送消息的类型> OrderReturnReasonEntity
     * 3.Channel:当前传输数据的通道。com.rabbitmq.client.Channel
     *
     *  Queue:可以很多人来监听,只要收到消息,队列删除消息,而且只有一个人收到此消息
     *  场景:
     *      1).订单服务启动多个。同一个消息,只能有一个客户端收到。
     *      2).只有一个消息完全处理完,方法运行结束,才可以接收下一个消息。
     *
     */
    @RabbitHandler
    public void recieveMessage(Message message, OrderReturnReasonEntity content, Channel channel) {
        byte[] body = message.getBody();
        MessageProperties properties = message.getMessageProperties();
        System.out.println("接收的消息内容1: " + message);
    }
     @RabbitHandler
    public void recieveMessage2(OrderEntity content) {
         System.out.println("接收的消息内容2: " + content);
    }
    }

4.发送信息- RabbitController

@RestController
@Slf4j
public class RabbitController {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @GetMapping("/sendMsg")
    public String sendMsg(@RequestParam(value = "num",defaultValue = "10") Integer num) {
        for (int i = 0; i < num; i++) {
            if (i % 2 == 0) {
                OrderReturnReasonEntity orderItem = new OrderReturnReasonEntity();
                orderItem.setId((long) i);
                rabbitTemplate.convertAndSend("hello-java-exchange", "hello.java", orderItem);
            } else {
                OrderEntity order = new OrderEntity();
                order.setId((long) i);
                rabbitTemplate.convertAndSend("hello-java-exchange", "hello.java", order);
            }
            log.info("发送消息成功: ");
        }
        return "ok";
    }
}

7.RabbitMQ消息确认机制-可靠抵达(可靠投递)

RabbitMQ-可靠投递文档
• 保证消息不丢失,可靠抵达,可以使用事务消息,性能下降250倍,为此引入确认机制
• publisher confirmCallback :确认模式
• publisher returnCallback: 未投递到 queue 退回模式
• consumer: ack机制(Ack消息确认机制)

在这里插入图片描述

a.可靠抵达-ConfirmCallback

• spring.rabbitmq.publisher-confirms=true
• 在创建 connectionFactory 的时候设置 PublisherConfirms(true) 选项,开启
confirmcallback 。
• CorrelationData:用来表示当前消息唯一性。
• 消息只要被 broker 接收到就会执行 confirmCallback,如果是 cluster 模式,需要所有
broker 接收到才会调用 confirmCallback。
• 被 broker 接收到只能表示 message 已经到达服务器,并不能保证消息一定会被投递
到目标 queue 里。所以需要用到接下来的 returnCallback 。

b.可靠抵达-ReturnCallback

• spring.rabbitmq.publisher-returns=true
•pring.rabbitmq.template.mandatory=true

• confrim 模式只能保证消息到达 broker,不能保证消息准确投递到目标 queue 里。在有
些业务场景下,我们需要保证消息一定要投递到目标 queue 里,此时就需要用到
return 退回模式。
• 这样如果未能投递到目标 queue 里将调用 returnCallback ,可以记录下详细到投递数
据,定期的巡检或者自动纠错都需要这些数据。

b.可靠抵达-Ack消息确认机制

spring.rabbitmq.listener.simple.acknowledge-mode=manual

•消费者获取到消息,成功处理,可以回复Ack给Broker
•basic.ack用于肯定确认;broker将移除此消息
•basic.nack用于否定确认;可以指定broker是否丢弃此消息,可以批量
•basic.reject用于否定确认;同上,但不能批量
•默认自动ack,消息被消费者收到,就会从broker的queue中移除
•queue无消费者,消息依然会被存储,直到消费者消费
•消费者收到消息,默认会自动ack。但是如果无法确定此消息是否被处理完成,
或者成功处理。我们可以开启手动ack模式
•消息处理成功,ack(),接受下一个消息,此消息broker就会移除
•消息处理失败,nack()/reject(),重新发送给其他人进行处理,或者容错处理后ack
•消息一直没有调用ack/nack方法,broker认为此消息正在被处理,不会投递给别人,此时客户
端断开,消息不会被broker移除,会投递给别人

手动确认ack消息

spring.rabbitmq.listener.simple.acknowledge-mode=manual

配置文件

#配合消息队列MQ
spring.rabbitmq.host=192.168.56.10
spring.rabbitmq.port=5672
spring.rabbitmq.virtual-host=/

#RabbitMQ消息确认机制-可靠抵达
#publisher confirmCallback ,开启发送端确认模式
spring.rabbitmq.publisher-confirms=true
#publisher returnCallback ,开启发送端消息抵达队列的确认。未投递到 queue 退回模式
spring.rabbitmq.publisher-returns=true
#只要抵达队列,以异步发送,优先回调我们这个return confirm返回确认
spring.rabbitmq.template.mandatory=true

配置类

  定制RabbitTemplate
   1、服务收到消息就会回调
    1)、spring.rabbitmq.publisher-confirms: true
    2)、设置确认回调
   2、消息正确抵达队列就会进行回调
    1)、spring.rabbitmq.publisher-returns: true
        spring.rabbitmq.template.mandatory: true
    2)、设置确认回调ReturnCallback
  3、消费端确认(保证每个消息都被正确消费,此时才可以broker删除这个消息)
    spring.rabbitmq.listener.simple.acknowledge-mode=manual 手动签收
   1).默认是自动确认的,只要消息接收到,客户端会自动确认,服务端就会移除这个消息
       问题:收到很多消息,自动回复给服务器,只要有一个消息处理成功,宕机了。发生消息丢失
       解决:消费者手动确认模式。
           只要我们没有明确告诉mq,货物被签收。没有ack,消息一直unacked。
           即使consumer宕机,消息永远不会丢失,会重新变为ready,这次新的consumer连接进来就发给他
   2).如何签收呢?
       channel.basicAck(deliveryTag,false);签收成功。业务成功完成,就应该签收
        channel.basicNack(deliveryTag,false,true); 拒收。业务失败,拒签
        channel.basicReject(deliveryTag,false); 拒收
		  1initRabbitTemplate()
		  只要消息抵达Broker,就ack=true
             correlationData:当前消息的唯一关联数据(这个是消息的唯一id)
             ack:消息是否成功收到
             cause:失败的原因
           2.rabbitTemplate.setReturnCallback()
           只要消息没有投递给指定的队列,就触发这个失败回调
           message:投递失败的消息详细信息
           replyCode:回复的状态码
           replyText:回复的文本内容
           exchange:当时这个消息发给哪个交换机
           routingKey:当时这个消息用哪个路邮键
@Configuration
public class MyRabbitConfig {
    @Autowired
//    private RabbitTemplate rabbitTemplate;
    RabbitTemplate rabbitTemplate;

//    @Primary
//    @Bean
//    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
//        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
//        this.rabbitTemplate = rabbitTemplate;
//        rabbitTemplate.setMessageConverter(messageConverter());
//        initRabbitTemplate();
//        return rabbitTemplate;
//    }

    //消息数据转为JSON数据
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }
 
    @PostConstruct  //MyRabbitConfig对象创建完成以后,执行这个方法
    public void initRabbitTemplate() {
        //1.设置确认回调
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            System.out.println("发送信息成功,confirm...correlationData[" + correlationData + "]==>ack:[" + ack + "]==>cause:[" + cause + "]");
        });

        /**
           2.只要消息没有投递给指定的队列,就触发这个失败回调
         */
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                System.out.println("发送失败的消息: [" + message + "]==>replyCode[" + replyCode + "]" +
                        "==>replyText[" + replyText + "]==>exchange[" + exchange + "]==>routingKey[" + routingKey + "]");
            }
        });
    }
}

OrderItemServiceImpl

@Service("orderItemService")
@RabbitListener(queues = {"hello-java-queue"})
public class OrderItemServiceImpl extends ServiceImpl<OrderItemDao, OrderItemEntity> implements OrderItemService{

    //queues:声明要监听的所有队列
//    @RabbitListener(queues = {"",""})
//    @RabbitListener(queues = {"hello-java-queue"})
    public void recieveMessage(Object message) {
        System.out.println("接收的消息: " + message + "===>类型: " + message.getClass());
    }

    /**
     * 参数类型
     * 1.Message :原生消息详细信息。头+体。org.springframework.amqp.core.Message;
     * 2.T<发送消息的类型> OrderReturnReasonEntity
     * 3.Channel:当前传输数据的通道。com.rabbitmq.client.Channel
     * <p>
     * Queue:可以很多人来监听,只要收到消息,队列删除消息,而且只有一个人收到此消息
     * 场景:
     * 1).订单服务启动多个。同一个消息,只能有一个客户端收到。
     * 2).只有一个消息完全处理完,方法运行结束,才可以接收下一个消息。
     */
    @RabbitHandler
    public void recieveMessage(Message message, OrderReturnReasonEntity content, Channel channel)  {
        byte[] body = message.getBody();
        MessageProperties properties = message.getMessageProperties();
        System.out.println("接收的消息内容1: " + message);
        //通道内按顺序是自增的
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        System.out.println("deliveryTag: " +deliveryTag);
        //签收消息,非批量签收
        try {
            if (deliveryTag%2==0){
                //收货
                channel.basicAck(deliveryTag,false);
                System.out.println("签收信息成功! "+deliveryTag);
            }else {
                //退货。requeue=false表示退货,requeue=true 发回服务器,服务器重新入队
                //long deliveryTag, boolean multiple, boolean requeue 。deliveryTag、是否批量、重新入队列
                channel.basicNack(deliveryTag,false,true);
                //long var1, boolean var3
//                channel.basicReject();
                System.out.println("签收信息失败。。。"+deliveryTag);
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("签收信息失败!");
        }
    }

    @RabbitHandler
    public void recieveMessage2(OrderEntity content) {
        System.out.println("接收的消息内容2: " + content);
    }

8.、RabbitMQ延时队列(实现定时任务)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值