学习交流群:817080571
<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>
</dependencies>
链接RabbitMQ
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ConnectionUtils {
public static Connection getConnection() throws IOException, TimeoutException {
//链接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置服务地址
factory.setHost("127.0.0.1");
//设置端口
factory.setPort(5672);
//设置vhost
factory.setVirtualHost("/vhost");
//设置用户名
factory.setUsername("victoria");
//设置密码
factory.setPassword("123");
return factory.newConnection();
}
}
即简单的点对点消息模型。开启mq服务,开启进程P 生产者向mq 写消息,进程C消费者监听mq,消费消息。
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
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_str = "hello simple !";
//发送消息
channel.basicPublish("",QUEUE_NAME,null,msg_str.getBytes());
System.out.println("--send simple"+msg_str);
//关闭
channel.close();
connection.close();
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class recv {
private static final String QUEUE_NAME = "test_simple_queue";
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);
//定义一个消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("---new recv" + new String(body, "utf-8"));
}
};
//监听队列
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
耦合度高,生产者和消费者一一对应,如果想有多个消费者消费队列就不可能了。如果队列名变更,消费者和生产者需要同时变更
一个生产者P,对应了多个消费者C。这些多个C,消费的消息各自不同,C1和C2 消费的消息,构成所有消息的一个全集。
可以开启C的消费竞争 channel.basicQos(1);C1和C2 能者多劳。
无论消费者速度快与慢,消费者都只会完成它所负责的那部分,其它消息即使没有被消费,它也不会去消费
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class send {
private static final String QUEUE_NAME = "test_work_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);
//生产者
for(int i = 0 ; i<50;i++){
String str_msg = "hello"+i;
channel.basicPublish("",QUEUE_NAME,null,str_msg.getBytes());
System.out.println(str_msg);
}
//关闭通道
channel.close();
//关闭链接
connection.close();
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
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 = connection.createChannel();
//定义队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//定义消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv1]+"+new String(body,"utf-8"));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//监听队列
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
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 = connection.createChannel();
//定义队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//定义消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv2]+"+new String(body,"utf-8"));
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//监听队列
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
解决了上面循环分发,完成固定消息的问题,解决消息速度快的将多解决消息,
一次只发布一条消息
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class send {
private static final String QUEUE_NAME = "test_work_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);
//一次只发一条消息
channel.basicQos(1);
//生产者
for(int i = 0 ; i<50;i++){
String str_msg = "hello"+i;
channel.basicPublish("",QUEUE_NAME,null,str_msg.getBytes());
System.out.println(str_msg);
}
//关闭通道
channel.close();
//关闭链接
connection.close();
}
}
一次只接受一条消息,关闭了自动接受,改为手动接受,给与消息队列ACK值
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
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();
//创建通道
final Channel channel = connection.createChannel();
//定义队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//一次只接受一条数据
channel.basicQos(1);
//定义消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv1]+"+new String(body,"utf-8"));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
//监听队列
channel.basicConsume(QUEUE_NAME,false,consumer);
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
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();
//创建通道
final Channel channel = connection.createChannel();
//定义队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//一次只接受一条数据
channel.basicQos(1);
//定义消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv2]+"+new String(body,"utf-8"));
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
//监听队列
channel.basicConsume(QUEUE_NAME,false,consumer);
}
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
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");
//一次只发一条数据
channel.basicQos(1);
//生产者
String str_msg = "hello exchange";
channel.basicPublish(EXCHANGE_NAME,"",null,str_msg.getBytes());
System.out.println(str_msg);
//关闭通道
channel.close();
//关闭链接
connection.close();
}
}
使用订阅模式,只启动生产者是看不到消息在哪里的
因为交换机没有存储的能力,RabbitMQ中只有队列有存储的能力
这个时候还没有队列绑定到这个交换机
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class recv1 {
private static final String QUEUE_NAME = "test_queue_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, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv1]+"+new String(body,"utf-8"));
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
//监听队列
boolean ack = false;
channel.basicConsume(QUEUE_NAME,ack,consumer);
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class recv2 {
private static final String QUEUE_NAME = "test_queue_cms";
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, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv2]+"+new String(body,"utf-8"));
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
//监听队列
boolean ack = false;
channel.basicConsume(QUEUE_NAME,ack,consumer);
}
}
运行完消费者后可以再交换机那里看到绑定的队列
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
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();
//定义交换机
channel.exchangeDeclare(EXCHANGE_NAME,"direct");
//一次只能发送一条数据
channel.basicQos(1);
//发送的消息
String str_msg = "hello direct";
//定义路由键
String rount_key = "info";
//生产者
channel.basicPublish(EXCHANGE_NAME,rount_key,null,str_msg.getBytes());
System.out.println(str_msg);
//关闭
channel.close();
connection.close();
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class recv1 {
private static final String QUEUE_NAME = "test_queue_recv1";
private static final String EXCHANGE_NAME= "test_exchange_direct";
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, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv1]:" + new String(body, "utf-8"));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//手动提交
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
//监听队列
//手动提交
boolean ack = false;
channel.basicConsume(QUEUE_NAME,ack,consumer);
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class recv2 {
private static final String QUEUE_NAME = "test_queue_recv2";
private static final String EXCHANGE_NAME= "test_exchange_direct";
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, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv1]:" + new String(body, "utf-8"));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//手动提交
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
//监听队列
//手动提交
boolean ack = false;
channel.basicConsume(QUEUE_NAME,ack,consumer);
}
}
路由模式,只能按照路由键来匹配队列,必须得路由键相同的队列才能获取到消息, 这样对多服务的项目不太友好
在路由模式的基础上添加了匹配。
交换机的type=topic
"#"代表一个和多个
“*”代表一个
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
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();
//定义交换机
channel.exchangeDeclare(EXCHANGE_NAME,"topic");
//一次只接受一条消息
channel.basicQos(1);
//消息
String str_msg = "hello topic";
//路由键
String rount_key = "goods.delete";
//生产者
channel.basicPublish(EXCHANGE_NAME,rount_key,null,str_msg.getBytes());
System.out.println(str_msg);
//关闭
channel.close();
connection.close();
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class recv1 {
private static final String QUEUE_NAME = "test_queue_topic1" ;
private static final String EXCHANGE_NAME = "test_exchange_topic";
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");
//一次只接受一条消息
channel.basicQos(1);
//消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv1]:" + new String(body, "utf-8"));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//手动提交
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
//监听队列
//手动提交
boolean ack = false;
channel.basicConsume(QUEUE_NAME,ack,consumer);
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class recv2 {
private static final String QUEUE_NAME = "test_queue_topic2";
private static final String EXCHANGE_NAME = "test_exchange_topic";
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.#");
//一次只接受一条消息
channel.basicQos(1);
//消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv2]:" + new String(body, "utf-8"));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//手动提交
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
//监听队列
//手动提交
boolean ack = false;
channel.basicConsume(QUEUE_NAME,ack,consumer);
}
}
boolean ack = false;
channel.basicConsume(QUEUE_NAME,ack,consumer);
一旦RabbitMQ将消息发送给消费者,RabbitMQ就会从内存中删除这个消息
如果RabbitMQ发送给消费者的过程中,消费者被终止,则这个消息也会从内存中删除
解决了上面自动应答的问题,只有消费者自己给RabbitMQ应答时,RabbitMQ才会从内存中删除消息,如果RabbitMQ发送给消费者的过程中,消费者被终止,则这条消息将会传递给下一个消费者完成
RabbitMQ发送消息的过程中,RabbitMQ挂掉了的问题
可以在定义队列时,完成消息持久化
//定义队列
//消息持久化
boolean durable = true;
channel.queueDeclare(QUEUE_NAME,durable,false,false,null);
如果设置durable=true;则打开了消息持久化,为false则反之
如果消息队列已经存在,则不能改变该队列消息持久化
一边接受生产者的消息,一边向队列推送消息
在RabbitMQ中我们可以通过持久化数据,解决RabbitMQ服务器异常的数据丢失问题
问题:生产者讲消息发送出去后,消息到底到没到达RabbitMQ服务器,默认的情况是不知道的;
两种方式:
AMQP实现事务机制
Confirm模式
txSelect:用户将当前channel设置成transation模式
txcommit:用于提交事务
txrollback:用户回滚事务
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
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);
//一次只能发送一条消息
channel.basicQos(1);
try {
//事务开始
channel.txSelect();
String str_msg = "send_tx";
//生产者(发布消息)
channel.basicPublish("",QUEUE_NAME,null,str_msg.getBytes());
System.out.println(str_msg);
//事务提交
channel.txCommit();
} catch (Exception e) {
System.out.println("tx_rollback");
//事务回滚
channel.txRollback();
} finally {
//关闭链接
channel.close();
connection.close();
}
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
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.basicQos(1);
//消费者(收取消息)
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv1]"+new String(body,"utf-8"));
}
};
//监听
channel.basicConsume(QUEUE_NAME,false,consumer);
}
}
此模式很耗时,降低了RabbitMQ的消息吞吐量
好处是能异步发送
channel.confirmSelect();
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class sendsingle {
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);
//一次只发送一条消息
channel.basicQos(1);
//开启confirm模式
channel.confirmSelect();
String str_msg = "hello confirm";
//发布消息(生产者)
channel.basicPublish("",QUEUE_NAME,null,str_msg.getBytes());
//判断是否有waitForConfirms
//有则代表发布消息成功,否则反之
if(channel.waitForConfirms()){
System.out.println("send confirm ok");
}else{
System.out.println("send confirm error");
}
//关闭链接
channel.close();
connection.close();
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class recvsingle {
private static final String QUEUE_NAME = "test_queue_confirm1";
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.basicQos(1);
//接受消息(消费者)
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv1]->"+new String(body,"utf-8"));
}
};
//监听
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class sendbatch {
private static final String QUEUE_NAME = "test_queue_confirm2";
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);
//一次只发送一条消息
channel.basicQos(1);
//开启confirm模式
channel.confirmSelect();
String str_msg = "hello confirm batch!";
//批量发布消息(生产者)
for(int i = 0 ;i<10;i++){
channel.basicPublish("",QUEUE_NAME,null,str_msg.getBytes());
}
//判断是否有waitForConfirms
//有则代表发布消息成功,否则反之
if(channel.waitForConfirms()){
System.out.println("send confirm ok");
}else{
System.out.println("send confirm error");
}
//关闭链接
channel.close();
connection.close();
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class recvbatch {
private static final String QUEUE_NAME = "test_queue_confirm2";
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.basicQos(1);
//接受消息(消费者)
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv1]->"+new String(body,"utf-8"));
}
};
//监听
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
Channel对象提供的ConfirmListener0回调方法只包含deliveryTag (当前Chanel发出的消息序号),我们需要自己为每一个Channel维护一个unconfirm的消息序号集合,每publish 一条数据,集合中元素加1,每回调一次handleAck方法,unconfirm集合删掉
相应的一条(multiple=false) 或多条(multiple=true) 记录。从程序运行效率上看,这个unconfirm集合最好采用有序集合SortedSet存储结构。
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
public class sendasyn {
private static final String QUEUE_NAME = "test_queue_confirm3";
public static void main(String[] args) throws Exception {
Connection connetion = ConnectionUtils.getConnection();
Channel channel = connetion.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//生产者调用confirmselect将channel 设置为conf1xm模式
//注意confirm模式跟事务机制不能在同一个队列中
channel.confirmSelect();
//未确认的消息标识
final SortedSet<Long> confirmSet = Collections.synchronizedSortedSet(new TreeSet<Long>());
channel.addConfirmListener(new ConfirmListener() {
/*
* 处理返回确认成功
* @param deliveryTag 如果是多条,这个就是最后一条消息的tag
* @param multiple 是否多条
* @throws IOException
*/
public void handleAck(long l, boolean b) throws IOException {
if(b){
System.out.println("----handleAck----multip1e");
confirmSet.headSet(l+1).clear();
}else {
System.out.println("----handleAck----multip1e false");
confirmSet.remove(l);
}
}
/*
* 处理返回确认失败
* @param deliveryTag 如果是多条,这个就是最后一条消息的tag
* @param multiple 是否多条
* @throws IOException
*/
public void handleNack(long l, boolean b) throws IOException {
if(b){
System.out.println("----handleNack----multip1e");
confirmSet.headSet(l+1).clear();
}else {
System.out.println("----handleNack----multip1e false");
confirmSet.remove(l);
}
}
});
String msg = "hello confirm message!";
while (true){
long seqNo = channel.getNextPublishSeqNo();
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes());
confirmSet.add(seqNo);
}
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class recvasyn {
private static final String QUEUE_NAME = "test_queue_confirm3";
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.basicQos(1);
//接受消息(消费者)
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("[recv3]->"+new String(body,"utf-8"));
}
};
//监听
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
basicPublish方法的参数mandatory
如果设置mandatory 为true时,交换器无法根据自身的类型和路由键找到一个符合条件的队列,那么RabbitMQ 会调用Basic.Return 命令将消息返回给生产者。
当mandatory参数设置为false 时,出现上述情形,则消息直接被丢弃;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ReturnListener;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class sendreturn {
private static final String EXCHANGE_NAME = "test_exchange_return";
public static void main(String[] args) throws IOException, TimeoutException {
//获取链接
Connection connection = ConnectionUtils.getConnection();
//创建通道
Channel channel = connection.createChannel();
//一次只发送一条消息
channel.basicQos(1);
//路由键名
String rount_key = "useaar.add";
String str_msg = "Hello exchange return";
//发送消息
channel.basicPublish(EXCHANGE_NAME,rount_key,true,null,str_msg.getBytes());
//return消息机制监听
channel.addReturnListener(new ReturnListener() {
//消息没到达执行的方法
public void handleReturn(int i, String s, String s1, String s2, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
System.out.println("----------return ---------");
//参数一:相应码
System.out.println(i);
//参数二:文本
System.out.println(s);
//参数三:交换机名
System.out.println(s1);
//参数四:路由键名
System.out.println(s2);
//参数五:basicProperties
System.out.println(basicProperties);
//参数流:传递的消息
System.out.println(new String(bytes));
}
});
}
}
import com.rabbitmq.client.*;
import com.victoria.rabbitmq.util.ConnectionUtils;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class recvreturn {
private static final String QUEUE_NAME = "test_queue_return";
private static final String EXCHANGE_NAME = "test_exchange_return";
public static void main(String[] args) throws IOException, TimeoutException {
//获取链接
Connection connection = ConnectionUtils.getConnection();
//创建通道
Channel channel = connection.createChannel();
//一次只接受一条消息
channel.basicQos(1);
//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME,"topic",true,false,null);
//声明队列
channel.queueDeclare(QUEUE_NAME,true,false,false,null);
//路由键匹配
String rount_key = "user.#";
//队列绑定交换机
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,rount_key);
//消息接收(消费者)
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body));
}
};
//监听
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}