这是我参与8月更文挑战的第22天
SpringBoot集成RabbitMq
三个注解:
@EnableRabbit:
@EnableRabbit和@Configuration一起使用,可以加在类或者方法上,这个注解开启了容器对注册的bean的@RabbitListener检查。
@RabbitHandler:
@RabbitListener 标注在类上面表示当有收到消息的时候,就交给 @RabbitHandler 的方法处理,具体使用哪个方法处理,根据 MessageConverter 转换后的参数类型
@RabbitListener:
注解来指定某方法作为消息消费的方法,例如监听某 Queue 里面的消息
springboot定义直连交换机
1、jar包
2、配置文件(消费者同理)
生产者配置信息
@Bean
public Queue DirectQueue(){
// durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
// exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
// autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
//一般设置一下队列的持久化就好,其余两个就是默认false
return new Queue(QUEUE_DIRECT_NAME,true);
}
@Bean
public Queue DirectQueue1(){
// durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
// exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
// autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
//一般设置一下队列的持久化就好,其余两个就是默认false
return new Queue(QUEUE_DIRECT_NAME1,true);
}
//声明交换机
/**
* CustomExchange
* DirectExchange :直连型(routing)交换机
* FanoutExchange :广播(订阅)交换机
* HeadersExchange :hdeader交换机
* TopicExchange.class :通配符交换机
*
* String name, 交换机名称
* boolean durable,是否持久化
* boolean autoDelete,是否自动删除
* Map<String, Object> arguments 拓展参数
*/
@Bean
public DirectExchange getDirectExchange(){
return new DirectExchange(EXCHANGE_DIRECT_NAME,true,false,null);
}
@Bean
//将队列绑定至交换机
public Binding getBindingDirect(){
return BindingBuilder.bind(DirectQueue()).to(getDirectExchange()).with(ROUTING_KEY_DIRECT_NAME);
}
生产者发送消息通过 参数:String exchange, 交换机名称 * String routingKey, routingkey * Object object,消息 * @Nullable CorrelationData correlationData RabbitTemplate.convertAndSend()
消费者
解决mq发送对象和接受对象的问题
生产者:
统一配置返回信息
消费者:
SpringBoot定义topic
与直连型交换机配置相同,只是再定义交换机时,定义routingKey,设置通配符
@Configuration
public class TopicRabbitConfig {
//定义交换机名称
private final String exchange_topic_name="topic_exchange_test";
//定义队列名称
private final String queue_topic_name_email = "email.topic";
private final String queue_topic_name_qq = "qq.topic";
@Bean
public Queue TopicQueueEmail(){
// durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
// exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
// autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
//一般设置一下队列的持久化就好,其余两个就是默认false
return new Queue(queue_topic_name_email,true);
}
@Bean
public Queue TopicQueueQq(){
// durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
// exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
// autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
//一般设置一下队列的持久化就好,其余两个就是默认false
return new Queue(queue_topic_name_qq,true);
}
//声明交换机
/**
* CustomExchange
* DirectExchange :直连型(routing)交换机
* FanoutExchange :广播(订阅)交换机
* HeadersExchange :hdeader交换机
* TopicExchange.class :通配符交换机
*
* String name, 交换机名称
* boolean durable,是否持久化
* boolean autoDelete,是否自动删除
* Map<String, Object> arguments 拓展参数
*/
@Bean
public TopicExchange getTopicExchange(){
return new TopicExchange(exchange_topic_name,true,false,null);
}
@Bean
//将队列绑定至交换机
public Binding getBindingTopic(){
return BindingBuilder.bind(TopicQueueEmail()).to(getTopicExchange()).with("topic.email.#");
}
@Bean
//将队列绑定至交换机
public Binding getBindingTopic1(){
return BindingBuilder.bind(TopicQueueQq()).to(getTopicExchange()).with("topic.#");
}
发送消息:
SpringBoot定义扇形交换机
基本流程同上,但是生产者再发送消息时,要指定routingKey为null,否则发送不到交换机上
配置消息确认回调
配置文件
在配置确认回调,测试发现无法触发回调函数,那么存在原因也许是因为版本导致的配置项不起效, 可以把publisher-confirms: true 替换为 publisher-confirm-type: correlated
配置回调函数
回调函数的四种情况:
①消息推送到server,但是在server里找不到交换机:ConfirmCallback
②消息推送到server,找到交换机了,但是没找到队列:ConfirmCallback和RetrunCallback两个回调函数
③消息推送到sever,交换机和队列啥都没找到 :ConfirmCallback
④消息推送成功 :ConfirmCallback
手动回复
配置监听容器:
配置业务处理:
basic.ack用于肯定确认
basic.nack用于否定确认(注意:这是AMQP 0-9-1的RabbitMQ扩展)
basic.reject用于否定确认,但与basic.nack相比有一个限制:一次只能拒绝单条消息
channel.basicReject(deliveryTag, true); 拒绝消费当前消息,如果第二参数传入true,就是将数据重新丢回队列里,那么下次还会消费这消息。设置false,就是告诉服务器,我已经知道这条消息数据了,因为一些原因拒绝它,而且服务器也把这个消息丢掉就行。 下次不想再消费这条消息了。
使用拒绝后重新入列这个确认模式要谨慎,因为一般都是出现异常的时候,catch异常再拒绝入列,选择是否重入列。
但是如果使用不当会导致一些每次都被你重入列的消息一直消费-入列-消费-入列这样循环,会导致消息积压。