上文中我们在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(), false, true);
}
}//*/
}
上边我一共定义了两个监听方法,我再RabbitMQ的配置中声明了需要手动确认消息
因此我这里需要调用我标注的手动监听消息方法。
如果你设置了手动确认消息,且使用的还是自动确认消息的方法,就会出现如下图所示的情况:
运行上方的代码,结果如下所示:
发送回调
手动确认监听: hello world
相关数据:null
确认情况:true
原因:null
===============================
我们可以通过控制台输出内容的顺序去对应到具体的方法中,从而决定你的代码逻辑要写到哪里。
目前我只测试了单台服务器安装RabbitMQ,我没有第二台服务器了,没有办法测试集群,先了解到这里吧,后期用到了再测试。
以上大概就是Springboot集成RabbitMQ小例子。
有好的建议,请在下方输入你的评论。