1、首先是rabbitmq的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit-1.4.xsd">
<!-- spring-rabbit.xsd的版本要注意,很1.4以前很多功能都没有,要用跟jar包匹配的版本 --> <bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" /> <rabbit:connection-factory
id="connectionFactory"
host="${rabbit.host}"
port="${rabbit.port}"
username="${rabbit.username}"
password="${rabbit.password}"
publisher-confirms="true"
/> <rabbit:admin connection-factory="connectionFactory" /> <!-- 给模板指定转换器 --><!-- mandatory必须设置true,return callback才生效 -->
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"
confirm-callback="confirmCallBackListener"
return-callback="returnCallBackListener"
mandatory="true"
/> <rabbit:queue name="CONFIRM_TEST" /> <rabbit:direct-exchange name="DIRECT_EX" id="DIRECT_EX" >
<rabbit:bindings>
<rabbit:binding queue="CONFIRM_TEST" />
</rabbit:bindings>
</rabbit:direct-exchange> <!-- 配置consumer, 监听的类和queue的对应关系 -->
<rabbit:listener-container
connection-factory="connectionFactory" acknowledge="manual" >
<rabbit:listener queues="CONFIRM_TEST" ref="receiveConfirmTestListener" />
</rabbit:listener-container> </beans>

2、发送方:

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; @Service("publishService")
public class PublishService {
@Autowired
private AmqpTemplate amqpTemplate; public void send(String exchange, String routingKey, Object message) {
amqpTemplate.convertAndSend(exchange, routingKey, message);
}
}

3、消费方:

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.stereotype.Service; import com.rabbitmq.client.Channel; @Service("receiveConfirmTestListener")
public class ReceiveConfirmTestListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
try{
System.out.println("consumer--:"+message.getMessageProperties()+":"+new String(message.getBody()));
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}catch(Exception e){
e.printStackTrace();//TODO 业务处理
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
}
}
}

4、确认后回调方:

import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.stereotype.Service; @Service("confirmCallBackListener")
public class ConfirmCallBackListener implements ConfirmCallback{
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
System.out.println("confirm--:correlationData:"+correlationData+",ack:"+ack+",cause:"+cause);
}
}

5、失败后return回调:

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback;
import org.springframework.stereotype.Service; @Service("returnCallBackListener")
public class ReturnCallBackListener implements ReturnCallback{
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
System.out.println("return--message:"+new String(message.getBody())+",replyCode:"+replyCode+",replyText:"+replyText+",exchange:"+exchange+",routingKey:"+routingKey);
}
}

6、测试类:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.dingcheng.confirms.publish.PublishService; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:application-context.xml"})
public class TestConfirm {
@Autowired
private PublishService publishService; private static String exChange = "DIRECT_EX"; @Test
public void test1() throws InterruptedException{
String message = "currentTime:"+System.currentTimeMillis();
System.out.println("test1---message:"+message);
//exchange,queue 都正确,confirm被回调, ack=true
publishService.send(exChange,"CONFIRM_TEST",message);
Thread.sleep(1000);
} @Test
public void test2() throws InterruptedException{
String message = "currentTime:"+System.currentTimeMillis();
System.out.println("test2---message:"+message);
//exchange 错误,queue 正确,confirm被回调, ack=false
publishService.send(exChange+"NO","CONFIRM_TEST",message);
Thread.sleep(1000);
} @Test
public void test3() throws InterruptedException{
String message = "currentTime:"+System.currentTimeMillis();
System.out.println("test3---message:"+message);
//exchange 正确,queue 错误 ,confirm被回调, ack=true; return被回调 replyText:NO_ROUTE
publishService.send(exChange,"",message);
// Thread.sleep(1000);
} @Test
public void test4() throws InterruptedException{
String message = "currentTime:"+System.currentTimeMillis();
System.out.println("test4---message:"+message);
//exchange 错误,queue 错误,confirm被回调, ack=false
publishService.send(exChange+"NO","CONFIRM_TEST",message);
Thread.sleep(1000);
}
}

7、测试结果:

test1---message:currentTime:1483786948506
test2---message:currentTime:1483786948532
consumer--:MessageProperties [headers={spring_return_correlation=445bc7ca-a5bd-47e2-8ba3-f0448420e441}, timestamp=null, messageId=null, userId=null, appId=null, clusterId=null, type=null, correlationId=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=DIRECT_EX, receivedRoutingKey=CONFIRM_TEST, deliveryTag=1, messageCount=0]:currentTime:1483786948506
test3---message:currentTime:1483786948536
confirm--:correlationData:null,ack:false,cause:channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'DIRECT_EXNO' in vhost '/', class-id=60, method-id=40)
confirm--:correlationData:null,ack:false,cause:Channel closed by application
[ERROR] 2017-01-07 19:02:28 org.springframework.amqp.rabbit.connection.CachingConnectionFactory.shutdownCompleted(CachingConnectionFactory.java:281):--> Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'DIRECT_EXNO' in vhost '/', class-id=60, method-id=40)
return--message:currentTime:1483786948536,replyCode:312,replyText:NO_ROUTE,exchange:DIRECT_EX,routingKey:
confirm--:correlationData:null,ack:true,cause:null
test4---message:currentTime:1483786948546
confirm--:correlationData:null,ack:false,cause:channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'DIRECT_EXNO' in vhost '/', class-id=60, method-id=40)
[ERROR] 2017-01-07 19:02:28 org.springframework.amqp.rabbit.connection.CachingConnectionFactory.shutdownCompleted(CachingConnectionFactory.java:281):--> Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'DIRECT_EXNO' in vhost '/', class-id=60, method-id=40)

8、总结如下:

如果消息没有到exchange,则confirm回调,ack=false

如果消息到达exchange,则confirm回调,ack=true

exchange到queue成功,则不回调return

exchange到queue失败,则回调return(需设置mandatory=true,否则不回回调,消息就丢了)

备注:需要说明,spring-rabbit和原生的rabbit-client ,表现是不一样的。测试的时候,原生的client,exchange错误的话,直接就报错了,是不会到confirmListener和returnListener的

源码地址:https://github.com/qq315737546/spring-rabbit

全文地址请点击:https://blog.csdn.net/qq315737546/article/details/54176560

使用spring-rabbit测试RabbitMQ消息确认(发送确认,接收确认)的更多相关文章

  1. 【Spring Boot】Spring Boot之整合RabbitMQ并实现消息的发送和接收

    一.项目配置 1)引入maven坐标 <!--amqp--> <dependency> <groupId>org.springframework.boot</ ...

  2. 探索 OpenStack 之(15):oslo.messaging 和 Cinder 中 MessageQueue 消息的发送和接收

    前言:上一篇文章 只是 RabbitMQ 的科普,本文将仔细分析 Cinder 中 RabbitMQ 的各组件的使用.消息的发送和接收等.由于各流程步骤很多,本文只会使用若干流程图来加以阐述,尽量做到 ...

  3. Queue 消息的发送与接收(PTP 消息传递模型)

    上篇博客写到了JMS两种消息模型(P2P.pub/sub)<JMS两种消息模型>.本篇博客通过一个实例来进一步了解P2P模型. Queue消息的发送与接收--PTP消息传递模型,样例: Q ...

  4. Udp实现消息的发送和接收、以及图片的上传

    //Udp实现消息的发送和接收 import java.io.IOException; import java.net.DatagramPacket; import java.net.Datagram ...

  5. nodejs 数据库操作,消息的发送和接收,模拟同步

    var deasync = require('deasync'); //导入模板 var mysql=require('mysql'); var Stomp = require('stompjs'); ...

  6. msgrcv,msgsnd进程通信,消息的发送和接收

    //进程通信,消息的发送和接收 //client.c #include <unistd.h> #include <sys/types.h> #include <sys/s ...

  7. 【转载】java实现rabbitmq消息的发送接受

    原文地址:http://blog.csdn.net/sdyy321/article/details/9241445 本文不介绍amqp和rabbitmq相关知识,请自行网上查阅 本文是基于spring ...

  8. Spring Boot 之 RabbitMQ 消息队列中间件的三种模式

    开门见山(文末附有消息队列的几个基本概念) 1.直接模式( Direct)模式 直白的说就是一对一,生产者对应唯一的消费者(当然同一个消费者可以开启多个服务). 虽然使用了自带的交换器(Exchang ...

  9. RabbitMQ消息发布和消费的确认机制

    前言 新公司项目使用的消息队列是RabbitMQ,之前其实没有在实际项目上用过RabbitMQ,所以对它的了解都谈不上入门.趁着周末休息的时间也猛补习了一波,写了两个窗体应用,一个消息发布端和消息消费 ...

随机推荐

  1. 【SqlServer】SQL Server的常用函数

    字符串函数 SubString():用于截取指定字符串的方法.该方法有三个参数:参数1:用于指定要操作的字符串.参数2:用于指定要截取的字符串的起始位置,起始值为 1 .参数3:用于指定要截取的长度. ...

  2. Kibana常用命令

    一.范围(>500) totalTime: [500 TO *] 二.不等于 NOT monitorName: "XXX" 三.字符匹配 正则表达式:    +url:/.* ...

  3. 恢复oracle中用PLSQL误删除drop掉的表

    一.查看回收站中表 select object_name,original_name,partition_name,type,ts_name,createtime,droptime from recy ...

  4. PHOTOSHOP中3D下拉菜单为灰色如何设置

    方法/步骤   安装好PS后,在测试3D功能时突然发不能用.如图,怎么办呢?   按“CTRL+K”打开,或者在编辑-首选项-性能-勾选“启用OpenGL绘图(D)”   在选项对话框中勾选“启用Op ...

  5. xcode修改项目名后反复出现 clang error

    xcode修改项目名后反复出现 clang error,  提示 ld: file not found . 并且该错误并不是出现在项目编译阶段,而是项目的Tests 的link阶段, 同时提示 xct ...

  6. MySQL中 optimize table '表名'的作用

    语法: optimize table '表名' 一,原始数据 1,数据量 2,存放在硬盘中的表文件大小 3,查看一下索引信息 索引信息中的列的信息说明. Table :表的名称.Non_unique: ...

  7. FreeSWITCH快速录音

    一.背景 测试人员反映FreeSWITCH录音不及时,需要大约5秒的时间才能捕获到RTP流. 二.原因及解决 查了下资料,FreeSWITCH默认的录音参数配置是开启缓冲的, 即RTP流大小到达655 ...

  8. [转]21分钟 MySQL 入门教程

    目录 一.MySQL的相关概念介绍 二.Windows下MySQL的配置 配置步骤 MySQL服务的启动.停止与卸载 三.MySQL脚本的基本组成 四.MySQL中的数据类型 五.使用MySQL数据库 ...

  9. 容错处理库Polly使用文档

    Design For Failure1. 一个依赖服务的故障不会严重破坏用户的体验.2. 系统能自动或半自动处理故障,具备自我恢复能力. 以下是一些经验的服务容错模式 超时与重试(Timeout an ...

  10. C#基础第七天-作业-利用面向对象的思想去实现名片-动态添加

    1.利用面向对象的思想去实现: (增加,修改,删除,查询,查询全部)需求:根据人名去(删除/查询).指定列:姓名,年龄,性别,爱好,电话. 多条添加 , 动态添加 名片 本系列教程: C#基础总结之八 ...