文章目录
RabbitMQ
MQ是什么
MQ:Message Queue消息队列
MQ是用来干嘛的呢?
消息队列:
队列-----先进先出
消息------传输的消息
向队列中存放传输的消息
消息队列有点类似于生活中的物流
你只需要将物品放到这个物流的平台上 物流就会给你进行运输到指定的目的地
使用MQ到底有什么作用呢?
1:可以将并行的请求串行化 -------- 消流 流量的消峰
2:模块之间的异步通信 主要是用在微服务上实现服务之间的异步通信
常见的消息队列有哪些呢?
JMS:JAVA Message Service :这个是JAVA的消息服务 是sun公司制定的一个标准
这个标准中存在两种通信模型
队列模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IEYoZSfn-1585470194466)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\msohtmlclip1\01\clip_image002.jpg)]
主题模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IiwpY9Gs-1585470194470)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\msohtmlclip1\01\clip_image004.jpg)]
ActiveMQ(简单的一个 实现sun公司制定的 JMS标准)
RabbitMQ(这个是我们讲的)
RocketMQ(阿里的)
Kafka(原本的设计初衷不是用来做消息队列的 是用来进行日志的处理的 因为日志有严格的顺序问题 所以就用来做消息队列来了)
RabbitMQ是什么?
RabbitMQ就是一个消息中间件 这个消息的中间件的作用就是实现 上面MQ的两个功能
RabbitMQ能干什么?
- 模块之间的异步通信
- 流量的消峰处理
- 将并行的处理串行化
RabbitMQ的安装
(2) 从EPEL源安装(这种方式安装的Erlang版本可能不是最新的,有时候不能满足RabbitMQ需要的最低版本)
yum install epel-release
yum install erlang
安装RabbitMQ:
wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.15/rabbitmq-server-3.6.15-1.el7.noarch.rpm
下载完成后安装:
yum install rabbitmq-server-3.6.15-1.el7.noarch.rpm
安装时如果遇到下面的依赖错误:
Error: Package: socat-1.7.2.3-1.el6.x86_64 (epel) Requires: libreadline.so.5()(64bit)
可以尝试先执行:
yum install socat
RabbitMQ的一些基本操作:
# 添加开机启动RabbitMQ服务
systemctl enable rabbitmq-server.service
#查看服务状态
systemctl status rabbitmq-server.service
启动服务
systemctl start rabbitmq-server.service
停止服务
systemctl stop rabbitmq-server.service
查看当前所有用户
rabbitmqctl list_users
查看默认guest用户的权限
rabbitmqctl list_user_permissions guest
由于RabbitMQ默认的账号用户名和密码都是guest。为了安全起见, 先删掉默认用户
rabbitmqctl delete_user guest
添加新用户
rabbitmqctl add_user `username` `password` (此处设置自己的用户名和密码)
设置用户tag
rabbitmqctl set_user_tags username administrator
赋予用户默认vhost的全部操作权限
rabbitmqctl set_permissions -p / username ".*" ".*" ".*"
查看用户的权限
rabbitmqctl list_user_permissions username
开启web管理接口 如果只从命令行操作RabbitMQ,多少有点不方便。幸好RabbitMQ自带了web管理界面,只需要启动插件便可以使用。
rabbitmq-plugins enable rabbitmq_management
访问: Linux远程地址:15672 例如:http://192.168.9.128:15672
登录遇到问题:User can only log in localhost
原因是从RabbitMQ3.3.0开始,禁止使用guest/guest权限通过localhost外的访问
所以最好新建一个用户
RabbitMQ的五种通信模型
基本的通信模型
1:创建一个帮助类
public class ConnectionUtils {
/**
* 返回连接服务器的连接
* @return
* @throws IOException
* @throws TimeoutException
*/
public static Connection getConnection() throws IOException, TimeoutException { //申明一个连接的工厂
ConnectionFactory connectionFactory = new ConnectionFactory(); //设置RabbitMQ的主机的地址
connectionFactory.setHost("116.62.6.66");
//设置虚拟主机 这里一般写成/就OK了 connectionFactory.setVirtualHost("/");
//设置用户名
connectionFactory.setUsername("xiaobobo");
//设置密码
connectionFactory.setPassword("123456");
//设置请求的服务的端口
connectionFactory.setPort(5672);
//返回这个连接
return connectionFactory.newConnection();
}
}
2:创建生产者
public class Sender {
private static final String QUEUE_NAME="queue_01"; public static void main(String[] args) throws IOException, TimeoutException {
//第一步:获取连接
Connection connection = ConnectionUtils.getConnection(); //第二步:创建通道
Channel channel = connection.createChannel(); //第三步:申明队列
/**
* 第一个参数:队列的名字
* 第二个参数:是否持久化 如果rabbitmq从新启动的话 那么 这个数据会丢失 持久化就可以解决这个问题 * 第三个参数:是否排外 * 1:连接关闭之后这个队列是否自动删除 * 2:是否允许其他的通道来进行访问 * 第四个参数:是否自动删除 * 当最后一个连接断开的时候 是否需要自动删除 * 第五个参数:申明队列带的这个参数 * */ channel.queueDeclare(QUEUE_NAME,false,false,false,null); //第四步:发送数据到队列
* /**
* * 第一个参数:交换机 没有就写""
* * 第二个参数:路由的key 只有队列的名字
* * 第三个参数:发送数据的时候可以携带参数
* */
* channel.basicPublish("",QUEUE_NAME,null,"我是HelloWorld发送的数据".getBytes());
* channel.close();
* connection.close(); } }
3:创建消费者
public class Consumer {
private static final String QUEUE_NAME="queue_01"; public static void main(String[] args) throws IOException, TimeoutException {
//第一步:获取连接
Connection connection = ConnectionUtils.getConnection();
//第二步:创建通道
Channel channel = connection.createChannel();
//第三步:申明队列
/**
* 第一个参数:队列的名字
* 第二个参数:是否持久化 如果rabbitmq从新启动的话 那么 这个数据会丢失 持久化就可以解决这个问题
* 第三个参数:是否排外
* * 1:连接关闭之后这个队列是否自动删除
* * 2:是否允许其他的通道来进行访问
* * 第四个参数:是否自动删除 * 当最后一个连接断开的时候 是否需要自动删除 * 第五个参数:申明队列带的这个参数
* *
* */
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//申明了一个消费者
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
/** * * @param consumerTag:消费者的唯一的标记 * @param envelope:信封 就是将请求的消息封装成一个对象 * @param properties:前面队列带过来的属性的值 * @param body:消息体 * @throws IOException */ @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,defaultConsumer); } }
Work模型
一个队列存在多个消费者的时候 多个消费者消费的数据之和 才是原来队列中的所有数据
1:生产者
public class Sender {
private static final String QUEUE_NAME = "queue_03";
public static void main(String[] args) throws IOException, TimeoutException {
//第一步:获取连接
Connection connection = ConnectionUtils.getConnection();
// 第二步:创建通道
Channel channel = connection.createChannel();
// 第三步:申明队列
/**
* * 第一个参数:队列的名字
* * 第二个参数:是否持久化 如果rabbitmq从新启动的话 那么 这个数据会丢失 持久化就可以解决这个问题
* * 第三个参数:是否排外
* * 1:连接关闭之后这个队列是否自动删除
* * 2:是否允许其他的通道来进行访问
* * 第四个参数:是否自动删除
* * 当最后一个连接断开的时候 是否需要自动删除
* * 第五个参数:申明队列带的这个参数
* *
* */
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//第四步:发送数据到队列
/**
* * 第一个参数:交换机 没有就写""
* * 第二个参数:路由的key 只有队列的名字
* * 第三个参数:发送数据的时候可以携带参数
* */
for (int i = 0; i < 100; i++) {
channel.basicPublish("", QUEUE_NAME, null, ("我是WorkQueue模型传输的数据" + i).getBytes());
}
channel.close();
connection.close();
}
}
2:消费者1
public class Consumer1 { private static final String QUEUE_NAME=“queue_03”; public static void main(String[] args) throws IOException, TimeoutException { //第一步:获取连接 Connection connection = ConnectionUtils.getConnection(); //第二步:创建通道 final Channel channel = connection.createChannel(); //第三步:申明队列 /** * 第一个参数:队列的名字 * 第二个参数:是否持久化 如果rabbitmq从新启动的话 那么 这个数据会丢失 持久化就可以解决这个问题 * 第三个参数:是否排外 * 1:连接关闭之后这个队列是否自动删除 * 2:是否允许其他的通道来进行访问 * 第四个参数:是否自动删除 * 当最后一个连接断开的时候 是否需要自动删除 * 第五个参数:申明队列带的这个参数 * / channel.queueDeclare(QUEUE_NAME,false,false,false,null); //没有确认的话 那么就不用分配任务给我 channel.basicQos(1); //申明了一个消费者 DefaultConsumer defaultConsumer = new DefaultConsumer(channel) { /* * * @param consumerTag:消费者的唯一的标记 * @param envelope:信封 就是将请求的消息封装成一个对象 * @param properties:前面队列带过来的属性的值 * @param body:消息体 * @throws IOException / @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { System.out.println(“11111111111收到消息了:”+new String(body)); try { Thread.sleep(1000); }catch (Exception err){ } //表示的是手动告诉队列我已经收到这个消息了 channel.basicAck(envelope.getDeliveryTag(),false); } }; /* * 第一个参数:队列的名字 * 第二个参数:是否自动应答 false:表示的是要手动应答 没有应答的话 那么在队列中依然存在 * 第三个参数:消费者的申明 */ channel.basicConsume(QUEUE_NAME,false,defaultConsumer); // channel.close(); // // connection.close(); } }
3:消费者2
public class Consumer2 { private static final String QUEUE_NAME=“queue_03”; public static void main(String[] args) throws IOException, TimeoutException { //第一步:获取连接 Connection connection = ConnectionUtils.getConnection(); //第二步:创建通道 final Channel channel = connection.createChannel(); //第三步:申明队列 /** * 第一个参数:队列的名字 * 第二个参数:是否持久化 如果rabbitmq从新启动的话 那么 这个数据会丢失 持久化就可以解决这个问题 * 第三个参数:是否排外 * 1:连接关闭之后这个队列是否自动删除 * 2:是否允许其他的通道来进行访问 * 第四个参数:是否自动删除 * 当最后一个连接断开的时候 是否需要自动删除 * 第五个参数:申明队列带的这个参数 * / channel.queueDeclare(QUEUE_NAME,false,false,false,null); //这句话的意思是我还没有确认的时候 你没有必要给我分配任务 channel.basicQos(1); //申明了一个消费者 DefaultConsumer defaultConsumer = new DefaultConsumer(channel) { /* * * @param consumerTag:消费者的唯一的标记 * @param envelope:信封 就是将请求的消息封装成一个对象 * @param properties:前面队列带过来的属性的值 * @param body:消息体 * @throws IOException / @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { System.out.println(“222222222222收到消息了:”+new String(body)); //表示的是手动告诉队列我已经收到这个消息了 channel.basicAck(envelope.getDeliveryTag(),false); } }; /* * 第一个参数:队列的名字 * 第二个参数:是否自动应答 false:表示的是要手动应答 没有应答的话 那么在队列中依然存在 * 第三个参数:消费者的申明 */ channel.basicConsume(QUEUE_NAME,false,defaultConsumer); // channel.close(); // // connection.close(); } }
发布订阅模式(经常用来做模块之间的异步通信)
生产者
public class Sender { //定义一个交换机的名字 private static final String EXCHANGE_NAME=“exchange1”; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtils.getConnection(); Channel channel = connection.createChannel(); //申明的是交换机 /** * 第一个参数:交换机的名字 * 第二个参数:交换机的类型 如果是发布订阅模式的话那么 交换机的类型只能是fanout */ channel.exchangeDeclare(EXCHANGE_NAME,“fanout”); //生产者发送信息到交换机 for (int i = 0; i <100 ; i++) { channel.basicPublish(EXCHANGE_NAME,"",null,(“发布订阅模式下的值”+i).getBytes()); } //关闭资源 channel.close(); connection.close(); } }
消费者1
public class Consumer1 { private static final String QUEUE_NAME=“queue_05”; private static final String EXCHANGE_NAME=“exchange1”; public static void main(String[] args) throws IOException, TimeoutException { //第一步:获取连接 Connection connection = ConnectionUtils.getConnection(); //第二步:创建通道 final Channel channel = connection.createChannel(); //第三步:申明队列 /** * 第一个参数:队列的名字 * 第二个参数:是否持久化 如果rabbitmq从新启动的话 那么 这个数据会丢失 持久化就可以解决这个问题 * 第三个参数:是否排外 * 1:连接关闭之后这个队列是否自动删除 * 2:是否允许其他的通道来进行访问 * 第四个参数:是否自动删除 * 当最后一个连接断开的时候 是否需要自动删除 * 第五个参数:申明队列带的这个参数 * / channel.queueDeclare(QUEUE_NAME,false,false,false,null); //申明交换机 channel.exchangeDeclare(EXCHANGE_NAME,“fanout”); //将队列绑定到交换机上 channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,""); //没有确认的话 那么就不用分配任务给我 channel.basicQos(1); //申明了一个消费者 DefaultConsumer defaultConsumer = new DefaultConsumer(channel) { /* * * @param consumerTag:消费者的唯一的标记 * @param envelope:信封 就是将请求的消息封装成一个对象 * @param properties:前面队列带过来的属性的值 * @param body:消息体 * @throws IOException / @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { System.out.println(“11111111111收到消息了:”+new String(body)); //表示的是手动告诉队列我已经收到这个消息了 channel.basicAck(envelope.getDeliveryTag(),false); } }; /* * 第一个参数:队列的名字 * 第二个参数:是否自动应答 false:表示的是要手动应答 没有应答的话 那么在队列中依然存在 * 第三个参数:消费者的申明 */ channel.basicConsume(QUEUE_NAME,false,defaultConsumer); } }
消费者2
public class Consumer2 { private static final String QUEUE_NAME=“queue_06”; private static final String EXCHANGE_NAME=“exchange1”; public static void main(String[] args) throws IOException, TimeoutException { //第一步:获取连接 Connection connection = ConnectionUtils.getConnection(); //第二步:创建通道 final Channel channel = connection.createChannel(); //第三步:申明队列 /** * 第一个参数:队列的名字 * 第二个参数:是否持久化 如果rabbitmq从新启动的话 那么 这个数据会丢失 持久化就可以解决这个问题 * 第三个参数:是否排外 * 1:连接关闭之后这个队列是否自动删除 * 2:是否允许其他的通道来进行访问 * 第四个参数:是否自动删除 * 当最后一个连接断开的时候 是否需要自动删除 * 第五个参数:申明队列带的这个参数 * / channel.queueDeclare(QUEUE_NAME,false,false,false,null); //申明交换机 channel.exchangeDeclare(EXCHANGE_NAME,“fanout”); //将队列绑定到交换机上 channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,""); //没有确认的话 那么就不用分配任务给我 channel.basicQos(1); //申明了一个消费者 DefaultConsumer defaultConsumer = new DefaultConsumer(channel) { /* * * @param consumerTag:消费者的唯一的标记 * @param envelope:信封 就是将请求的消息封装成一个对象 * @param properties:前面队列带过来的属性的值 * @param body:消息体 * @throws IOException / @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { System.out.println(“11111111111收到消息了:”+new String(body)); //表示的是手动告诉队列我已经收到这个消息了 channel.basicAck(envelope.getDeliveryTag(),false); } }; /* * 第一个参数:队列的名字 * 第二个参数:是否自动应答 false:表示的是要手动应答 没有应答的话 那么在队列中依然存在 * 第三个参数:消费者的申明 */ channel.basicConsume(QUEUE_NAME,false,defaultConsumer); } }
路由模式(有选择性的路由到提前设置好的队列)
1:生产者
public class Sender { //定义一个交换机的名字 private static final String EXCHANGE_NAME=“exchange2”; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtils.getConnection(); Channel channel = connection.createChannel(); //申明的是交换机 /** * 第一个参数:交换机的名字 * 第二个参数:交换机的类型 如果是发布订阅模式的话那么 交换机的类型只能是fanout / channel.exchangeDeclare(EXCHANGE_NAME,“direct”); //生产者发送信息到交换机 /* * 第二个参数:路由的key * 这个key可以进行自己设置 xiaobobo */ for (int i = 0; i <100 ; i++) { channel.basicPublish(EXCHANGE_NAME,“xiaowangzi”,null,(“发布订阅模式下的值”+i).getBytes()); } //关闭资源 channel.close(); connection.close(); } }
2:消费者1
public class Consumer1 { private static final String QUEUE_NAME=“queue_07”; private static final String EXCHANGE_NAME=“exchange2”; public static void main(String[] args) throws IOException, TimeoutException { //第一步:获取连接 Connection connection = ConnectionUtils.getConnection(); //第二步:创建通道 final Channel channel = connection.createChannel(); //第三步:申明队列 /** * 第一个参数:队列的名字 * 第二个参数:是否持久化 如果rabbitmq从新启动的话 那么 这个数据会丢失 持久化就可以解决这个问题 * 第三个参数:是否排外 * 1:连接关闭之后这个队列是否自动删除 * 2:是否允许其他的通道来进行访问 * 第四个参数:是否自动删除 * 当最后一个连接断开的时候 是否需要自动删除 * 第五个参数:申明队列带的这个参数 * / channel.queueDeclare(QUEUE_NAME,false,false,false,null); //申明交换机 channel.exchangeDeclare(EXCHANGE_NAME,“direct”); //将队列绑定到交换机上 channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,“xiaobobo”); //没有确认的话 那么就不用分配任务给我 channel.basicQos(1); //申明了一个消费者 DefaultConsumer defaultConsumer = new DefaultConsumer(channel) { /* * * @param consumerTag:消费者的唯一的标记 * @param envelope:信封 就是将请求的消息封装成一个对象 * @param properties:前面队列带过来的属性的值 * @param body:消息体 * @throws IOException / @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { System.out.println(“11111111111收到消息了:”+new String(body)); //表示的是手动告诉队列我已经收到这个消息了 channel.basicAck(envelope.getDeliveryTag(),false); } }; /* * 第一个参数:队列的名字 * 第二个参数:是否自动应答 false:表示的是要手动应答 没有应答的话 那么在队列中依然存在 * 第三个参数:消费者的申明 */ channel.basicConsume(QUEUE_NAME,false,defaultConsumer); } }
3:消费者2
public class Consumer2 { private static final String QUEUE_NAME=“queue_08”; private static final String EXCHANGE_NAME=“exchange2”; public static void main(String[] args) throws IOException, TimeoutException { //第一步:获取连接 Connection connection = ConnectionUtils.getConnection(); //第二步:创建通道 final Channel channel = connection.createChannel(); //第三步:申明队列 /** * 第一个参数:队列的名字 * 第二个参数:是否持久化 如果rabbitmq从新启动的话 那么 这个数据会丢失 持久化就可以解决这个问题 * 第三个参数:是否排外 * 1:连接关闭之后这个队列是否自动删除 * 2:是否允许其他的通道来进行访问 * 第四个参数:是否自动删除 * 当最后一个连接断开的时候 是否需要自动删除 * 第五个参数:申明队列带的这个参数 * / channel.queueDeclare(QUEUE_NAME,false,false,false,null); //申明交换机 channel.exchangeDeclare(EXCHANGE_NAME,“direct”); //将队列绑定到交换机上 channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,“xiaowangzi”); //没有确认的话 那么就不用分配任务给我 channel.basicQos(1); //申明了一个消费者 DefaultConsumer defaultConsumer = new DefaultConsumer(channel) { /* * * @param consumerTag:消费者的唯一的标记 * @param envelope:信封 就是将请求的消息封装成一个对象 * @param properties:前面队列带过来的属性的值 * @param body:消息体 * @throws IOException / @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { System.out.println(“11111111111收到消息了:”+new String(body)); //表示的是手动告诉队列我已经收到这个消息了 channel.basicAck(envelope.getDeliveryTag(),false); } }; /* * 第一个参数:队列的名字 * 第二个参数:是否自动应答 false:表示的是要手动应答 没有应答的话 那么在队列中依然存在 * 第三个参数:消费者的申明 */ channel.basicConsume(QUEUE_NAME,false,defaultConsumer); } }
主题模式(比路由模式要高级一点 设置路由的key的时候只需要设置前缀就可以了)
生产者
public class Sender { //定义一个交换机的名字 private static final String EXCHANGE_NAME=“exchange3”; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtils.getConnection(); Channel channel = connection.createChannel(); //申明的是交换机 /** * 第一个参数:交换机的名字 * 第二个参数:交换机的类型 如果是发布订阅模式的话那么 交换机的类型只能是fanout / channel.exchangeDeclare(EXCHANGE_NAME,“topic”); //生产者发送信息到交换机 /* * 第二个参数:路由的key * 这个key可以进行自己设置 xiaobobo */ for (int i = 0; i <100 ; i++) { channel.basicPublish(EXCHANGE_NAME,“xiaobobo.asasfcsvofhnjwv”,null,(“发布订阅模式下的值”+i).getBytes()); } //关闭资源 channel.close(); connection.close(); } }
消费者1
public class Consumer1 { private static final String QUEUE_NAME=“queue_09”; private static final String EXCHANGE_NAME=“exchange3”; public static void main(String[] args) throws IOException, TimeoutException { //第一步:获取连接 Connection connection = ConnectionUtils.getConnection(); //第二步:创建通道 final Channel channel = connection.createChannel(); //第三步:申明队列 /** * 第一个参数:队列的名字 * 第二个参数:是否持久化 如果rabbitmq从新启动的话 那么 这个数据会丢失 持久化就可以解决这个问题 * 第三个参数:是否排外 * 1:连接关闭之后这个队列是否自动删除 * 2:是否允许其他的通道来进行访问 * 第四个参数:是否自动删除 * 当最后一个连接断开的时候 是否需要自动删除 * 第五个参数:申明队列带的这个参数 * / channel.queueDeclare(QUEUE_NAME,false,false,false,null); //申明交换机 channel.exchangeDeclare(EXCHANGE_NAME,“topic”); //将队列绑定到交换机上 channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"xiaobobo."); //没有确认的话 那么就不用分配任务给我 channel.basicQos(1); //申明了一个消费者 DefaultConsumer defaultConsumer = new DefaultConsumer(channel) { /** * * @param consumerTag:消费者的唯一的标记 * @param envelope:信封 就是将请求的消息封装成一个对象 * @param properties:前面队列带过来的属性的值 * @param body:消息体 * @throws IOException / @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { System.out.println(“11111111111收到消息了:”+new String(body)); //表示的是手动告诉队列我已经收到这个消息了 channel.basicAck(envelope.getDeliveryTag(),false); } }; /* * 第一个参数:队列的名字 * 第二个参数:是否自动应答 false:表示的是要手动应答 没有应答的话 那么在队列中依然存在 * 第三个参数:消费者的申明 */ channel.basicConsume(QUEUE_NAME,false,defaultConsumer); } }
消费者2
public class Consumer2 { private static final String QUEUE_NAME=“queue_10”; private static final String EXCHANGE_NAME=“exchange3”; public static void main(String[] args) throws IOException, TimeoutException { //第一步:获取连接 Connection connection = ConnectionUtils.getConnection(); //第二步:创建通道 final Channel channel = connection.createChannel(); //第三步:申明队列 /** * 第一个参数:队列的名字 * 第二个参数:是否持久化 如果rabbitmq从新启动的话 那么 这个数据会丢失 持久化就可以解决这个问题 * 第三个参数:是否排外 * 1:连接关闭之后这个队列是否自动删除 * 2:是否允许其他的通道来进行访问 * 第四个参数:是否自动删除 * 当最后一个连接断开的时候 是否需要自动删除 * 第五个参数:申明队列带的这个参数 * / channel.queueDeclare(QUEUE_NAME,false,false,false,null); //申明交换机 channel.exchangeDeclare(EXCHANGE_NAME,“topic”); //将队列绑定到交换机上 channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"xiaowangzi."); //没有确认的话 那么就不用分配任务给我 channel.basicQos(1); //申明了一个消费者 DefaultConsumer defaultConsumer = new DefaultConsumer(channel) { /** * * @param consumerTag:消费者的唯一的标记 * @param envelope:信封 就是将请求的消息封装成一个对象 * @param properties:前面队列带过来的属性的值 * @param body:消息体 * @throws IOException / @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { System.out.println(“11111111111收到消息了:”+new String(body)); //表示的是手动告诉队列我已经收到这个消息了 channel.basicAck(envelope.getDeliveryTag(),false); } }; /* * 第一个参数:队列的名字 * 第二个参数:是否自动应答 false:表示的是要手动应答 没有应答的话 那么在队列中依然存在 * 第三个参数:消费者的申明 */ channel.basicConsume(QUEUE_NAME,false,defaultConsumer); } }
列的名字 * 第二个参数:是否自动应答 false:表示的是要手动应答 没有应答的话 那么在队列中依然存在 * 第三个参数:消费者的申明 */ channel.basicConsume(QUEUE_NAME,false,defaultConsumer); } }
p