敲详细的springboot中使用RabbitMQ的源码解析

这里介绍的源码主要是涉及springboot框架下的rabbitmq客户端代码(具体在springframework.amqp.rabbit包下,区分一下不由springboot直接接管的spring-rabbit的内容),springboot基于RabbitMQ的Java客户端建立了简便易用的框架。

springboot的框架下相对更多地使用消费者Consumer和监听器Listener的概念,这两个概念不注意区分容易混淆。默认情况下,springboot中消费者为单线程串行消费的模型,体现了队列的特性。


在springboot的框架下使用rabbitmq的一般步骤

  1. 启动rabbitmq服务器,springboot项目引入依赖
  2. 配置信息,有两种方式
    1. 配置文件配置
    2. 配置类配置SimpleMessageListenerContainer
  3. 实现消息处理类ChannelAwareMessageListener处理业务逻辑,或用@RabbitListener注解

这两种方式其实异曲同工,@RabbitListener的方式在实际使用时创建MessagingMessageListenerAdapter,这个对象是ChannelAwareMessageListener接口的实现类,实现了onMessage()方法,这个方法利用了适配器模式,能够调用注解标注的方法,而实现ChannelAwareMessageListener的方式比较直白就是实现onMessage()方法


源码解析

关于SimpleMessageListenerContainer

SimpleMessageListenerContainer是在spring项目中使用RabbitMQ关键的类,用来接收并处理消息的。阅读源码可以从这个类入手。

  1. 首先关注构造器,需要传入ConnectionFactory用于获取连接,这跟原生rabbitmq是一致的,都从Connection连接开始。

  2. 关键属性

    concurrentConsumers:指定要创建的并发消费者的数量。默认值为1。建议增加并发使用者的数量,以便扩展从队列传入的消息的消耗。但是,请注意,一旦注册了多个消费者,将无法保证顺序。一般来说,对于低容量队列,坚持使用1个消费者。同时不能超过maxConcurrentConsumers(如果设置了)。

    maxConcurrentConsumers:设置消费者数量的上限。默认为concurrentConsumers。消费者可以根据需求增加,但不会小于concurrentConsumers。

    acknowledgeMode:消息确认模式

    // 自动确认消息
    container.setAcknowledgeMode(AcknowledgeMode.NONE);
    // 根据情况确认消息
    container.setAcknowledgeMode(AcknowledgeMode.AUTO);
    // 手动确认消息
    container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
    
  3. 绑定组件:

  4. 设置消费者的Consumer_tag和Arguments:container.setConsumerTagStrategy可以设置消费者的 Consumer_tag, container.setConsumerArguments可以设置消费者的 Arguments

    container.setConsumerTagStrategy(queue -> "order_queue_"+(++count));
    //设置消费者的Arguments
    Map<String, Object> args = new HashMap<>();
    args.put("module","订单模块");
    args.put("fun","发送消息");
    container.setConsumerArguments(args);
    

    在这里插入图片描述


spring的亮点在于用注解简化了很多代码操作,其中最常用的当属@RabbitListener

@RabbitListener(queues = {
   
   BiMqConstant.BI_QUEUE_NAME}, ackMode = "MANUAL")
public void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag){
   
   
}

从@RabbitListener入手

1、从spring开启RabbitMQ的注解模式,@EnableRabbit导入RabbitBootstrapConfiguration配置类。

2、这个配置类定义了RabbitListenerAnnotationBeanPostProcessor和RabbitListenerEndpointRegistry两个bean。前者用来扫描加了@RabbitListener 的类,通过反射找到带注解的类,再找到对应的方法,存为handlerMethods。后者在注册终端后用于构建ListenerContainer(继承了RabbitListener注解内的信息,包括监听的队列和注解所在的类和方法)。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(RabbitBootstrapConfiguration.class)
public @interface EnableRabbit {
   
   
}

3、RabbitListenerEndpointRegistry通过创建MethodRabbitListenerEndpoint对象和SimpleRabbitListenerContainerFactory工厂bean,生成SimpleMessageListenerContainer对象。

(RabbitListenerAnnotationBeanPostProcessor中拥有注解信息,如队列名,以及被标注注解的方法,所以endpoint的注册还是在processor类中)

(processor中有注册员成员变量registrar的registerEndpoint()注册endpoint,registrar有注册处registry成员变量注册利用registerListenerContainer()的createListenerContainer()注册container)

public class RabbitListenerEndpointRegistry  implements SmartLifecycle{
   
   
 
	private final Map<String, MessageListenerContainer> listenerContainers =
			new ConcurrentHashMap<String, MessageListenerContainer>();
	//注册终端
	public void registerListenerContainer(RabbitListenerEndpoint endpoint, RabbitListenerContainerFactory<?> factory,
				boolean startImmediately) {
   
   
 
		String id = endpoint.getId();
		synchronized (this.listenerContainers) {
   
   
			//创建 listenerContainer
			MessageListenerContainer container = createListenerContainer(endpoint, factory);
			this.listenerContainers.put(id, container);
			……
 
			if (startImmediately) {
   
   
				startIfNecessary(container);
			}
		}
	}
 
	    protected MessageListenerContainer createListenerContainer(RabbitListenerEndpoint endpoint,
            RabbitListenerContainerFactory<?> factory) {
   
   
        //调用RabbitListener容器工厂的createListenerContainer方法获取RabbitListener容器
        MessageListenerContainer listenerContainer = factory.createListenerContainer(endpoint);
 
        return listenerContainer;
    }

4、SimpleMessageListenerContainer对象保存了要监听的队列名(可以是configuration时set的也可以是@RabbitListener中标注的),创建了用于处理消息的MessagingMessageListenerAdapter实例(实际上是一个listener)

public class MethodRabbitListenerEndpoint extends AbstractRabbitListenerEndpoint {
   
   
    ......
    @Override
    protected MessagingMessageListenerAdapter
### 如何在 Spring Boot 项目中整合 RabbitMQ #### 创建 Spring Boot 项目并添加依赖 为了创建一个新的 Spring Boot 项目,推荐使用 Spring Initializr 来初始化工程,并添加必要的依赖项。对于与 RabbitMQ 的集成来说,`spring-boot-starter-web` 和 `spring-boot-starter-amqp` 是必需的两个组件[^1]。 ```xml <dependencies> <!-- 添加Web功能 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 支持AMQP协议, 即RabbitMQ的支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> </dependencies> ``` #### 配置 RabbitMQ 连接参数 接下来,在项目的 application.properties 或 application.yml 文件里设置 RabbitMQ 的连接属性: ```yaml spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.rabbitmq.username=guest spring.rabbitmq.password=guest ``` 这些配置指定了主机地址、端口号以及登录凭证等基本信息[^3]。 #### 编写消息生产者和服务消费者逻辑 定义一个简单的控制器用于发送消息给队列;同时实现监听器接口以接收来自指定队列的消息。 ##### 生产者代码示例 ```java @RestController public class MessageProducer { @Autowired private AmqpTemplate amqpTemplate; @GetMapping("/send/{message}") public String sendMessage(@PathVariable String message){ this.amqpTemplate.convertAndSend("hello", message); return "Message sent!"; } } ``` 这段程序展示了如何利用 `AmqpTemplate` 发送一条字符串形式的信息至名为 `"hello"` 的交换机或直接到特定队列中去[^4]。 ##### 消费者代码片段 ```java @Component public class MessageConsumer { @RabbitListener(queues = {"hello"}) public void receive(String content) throws Exception{ System.out.println("[x] Received '" + content + "'"); } } ``` 这里展示了一个基于注解的方式订阅名为 `"hello"` 的队列,并处理收到的数据流。 #### 测试整个流程 启动应用程序之后,可以通过浏览器访问 `/send/your_message_here` 接口触发消息传递操作,随后观察控制台输出确认消息已被成功消费。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值