1 创建工程
创建生产者工程 springboot-rabbitmq-producer
2 添加依赖
修改pom.xml文件内容为如下:
<dependencies>
<!--2. rabbitmq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
3. 启动类
@SpringBootApplication
public class ProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ProducerApplication.class);
}
}
4. 配置RabbitMQ
spring:
rabbitmq:
username: lhj
password: 123
host: 192.168.226.66
virtual-host: lhj
port: 5672
publisher-returns: true #开启回退模式
# publisher-confirm-type: correlated #开启确认模式
mq:
exchange:
name: test_exchange_topic
queue:
name1: test_topic_exchange_queue_1
name2: test_topic_exchange_queue_2
5.手动授权配置文件
spring:
rabbitmq:
username: lhj
password: 123
host: 192.168.226.66
virtual-host: lhj
port: 5672
listener:
simple:
acknowledge-mode: manual #开启手动授权
#mq:
# exchange:
# name: test_exchange_topic
# queue:
# name1: test_topic_exchange_queue_1
server:
port: 8085
# name2: test_topic_exchange_queue_2
6.绑定交换机和队列
创建RabbitMQ队列与交换机绑定的配置类com.yyl.rabbitmq.config.RabbitMQConfig
//设置交换机的名字 和 队列的名字
public static final String EXCHANGE_NAME="exchange_topic_name";
public static final String QUEUE_NAME="queue_topic_name1";
public static final String QUEUE_NAME_2="queue_topic_name2";
//将交换机这只成为一个bean注入到Springboot里面
@Bean("topicExchange")
public Exchange topicExchange(){
//可以持久化的一个交换机
return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
}
/**
* 队列
*/
@Bean("topicQueue")
public Queue topicQueue(){
return QueueBuilder.durable(QUEUE_NAME).build();
}
@Bean("topicQueue2")
public Queue topicQueue2(){
return QueueBuilder.durable(QUEUE_NAME_2).build();
}
/**
* 将队列和交换机绑定到一起
*/
@Bean
public Binding exchangeWithQueue(@Qualifier("topicExchange") Exchange exchage, @Qualifier("topicQueue") Queue queue){
//保存到数据库中
//将交换机和队列绑定在一起
return BindingBuilder.bind(queue).to(exchage).with("*.error").noargs();
}
@Bean
public Binding exchangeWithQueue2(@Qualifier("topicExchange") Exchange exchage, @Qualifier("topicQueue2") Queue queue){
//输出到控制台中
//将交换机和队列绑定在一起
return BindingBuilder.bind(queue).to(exchage).with("*.*").noargs();
}
7.消费者代码
@Resource
private RabbitTemplate rabbitTemplate;
@Test
public void testSendMesssage(){
//将消息发送到队列里面
rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_NAME,"test.error","我是test模块中,日志级别为error的信息");
}
8. 消息的可靠投递
在使用 RabbitMQ 的时候,作为消息发送方希望杜绝任何消息丢失或者投递失败场景。RabbitMQ 为我们提供了两种方式用来控制消息的投递可靠性模式。
- confirm 确认模式
📌
确认队列中的消息是否被消费者消费
- return 退回模式
💡
交换机中的消息是否到达队列里面
8.1.确认模式
@Resource
private RabbitTemplate rabbitTemplate;
//确认模式的测试
//1.开启确认模式 开启publisher-confirms="true"
//2. 定义回调 在rabbitTemplate中设置信息的确认
@Test
public void testConfirm(){
/**
* @param correlationData 相关配置信息
* @param ack exchange交换机 是否成功收到了消息。true 成功,false代表失败
* @param cause 失败原因
*/
//匿名的内部类
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String s) {
System.out.println("confirm方法执行了。。。。。。");
if(ack){
System.out.println("接收成功");
}else{
System.out.println("接收失败,失败的原因是:"+s);
}
}
});
//发送消息
rabbitTemplate.convertAndSend(ConfirmConfig.EXCHAGE_CONFIRM_NAME,"confirm","confirm message");
}
设置publisher-confirms="true" 开启 确认模式。
使用rabbitTemplate.setConfirmCallback设置回调函数。当消息发送到exchange后回调confirm方法。在方法中判断ack,如果为true,则发送成功,如果为false,则发送失败,需要处理。
8.2回退模式
//设置交换机处理失败消息的模式
rabbitTemplate.setMandatory(true);
//匿名的内部类
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
System.out.println("return 执行了....");
// System.out.println(message);
// System.out.println(replyCode);
// System.out.println(replyText);
// System.out.println(exchange);
// System.out.println(routingKey);
}
});
//发送消息
rabbitTemplate.convertAndSend(ConfirmConfig.EXCHAGE_CONFIRM_NAME,"confirm","confirm message");
设置publisher-returns="true"开启 退回模式。
使用rabbitTemplate.setReturnCallback设置退回函数,当消息从exchange路由到queue失败后,如果设置了rabbitTemplate.setMandatory(true)参数,则会将消息退回给producer。并执行回调函数returnedMessage。
8.3手动确认:
acknowledge="manual" 。可以解决业务异常的情况
(收到消息之后不会立马确认收到消息,当业务处理没有问题的时候手动的调用代码的方 式来进行处理,如果业务失败了,就可以进行额外的操作)
@Override
@RabbitListener(queues = "test_confirm_queue")
public void onMessage(Message message, Channel channel) throws Exception {
Thread.sleep(2000);
//1.接收消息
System.out.println(new String(message.getBody()));
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
//2.处理业务luoji
System.out.println("开始处理业务逻辑");
int i=3/0;
//3.成功就直接签收
/**
* basicAck(long deliveryTag, boolean multiple)
* 参数1 当前收到的消息的tag标签的内容
* 参数2 是否允许多条消息被同时签收
*/
//得到第一个参数
channel.basicAck(deliveryTag, true);
}catch(Exception e){
//发生异常的时候就拒接签收
/**
* basicNack(long deliveryTag, boolean multiple, boolean requeue)
* 参数3 是否重回队列 如果设置为true,则消息重新回到queue,broker会重新发送该消息给消费端
*/
channel.basicNack(deliveryTag,true,true);
}
}
设置手动模式需要在配置文件里面添加 acknowlwdge-mode:manual
如果消费端没有异常就会走basicAck的方法,确认签收消息,如果有异常就会调用basicNack的方法拒接签收消息,让MQ重新发送消息