组件整合之RabbitMQ

引入依赖

<!-- spring-rabbit -->
<dependency>
  <groupId>org.springframework.amqp</groupId>
  <artifactId>spring-rabbit</artifactId>
  <version>2.3.10</version>
</dependency>

用户管理组件RabbitAdmin

RabbitAdmin 类可以很好的操作 rabbitMQ,在 Spring 中直接进行注入即可。

autoStartup 必须设置为 true,否则 Spring 容器不会加载它。

RabbitAdmin实现了4个Interface: AmqpAdmin, ApplicationContextAware, ApplicationEventPublisherAware,InitializingBean。

AmqpAdmin

为AMQP指定一组基本的便携式AMQP管理操作。

ApplicationEventPublisherAware

实现该接口的类,通过函数setApplicationEventPublisher()获得它执行所在的ApplicationEventPublisher。

RabbitAdmin借助于 ApplicationContextAware 和 InitializingBean来获取我们在配置类中声明的exchange, queue, binding beans等信息并调用channel的相应方法来声明。

  • 首先,RabbitAdmin借助于ApplicationContextAware来获取ApplicationContext applicationContext
  • 然后,借助于InitializingBean以及上面的applicationContext来实现rabbitMQ entity的声明

下面是RabbitAdmin中afterPropertiesSet()函数的代码片段。这里在创建connection的时候调用函数initialize()。

于是以此为突破口进行源码分析:

(1)RabbitAdmin#afterPropertiesSet

这里最后分别调用函数declareExchanges(),declareQueues(),declareBindings()来声明RabbitMQ Entity。

(2)先定义了三个集合,利用applicationContext.getBeansOfType来获得container中的Exchange,Queue,Binding声明放入集合中

(3)然后调用filterDeclarables()来过滤不能declareable的bean

(4)按照RabbitMQ的方式拼接

(5)使用rabbitTemplate执行交互

3、实操

查看管控台

SpringAMQP声明

RabbitMQ声明式配置使用SpringAMQP 声明,即在 rabbit 基础 API 里面声明一个 exchange、Bingding、queue。使用SpringAMQP 去声明,就需要使用 @Bean 的声明方式。

查看管控台

消息模板RabbitTemplate

RabbitTemplate是与 SpringAMQP 整合发送消息的关键类,它提供了丰富的发送消息方法。包括可靠性投递消息方法、回调监听消息接口 ConfirmCallback、返回值确认接口 ReturnCallback等。

同样的,我们需要注入到 Spring 容器中,然后直接使用。

RabbitTemplate 在 Spring 整合时需要实例化,但是在 Springboot 整合时,在配置文件里添加配置即可。

先声明bean:

测试

SpringAMQP消息容器

SimpleMessageListenerContainer这个类非常的强大,我们可以对它进行很多的设置,用对于消费者的配置项,这个类都可以满足。它有监听单个或多个队列、自动启动、自动声明功能。

  • 设置事务特性、事务管理器、事务属性、事务并发、是否开启事务、回滚消息等。但是我们在实际生产中,很少使用事务,基本都是采用补偿机制
  • 设置消费者数量、最小最大数量、批量消费
  • 设置消息确认和自动确认模式、是否重回队列、异常捕获 Handler 函数
  • 设置消费者标签生成策略、是否独占模式、消费者属性等
  • 设置具体的监听器、消息转换器等等。

SimpleMessageListenerContainer可以进行动态设置,比如在运行中的应用可以动态的修改其消费者数量的大小、接收消息的模式等。很多基于 RabbitMQ 的自制定化后端管控台在进行设置的时候,也是根据这一去实现的。

SpringAMQP消息适配器

MessageListenerAdapter消息监听适配器,通过反射将消息处理委托给目标监听器的处理方法,并进行灵活的消息类型转换。

允许监听器方法对消息内容类型进行操作,完全独立于RabbitMQ API。

默认情况下,传入Rabbit消息的内容在被传递到目标监听器方法之前被提取,以使目标方法对消息内容类型进行操作以String或者byte类型进行操作,而不是原始Message类型。 (消息转换器)。

消息类型转换委托给MessageConverter接口的实现类。 默认情况下,将使用SimpleMessageConverter。 (如果您不希望进行这样的自动消息转换,那么请自己通过#setMessageConverter MessageConverter设置为null)。

如果目标监听器方法返回一个非空对象(通常是消息内容类型,例如String或byte数组),它将被包装在一个Rabbit Message 中,并发送使用来自Rabbit ReplyTo属性或通过#setResponseRoutingKey(String)指定的routingKey的routingKey来传送消息。(使用rabbitmq 来实现异步rpc功能时候会使用到这个属性)。

注意:发送响应消息仅在使用ChannelAwareMessageListener入口点(通常通过Spring消息监听器容器)时可用。 用作MessageListener不支持生成响应消息。

继承自AbstractAdaptableMessageListener类,实现了MessageListener和ChannelAwareMessageListener接口,而MessageListener和ChannelAwareMessageListener接口的onMessage方法就是具体容器监听队列处理队列消息的方法。

(1)委托类MessageDelegate,类中定义的方法也就是目标监听器的处理方法

(2)配置类代码

(3)运行测试代码

使用MessageListenerAdapter处理器进行消息队列监听处理:

  • ① 如果容器没有设置setDefaultListenerMethod,则处理器中默认的处理方法名是handleMessage
  • ② 如果设置了setDefaultListenerMethod

则处理器中处理消息的方法名就是setDefaultListenerMethod方法参数设置的值

也可以通过setQueueOrTagToMethodName方法为不同的队列设置不同的消息处理方法。

消息转换器MessageConverter

MessageConverter我们在进行发送消息的时候,正常情况下消息体为二进制的数据方式进行传输,如果希望内部帮我们进行转换,或者指定自定义的转换器,就需要用到 MessageConverter了。

我们自定义常用转换器,都需要实现这个接口,然后重写其中的两个方法:

常见的转换器:

  • Json 转换器 - jackson2JsonMessageConverter Java 对象的转换功能
  • DefaultJackson2JavaTypeMapper 映射器 Java对象的映射关系
  • 自定义二进制转换器 比如图片类型、PDF、PPT、流媒体实操

配置JSON转换器

配置Java对象转换器

多个Java对象转换

全局转换器

消息监听器@RabbitListener

rabbitmq中消费者可使用@RabbitListener标注的方法进行处理。

  • 定义消息处理器,@RabbitListener注解标记的方法
  • 添加@EnableRabbit
RabbitListenerAnnotationBeanPostProcessor类用于解析RabbitListener注解,该类实现了BeanPostProcessor,Ordered,BeanFactoryAware,BeanClassLoaderAware,EnvironmentAware。

@RabbitListener可以标注在类上面,当使用在类上面的时候,需要配合@RabbitHandler注解一起使用,@RabbitListener标注在类上面表示当有收到消息的时候,就交给带有@RabbitHandler的方法处理,具体找哪个方法处理,需要跟进MessageConverter转换后的java对象。

说明:

  • org.springframework.amqp.core.Message 只能接收简单消息,像字符串、数字这种
  • org.springframework.messaging.Message 可以接收复杂类型,像对象
  • com.rabbitmq.client.Channel 消息使用的channel

@RabbitListener 提供消费者配置:

  • ackMode:覆盖容器工厂 AcknowledgeMode属性。
  • admin:参考AmqpAdmin.
  • autoStartup:设置为 true 或 false,以覆盖容器工厂中的默认设置。
  • QueueBinding[] bindings:QueueBinding提供监听器队列名称以及交换和可选绑定信息的数组。
  • concurrency:消费并发数。
  • containerFactory:RabbitListenerContainerFactory的bean名称 ,没有则使用默认工厂。
  • converterWinsContentType:设置为“false”以使用“replyContentType”属性的值覆盖由消息转换器设置的任何内容类型标头。
  • errorHandler:消息异常时调用的方法名。
  • exclusive:当为true时,容器中的单个消费者将独占使用 queues(),从而阻止其他消费者从队列接收消息。
  • executor:线程池bean的名称
  • group:如果提供,则此侦听器的侦听器容器将添加到以该值作为其名称的类型为 的 bean 中Collection<MessageListenerContainer>。
  • id:为此端点管理的容器的唯一标识符。
  • messageConverter:消息转换器。
  • priority:此端点的优先级。
  • String[] queues:监听的队列名称
  • Queue[] queuesToDeclare:监听的队列Queue注解对象,与bindings()、queues()互斥。
  • replyContentType:用于设置回复消息的内容类型。
  • replyPostProcessor:在ReplyPostProcessor发送之前处理响应的 bean 名称 。
  • returnExceptions:设置为“true”以导致使用正常replyTo/@SendTo语义将侦听器抛出的异常发送给发送者。

其他

RabbitMQ的一些注解

1、@QueueBinding

2、@Queue

  • name: 队列的名称;

  • durable: 是否持久化;

  • exclusive: 是否独享、排外的;

  • autoDelete: 是否自动删除;

  • arguments:队列的其他属性参数,有如下可选项

    • x-message-ttl:消息的过期时间,单位:毫秒;

    • x-expires:队列过期时间,队列在多长时间未被访问将被删除,单位:毫秒;

    • x-max-length:队列最大长度,超过该最大值,则将从队列头部开始删除消息;

    • x-max-length-bytes:队列消息内容占用最大空间,受限于内存大小,超过该阈值则从队列头部开始删除消息;

    • x-overflow:设置队列溢出行为。这决定了当达到队列的最大长度时消息会发生什么。有效值是drop-head、reject-publish或reject-publish-dlx。仲裁队列类型仅支持drop-head;

    • x-dead-letter-exchange:死信交换器名称,过期或被删除(因队列长度超长或因空间超出阈值)的消息可指定发送到该交换器中;

    • x-dead-letter-routing-key:死信消息路由键,在消息发送到死信交换器时会使用该路由键,如果不设置,则使用消息的原来的路由键值

    • x-single-active-consumer:表示队列是否是单一活动消费者,true时,注册的消费组内只有一个消费者消费消息,其他被忽略,false时消息循环分发给所有消费者(默认false)

    • x-max-priority:队列要支持的最大优先级数;如果未设置,队列将不支持消息优先级;

    • x-queue-mode(Lazy mode):将队列设置为延迟模式,在磁盘上保留尽可能多的消息,以减少RAM的使用;如果未设置,队列将保留内存缓存以尽可能快地传递消息;

    • x-queue-master-locator:在集群模式下设置镜像队列的主节点信息。

3、@Exchange

4、@RabbitHandler

@RabbitListener可以标注在类上面,当使用在类上面的时候,需要配合@RabbitHandler注解一起使用,@RabbitListener标注在类上面表示当有收到消息的时候,就交给带有@RabbitHandler的方法处理,具体找哪个方法处理,需要跟进MessageConverter转换后的java对象。 

5、@Payload

6、@Headers

 

posted @ 2022-01-03 14:20  残城碎梦  阅读(292)  评论(0编辑  收藏  举报