1.1 概述
http://www.rabbitmq.com/getstarted.html
1.2 simplest(简单队列)
1.2.1.概述
The simplest thing that does something
- 简单队列 生产消费一一对应,耦合性高.
- 生产消息快,消费消息慢.如果很多容易堵塞
P:消息生产者;红色的:队列;C:消费者.
1.2.2 示例
pom.xml
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>1.7.5.RELEASE</version>
</dependency>
</dependencies>
rabbitmq.util
public class ConnectionUtils {
/**
* 获取MQ的连接
* @return
* @throws TimeoutException
* @throws IOException
*/
public static Connection getConnection() throws IOException, TimeoutException{
//定义一个连接工厂
ConnectionFactory factory =new ConnectionFactory();
//设置服务地址
factory.setHost("127.0.0.1");
//AMQP 5672
factory.setPort(5672);
//vhost
factory.setVirtualHost("/vhost_bobshute");
//用户名
factory.setUsername("bobshute");
//密码
factory.setPassword("123456");
return factory.newConnection();
}
}
rabbitmq.simple
public class Send {
private static final String QUEUE_NAME="test_simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//获取一个连接
Connection connection = ConnectionUtils.getConnection();
//从连接中获取一个通道
Channel channel = connection.createChannel();
//创建队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String msg="hello simple !";
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
System.out.println("--send msg:"+msg);
channel.close();
connection.close();
}
}
public class Recv {
private static final String QUEUE_NAME = "test_simple_queue";
@SuppressWarnings("deprecation")
public static void main(String[] args) throws IOException,
TimeoutException, ShutdownSignalException,
ConsumerCancelledException, InterruptedException {
// 获取连接
Connection connection = ConnectionUtils.getConnection();
// 创建频道
Channel channel = connection.createChannel();
//队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel){
//获取到达消息
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body,"utf-8");
System.out.println("new api recv:"+msg);
}
};
//监听队列
channel.basicConsume(QUEUE_NAME, true,consumer);
}
private static void oldapiu() throws IOException, TimeoutException,
InterruptedException {
// 获取连接
Connection connection = ConnectionUtils.getConnection();
// 创建频道
Channel channel = connection.createChannel();
// 定义队列的消费者
QueueingConsumer consumer = new QueueingConsumer(channel);
// 监听队列
channel.basicConsume(QUEUE_NAME, true, consumer);
while (true) {
Delivery delivery = consumer.nextDelivery();
String msgString = new String(delivery.getBody());
System.out.println("[recv] msg:" + msgString);
}
}
}
1.3 Work queues(工作队列)
1.3.1 概述
生产消息快,消费消息慢. work queues支持多个消费者.
- 公平分发. 手动返回结果 backQos 受到结果响应才下一条.
1.3.2 Work queues(轮询分发)
rabbitmq.work
public class Send {
/* |---C1
* P-----Queue----|
* ` |---C2
*
*/
private static final String QUEUE_NAME="test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
//获取连接
Connection connection = ConnectionUtils.getConnection();
//获取channel
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
for (int i = 0; i <50; i++) {
String msg="hello "+i;
System.out.println("[WQ ]send:"+msg);
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
Thread.sleep(i*20);
}
channel.close();
connection.close();
}
}
public class Recv1 {
private static final String QUEUE_NAME="test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//获取连接
Connection connection = ConnectionUtils.getConnection();
//获取channel
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body,"utf-8");
System.out.println("[1] Recv msg:"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[1] done ");
}
}
};
boolean autoAck=true;
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}
public class Recv2 {
private static final String QUEUE_NAME="test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//获取连接
Connection connection = ConnectionUtils.getConnection();
//获取channel
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body,"utf-8");
System.out.println("[2] Recv msg:"+msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[2] done ");
}
}
};
boolean autoAck=true;
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}
1.3.3 Work queues(轮询分发)总结
接受消息的逻辑是一样的,支持处理时间不一样,会发现这种模式不管消费的时间,每个消费端各接受一次.
这种方式叫Round-robin(轮询分发)
- 消费者接受消息个数一样的,每个接受一次.如50条消息.2个消费,那就一个接受奇数,一个接受偶书. 如果3个消费者,那就模3,每个消费端接受个数一样多.
1.3.4 Fair dispatch(公平分发)
rabbitmq.workfair
public class Send {
/* |---C1
* P-----Queue----|
* ` |---C2
*
*/
private static final String QUEUE_NAME="test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
//获取连接
Connection connection = ConnectionUtils.getConnection();
//获取channel
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
/**
* 每个消费者 发送确认消息之前,消息队列不发送下一个消息到消费者,一次只处理一个消息
*
* 限制发送给同一个消费者 不得超过一条消息
*/
int prefetchCount=1;
channel.basicQos(prefetchCount); //Fair dispatch 注意点
for (int i = 0; i <50; i++) {
String msg="hello "+i;
System.out.println("[WQ ]send:"+msg);
channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
Thread.sleep(i*5);
}
channel.close();
connection.close();
}
}
public class Recv1 {
private static final String QUEUE_NAME="test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//获取连接
Connection connection = ConnectionUtils.getConnection();
//获取channel
final Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.basicQos(1);//保证一次只分发一个 //Fair dispatch 注意点
//定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body,"utf-8");
System.out.println("[1] Recv msg:"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[1] done ");
channel.basicAck(envelope.getDeliveryTag(), false); //手动回执 Fair dispatch 注意点
}
}
};
boolean autoAck=false;//自动应答 false //Fair dispatch 注意点
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}
public class Recv2 {
private static final String QUEUE_NAME="test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//获取连接
Connection connection = ConnectionUtils.getConnection();
//获取channel
final Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.basicQos(1);//保证一次只分发一个 //Fair dispatch 注意点
//定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body,"utf-8");
System.out.println("[2] Recv msg:"+msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[2] done ");
channel.basicAck(envelope.getDeliveryTag(), false); //手动回执 Fair dispatch 注意点
}
}
};
boolean autoAck=false;//Fair dispatch 注意点
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}
1.3.5 Fair dispatch(公平分发) 总结
- 现象:处理快的接收消息多,处理慢的接受消息少
- 原理:一次发送一条,不自动应答,自动应答,收到应答后就发送新消息
- 代码区别处
//channel注意出,消费和接受都写
channel.basicQos(1);//保证一次只分发一个 //Fair dispatch 注意点
//消费端注意
channel.basicAck(envelope.getDeliveryTag(), false); // 手动回执 Fair dispatch 注意点
boolean autoAck=false;//自动应答 false //Fair dispatch 注意点
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
1.4 Publish/Subscribe
1.4.1 概述
- 生产者不是直接把消费发送到队列,而是发到了Exchange(交换机,转发器)
- 生产者发送的消息,经过交换机,到达队列,然后实现一个队列被多个消费者消费.
- 每一个消费者都有自己的队列
- 每个队列都要绑到交换机上
一个生产者,多个消费者消费同样的消息
应用场景
比如一个消息又要发到短信,又要发到邮件.exchange type(exchange类型) : fanout(分发)
- 启动时需要先启动消费端
1.4.2 示例
rabbitmq.ps
public class Send {
private static final String EXCHANGE_NAME="test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");//分发
//发送消息
String msg="hello ps";
channel.basicPublish(EXCHANGE_NAME, "", null, msg.getBytes());
System.out.println("Send :"+msg);
channel.close();
connection.close();
}
}
public class Recv1 {
private static final String QUEUE_NAME="test_queue_fanout_email";
private static final String EXCHANGE_NAME="test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
final Channel channel = connection.createChannel();
//队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//绑定队列到交换机 转发器
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
channel.basicQos(1);//保证一次只分发一个
//定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body,"utf-8");
System.out.println("[1] Recv msg:"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[1] done ");
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
boolean autoAck=false;//自动应答 false
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}
public class Recv2 {
private static final String QUEUE_NAME="test_queue_fanout_sms";
private static final String EXCHANGE_NAME="test_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
final Channel channel = connection.createChannel();
//队列声明
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//绑定队列到交换机 转发器
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
channel.basicQos(1);//保证一次只分发一个
//定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body,"utf-8");
System.out.println("[2] Recv msg:"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[2] done ");
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
boolean autoAck=false;//自动应答 false
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}
1.5 Routing
1.5.1 概述
* 匹配1个
# 匹配一个或多个
1.5.2 示例
packagerabbitmq.routing;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.mmr.rabbitmq.util.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class Send {
private static final String EXCHANGE_NAME="test_exchange_direct";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
//exchange
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
String msg="hello direct!";
String routingKey="info";
channel.basicPublish(EXCHANGE_NAME, routingKey, null, msg.getBytes());
System.out.println("send "+msg);
channel.close();
connection.close();
}
}
public class Recv1 {
private static final String EXCHANGE_NAME = "test_exchange_direct";
private static final String QUEUE_NAME = "test_queue_direct_1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
final Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "error");
channel.basicQos(1);
//定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body,"utf-8");
System.out.println("[1] Recv msg:"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[1] done ");
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
boolean autoAck=false;//自动应答 false
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}
public class Recv2 {
private static final String EXCHANGE_NAME = "test_exchange_direct";
private static final String QUEUE_NAME = "test_queue_direct_2";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
final Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "error");
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "info");
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "warning");
channel.basicQos(1);
//定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body,"utf-8");
System.out.println("[2] Recv msg:"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[2] done ");
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
boolean autoAck=false;//自动应答 false
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}
1.6 Topics
1.6.1 概述
1.6.2 示例
package rabbitmq.topic;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.mmr.rabbitmq.util.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class Send {
private static final String EXCHANGE_NAME = "test_exchange_topic";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
//exchange
channel.exchangeDeclare(EXCHANGE_NAME, "topic");//topic注意
String msgString="商品....";
channel.basicPublish(EXCHANGE_NAME, "goods.delete", null, msgString.getBytes());
System.out.println("---send "+msgString);
channel.close();
connection.close();
}
}
public class Recv1 {
private static final String EXCHANGE_NAME = "test_exchange_topic";
private static final String QUEUE_NAME = "test_queue_topic_1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
final Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "goods.add"); //topic注意
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "goods.update");//topic注意
channel.basicQos(1);
//定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body,"utf-8");
System.out.println("[1] Recv msg:"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[1] done ");
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
boolean autoAck=false;//自动应答 false
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}
public class Recv2 {
private static final String EXCHANGE_NAME = "test_exchange_topic";
private static final String QUEUE_NAME = "test_queue_topic_2";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
final Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "goods.#");//topic注意
channel.basicQos(1);
//定义一个消费者
Consumer consumer=new DefaultConsumer(channel){
//消息到达 触发这个方法
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
String msg=new String(body,"utf-8");
System.out.println("[2] Recv msg:"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
System.out.println("[2] done ");
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
boolean autoAck=false;//自动应答 false
channel.basicConsume(QUEUE_NAME,autoAck , consumer);
}
}
1.7 RPC
1.8 重要源码分析
public class ConnectionFactory implements Cloneable {
public Connection newConnection() throws IOException, TimeoutException {
return newConnection(this.sharedExecutor, Collections.singletonList(new Address(getHost(), getPort())));
}
}
public interface Channel extends ShutdownNotifier {
Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map<String, Object> arguments) throws IOException;
void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;
void basicQos(int prefetchCount) throws IOException;
Exchange.DeclareOk exchangeDeclare(String exchange, String type) throws IOException;
}
1.9 常用API
1.9.1 autoAck及basicAck (自动应答及手工回执)
channel中
//自动应答 ture,如果消息分发给消费者就从内存中删除,这种如果杀死正在处理的消费者,那么数据就丢了,默认为true
boolean autoAck=true;
//自动应答 false,需要手动回执确认收到消息,如果没有收到回执,则会再发送给其它消费者
boolean autoAck=false;
channel.basicConsume(QUEUE_NAME,autoAck , consumer);//设置是否自动应答
//ack Message acknowledgment
//消费时
channel.basicAck(envelope.getDeliveryTag(), false); // 手动回执
1.9.2 durable(消息持久化)
//申明队列是时
Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map<String, Object> arguments) throws IOException;
1.9.3 exchange type(exchange类型)
-
- fanout 分发
不处理,直接转发.
- fanout 分发
-
- direct 处理
- direct 处理
-
- topic 模糊匹配,归类
- topic 模糊匹配,归类
* 匹配1个
# 匹配一个或多个
1.9.4 tx(事务)
能够进行事务管理,但是由于是同步的, 会降低吞吐量.
package com.mmr.rabbitmq.tx;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.mmr.rabbitmq.util.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class TxSend {
private static final String QUEUE_NAME="test_queue_tx";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
String msgString="hello tx message!";
try {
channel.txSelect(); //事务注意
channel.basicPublish("", QUEUE_NAME, null,msgString.getBytes());
int xx=1/0;
System.out.println("send "+msgString);
channel.txCommit(); //事务注意
} catch (Exception e) {
channel.txRollback();//事务注意
System.out.println(" send message txRollback");
}
channel.close();
connection.close();
}
}
public class TxRecv {
private static final String QUEUE_NAME="test_queue_tx";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.basicConsume(QUEUE_NAME, true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
System.out.println("recv[tx] msg:"+new String(body,"utf-8"));
}
});
}
}
1.9.5 confirm(确认模式)
public class Recv {
private static final String QUEUE_NAME="test_queue_confirm3";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.basicConsume(QUEUE_NAME, true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
BasicProperties properties, byte[] body) throws IOException {
System.out.println("recv[confirm] msg:"+new String(body,"utf-8"));
}
});
}
}
/**
*普通模式,发一条(同步)
*/
public class Send1 {
private static final String QUEUE_NAME="test_queue_confirm1";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//生产者调用confirmSelect 将channel设置为confirm模式 注意
channel.confirmSelect(); //confirm注意
String msgString="hello confirm message!";
channel.basicPublish("", QUEUE_NAME, null,msgString.getBytes());
if(!channel.waitForConfirms()){ //confirm注意
System.out.println("message send failed");
}else {
System.out.println("message send ok");
}
channel.close();
connection.close();
}
}
/**
*普通模式-发批量(同步)
*/
public class Send2 {
private static final String QUEUE_NAME="test_queue_confirm1";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//生产者调用confirmSelect 将channel设置为confirm模式 注意
channel.confirmSelect(); //confirm注意
String msgString="hello confirm message batch!";
//批量发送
for (int i = 0; i < 10; i++) {
channel.basicPublish("", QUEUE_NAME, null,msgString.getBytes());
}
//确认
if(!channel.waitForConfirms()){
System.out.println("message send failed");
}else {
System.out.println("message send ok");
}
channel.close();
connection.close();
}
}
/**
* 确认模式-异步模式
*/
public class Send3 {
private static final String QUEUE_NAME="test_queue_confirm3";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//生产者调用confirmSelect 将channel设置为confirm模式 注意
channel.confirmSelect();//confirm注意
//未确认的消息标识
final SortedSet<Long> confirmSet=Collections.synchronizedSortedSet(new TreeSet<Long>());
//通道添加监听
channel.addConfirmListener(new ConfirmListener() {
//没有问题的handleAck,成功的调这里.
public void handleAck(long deliveryTag, boolean multiple)
throws IOException {
if(multiple){//多条
System.out.println("----handleAck----multiple");
confirmSet.headSet(deliveryTag+1).clear(); //headSet是返回此有序集合中小于(deliveryTag+1)的所有元素,clear是并清除
}else{//单条
System.out.println("----handleAck-----multiple false");
confirmSet.remove(deliveryTag);
}
}
//handleNack,失败的调这里.
public void handleNack(long deliveryTag, boolean multiple)
throws IOException {
if(multiple){//多条
System.out.println("---handleNack------multiple");
confirmSet.headSet(deliveryTag+1).clear();//headSet是返回此有序集合中小于(deliveryTag+1)的所有元素,clear是并清除
}else{//单条
System.out.println("--handleNack-------multiple false");
confirmSet.remove(deliveryTag);
}
}
});
String msgStr="ssssss";
while(true){
long seqNo = channel.getNextPublishSeqNo();//消息编号,序列
channel.basicPublish("", QUEUE_NAME, null, msgStr.getBytes());
confirmSet.add(seqNo); //边发,边存.
}
}
}
1.10 注意
- 已经申明过的队列,不能修改队列属性(rabbitmq不允许用不同参数重新定义的已存在的队列)
注:根据牧马人老王整理.