RabbitMQ(四)Springboot集成RabbitMQ

210 阅读4分钟

上文中我们在linux服务器中安装了RabbitMQ中间件。这里我们来尝试一下在Springboot中集成RabbitMQ。

 

一:RabbitMQ依赖

首先需要添加依赖:

<!--rabbitmq-需要的 AMQP 依赖-->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-amqp</artifactId>
 </dependency>

二:添加yml配置

spring:
   #配置rabbitmq 服务器
   rabbitmq:
     host: 111.111.111.111
     port: 5672
     username: xxxx
     password: xxxx
     # 确认消息发送到交换机上
     publisher-confirm-type: correlated
     # publisher-confirms 消息的可靠投递, confirm 确认模式 默认为false
     publisher-confirms: true
     # publisher-returns 消息的可靠投递, return 回退模式 默认为false
     publisher-returns: true
     ### listener
     listener:
       # 每次从队列中预取10条消息
       prefetch: 10
       # 最小消费者数量
       concurrency: 1
       # 最大的消费者数量
       max-concurrency: 1
       simple:
         # 开启manual确认模式
         acknowledge-mode: manual
     ## template相关
     template:
       # 接受消息超时时间
       receive-timeout: 0
       ## retry重试相关
       retry:
         enabled: false #是否开启
         maxAttempts: 0 #最大重试次数
         initialInterval: 1000 #重试间隔
         multiplier: 1 #失败间隔乘数
         maxInterval: 1000 #最大间隔

三:RabbitMQ交换机配置

我这里只使用Direct模式进行演示,fanout与topic模式后期有时间我再进行演示。

在config目录下创建RabbitMQDirectConfig.java文件,代码如下所示:

package com.springbootblog.config;
 
 import org.springframework.amqp.core.*;
 import org.springframework.amqp.rabbit.annotation.EnableRabbit;
 import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
 import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
 import org.springframework.amqp.rabbit.connection.ConnectionFactory;
 import org.springframework.amqp.rabbit.core.RabbitTemplate;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
 
 /**
  * RabbitMQ direct配置类
  */
 @Configuration
 // 开启RabbitMQ注解模式
 @EnableRabbit
 public class RabbitMQDirectConfig
 {
     @Value("${spring.rabbitmq.host}")
     private String host;
     @Value("${spring.rabbitmq.port}")
     private int port;
     @Value("${spring.rabbitmq.username}")
     private String userName;
     @Value("${spring.rabbitmq.password}")
     private String password;
     @Value("${spring.rabbitmq.listener.prefetch}")
     private int prefetch;
     @Value("${spring.rabbitmq.listener.concurrency}")
     private int concurrentConsumers;
     @Value("${spring.rabbitmq.listener.max-concurrency}")
     private int maxConcurrentConsumers;
 
     /**
      * 链接RabbitMQ
      * @return
      */
     @Bean
     public ConnectionFactory connectionFactory()
     {
         CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
         connectionFactory.setHost(host);
         connectionFactory.setPort(port);
         connectionFactory.setUsername(userName);
         connectionFactory.setPassword(password);
         connectionFactory.setPublisherConfirms(true); //必须要设置
         return connectionFactory;
     }
 
     /**
      * 配置RabbitMQ参数
      * @return
      */
     @Bean
     public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory()
     {
         SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
         factory.setConnectionFactory(connectionFactory());
         //设置最小并发的消费者数量
         factory.setConcurrentConsumers(concurrentConsumers);
         //设置最大并发的消费者数量
         factory.setMaxConcurrentConsumers(maxConcurrentConsumers);
         //限流,单位时间内消费多少条记录
         factory.setPrefetchCount(prefetch);
         // json转消息
         //factory.setMessageConverter(new Jackson2JsonMessageConverter());
         //设置rabbit 确认消息的模式,默认是自动确认
         //factory.setAcknowledgeMode(AcknowledgeMode.AUTO);
         //设置rabbit 确认消息的模式,默认是自动确认
         factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
         return factory;
     }
 
     /**
      * 回调函数
      * @param connectionFactory
      * @return
      */
     @Bean
     public RabbitTemplate createRabbitTemplate(ConnectionFactory connectionFactory)
     {
         RabbitTemplate rabbitTemplate = new RabbitTemplate();
         rabbitTemplate.setConnectionFactory(connectionFactory);
         //设置开启Manatory,才能触发回调函数,无论消息推送结果怎么样都会强制调用回调函数
         rabbitTemplate.setMandatory(true);
 
         // 设置确认发送到交换机的回调函数 =》 消息推送到server,但是在server里找不到交换机 / 消息推送到sever,交换机和队列啥都没找到 / 消息推送到server,找到交换机了,但是没找到队列 / 消息推送成功
         rabbitTemplate.setConfirmCallback((correlationData, b, s) -> {
             System.out.println("相关数据:"+correlationData);
             System.out.println("确认情况:"+b);
             System.out.println("原因:"+s);
             System.out.println("===============================");
         });
 
         //设置确认消息已发送到队列的回调  =》 消息推送到server,找到交换机了,但是没找到队列 触发这个回调函数
         rabbitTemplate.setReturnsCallback(returnedMessage -> {
             System.out.println("交换机为:"+returnedMessage.getExchange());
             System.out.println("返回消息为:"+returnedMessage.getMessage());
             System.out.println("路由键为:"+returnedMessage.getRoutingKey());
             System.out.println("回应消息为:"+returnedMessage.getReplyText());
             System.out.println("回应代码为:"+returnedMessage.getReplyCode());
             System.out.println("===============================");
         });
         return rabbitTemplate;
     }
 
     /**
      * 队列
      * @return
      */
     @Bean
     public Queue queue()
     {
         return new Queue("test_queue_1"true);
     }
 
     /**
      * 交换机
      * @return
      */
     @Bean
     public DirectExchange directExchange()
     {
         return new DirectExchange("test_exchange");
     }
 
     /**
      * 队列绑定交换机
      * @param queue
      * @param exchange
      * @return
      */
     @Bean
     public Binding binding(Queue queue, DirectExchange exchange)
     {
         return BindingBuilder.bind(queue).to(directExchange()).with("test_queue_1");
     }
 }

这里需要注意一下

// 开启RabbitMQ注解模式
 @EnableRabbit

**这个注解一定要添加,开启RabbitMQ注解模式
**其他的部分代码中都有注释,参照即可。

 

四:测试调用

package com.springbootblog.controller.fontend;
 
 import com.rabbitmq.client.*;
 import com.springbootblog.utils.RabbitUtils;
 import org.springframework.amqp.AmqpException;
 import org.springframework.amqp.core.Message;
 import org.springframework.amqp.core.MessagePostProcessor;
 import org.springframework.amqp.rabbit.annotation.RabbitHandler;
 import org.springframework.amqp.rabbit.annotation.RabbitListener;
 import org.springframework.amqp.rabbit.core.RabbitTemplate;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import java.io.IOException; 
 
 @RequestMapping("java")
 @RestController
 public class RabbitMQController
 {
     @Resource
     private RabbitTemplate rabbitTemplate;
 
     @GetMapping("rabbit/sendMsg")
     public void send(String message)
     {
         rabbitTemplate.convertAndSend("test_exchange""test_queue_1""hello world"new MessagePostProcessor() {
             @Override
             public Message postProcessMessage(Message message) throws AmqpException {
                 // message.getMessageProperties().setHeader("x-delay",1000*60);
                 System.out.println("发送回调");
                 return message;
             }
         });
         //rabbitTemplate.convertAndSend("test_exchange", "test_queue_1", "hello world");
     }
 
     /**
      * 自动确认监听 方法
      * @param message
      */
     // 这个注解标注的方法是不能有返回值的
     /*@RabbitListener(queues = "test_queue_1")
     public void receive(String message)
     {
         System.out.println("Received Message: " + message);
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         System.out.println("消息接收时间:"+sdf.format(new Date()));
         System.out.println("接收到的消息:"+message);
     }//*/
 
     /**
      * 手动确认监听 方法
      * @param message
      * @param channel
      * @throws IOException
      */
     // 这个注解标注的方法是不能有返回值的
     @RabbitListener(queues = "test_queue_1", containerFactory = "rabbitListenerContainerFactory")
     public void receiveMessage(Message message, Channel channel) throws IOException
     {
         try
         {
             // 处理消息
             System.out.println("手动确认监听: " + new String(message.getBody()));
 
             // 确认消息
             channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
         }
         catch (Exception e)
         {
             // 处理异常,可以选择重新将消息重新放入队列
             channel.basicNack(message.getMessageProperties().getDeliveryTag(), falsetrue);
         }
     }//*/
 }

上边我一共定义了两个监听方法,我再RabbitMQ的配置中声明了需要手动确认消息

因此我这里需要调用我标注的手动监听消息方法。

 

如果你设置了手动确认消息,且使用的还是自动确认消息的方法,就会出现如下图所示的情况:

1.jpg

 

运行上方的代码,结果如下所示:

发送回调
手动确认监听: hello world
相关数据:null
确认情况:true
原因:null
===============================

 

我们可以通过控制台输出内容的顺序去对应到具体的方法中,从而决定你的代码逻辑要写到哪里。

 

目前我只测试了单台服务器安装RabbitMQ,我没有第二台服务器了,没有办法测试集群,先了解到这里吧,后期用到了再测试。

 

以上大概就是Springboot集成RabbitMQ小例子。

 

有好的建议,请在下方输入你的评论。