public class SimpleProducer {
public static void main(String[] args) throws IOException {
Connection connection = MQUtils.getConnection();
//创建通道
Channel channel = connection.createChannel();
//定义队列
channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);
String msg = “Hello World!”;
//发布消息到队列
channel.basicPublish(“”,MQUtils.QUEUE_NAME,null,msg.getBytes());
channel.close();
connection.close();
}
}
运行生产者代码,管理页面点进myqueue01,在GetMessages中可以看到消息
消费者
/**
- 消费者,从队列中读取简单的消息
*/
public class SimpleConsumer {
public static void main(String[] args) throws IOException, InterruptedException {
Connection connection = MQUtils.getConnection();
Channel channel = connection.createChannel();
//定义队列
channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);
//创建消费者
QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
//消费者消费通道中的消息
channel.basicConsume(MQUtils.QUEUE_NAME,true,queueingConsumer);
//读取消息
while(true){
QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
System.out.println(new String(delivery.getBody()));
}
}
}
运行读取消息
==================================================================
工作队列,生产者将消息分发给多个消费者,如果生产者生产了100条消息,消费者1消费50条,消费者2消费50条。
生产者
/**
多对多模式的生产者,会发送多条消息到队列中
*/
public class WorkProductor {
public static void main(String[] args) throws IOException, InterruptedException {
Connection connection = MQUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);
for(int i = 0;i < 100;i++){
String msg = “Hello–>” + i;
channel.basicPublish(“”,MQUtils.QUEUE_NAME,null, msg.getBytes());
System.out.println(“send:” + msg);
Thread.sleep(10);
}
channel.close();
connection.close();
}
}
消费者1
/**
- 多对多模式的消费者1
*/
public class WorkConsumer01 {
public static void main(String[] args) throws IOException, InterruptedException {
Connection connection = MQUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);
QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
//消费者消费通道中的消息
channel.basicConsume(MQUtils.QUEUE_NAME,true,queueingConsumer);
while(true){
QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
System.out.println(“WorkConsumer1 receive :” + new String(delivery.getBody()));
Thread.sleep(10);
}
}
}
消费者2
/**
- 多对多模式的消费者2
*/
public class WorkConsumer02 {
public static void main(String[] args) throws IOException, InterruptedException {
Connection connection = MQUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);
QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
//消费者消费通道中的消息
channel.basicConsume(MQUtils.QUEUE_NAME,true,queueingConsumer);
while(true){
QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
System.out.println(“WorkConsumer2 receive :” + new String(delivery.getBody()));
Thread.sleep(1000);
}
}
}
生产者发送100个消息,两个消费者分别读取了50条。
看消息内容,发现队列发送消息采用的是轮询方式,也就是先发给消费者1,再发给消费者2,依次往复。
上面案例中有一个问题:消费者处理消息的速度是不一样的,消费者1处理后睡眠10毫秒(Thread.sleep(10)),消费者2是1000毫秒,速度相差100倍,但是最后处理的消息数还是一样的。这样就存在效率问题:处理能力强的消费者得不到更多的消息。
因为队列默认采用是自动确认机制,消息发过去后就自动确认,队列不清楚每个消息具体什么时间处理完,所以平均分配消息数量。
实现能者多劳:
-
channel.basicQos(1);限制队列一次发一个消息给消费者,等消费者有了反馈,再发下一条
-
channel.basicAck 消费完消息后手动反馈,处理快的消费者就能处理更多消息
-
basicConsume 中的参数改为false
修改消费者1和2
/**
- 多对多模式的消费者1
*/
public class WorkConsumer1 {
public static void main(String[] args) throws IOException, InterruptedException {
Connection connection = MQUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);
//同一时刻服务器只发送一条消息给消费者
channel.basicQos(1);
QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
//true是自动返回完成状态,false表示手动
channel.basicConsume(MQUtils.QUEUE_NAME,false,queueingConsumer);
while(true){
QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
System.out.println(“WorkConsumer1 receive :” + new String(delivery.getBody()));
Thread.sleep(10);
//手动确定返回状态,不写就是自动确认
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
}
}
}
/**
- 多对多模式的消费者2
*/
public class WorkConsumer2 {
public static void main(String[] args) throws IOException, InterruptedException {
Connection connection = MQUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);
//同一时刻服务器只发送一条消息给消费者
channel.basicQos(1);
QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
//true是自动返回完成状态,false表示手动
channel.basicConsume(MQUtils.QUEUE_NAME,false,queueingConsumer);
while(true){
QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
System.out.println(“WorkConsumer2 receive :” + new String(delivery.getBody()));
Thread.sleep(1000);
//手动确定返回状态,不写就是自动确认
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
}
}
}
再次执行消费者2只消费了5条,消费者消费95条消息
===================================================================
发布/订阅模式和Work模式的区别是:Work模式只存在一个队列,多个消费者共同消费一个队列中的消息;而发布订阅模式存在多个队列,不同的消费者可以从各自的队列中处理完全相同的消息。
实现步骤:
-
创建交换机(Exchange)类型是fanout
-
交换机需要绑定不同的队列
-
不同的消费者从不同的队列中获得消息
-
生产者发送消息到交换机
-
再由交换机将消息分发到多个队列
新建队列
新建交换机
点击交换机,在bindings里面绑定两个队列
生产者
/**
- 发布和订阅模式的生产者,消息会通过交换机发到队列
*/
public class PublishProductor {
public static void main(String[] args) throws IOException {
Connection connection = MQUtils.getConnection();
Channel channel = connection.createChannel();
//声明fanout exchange
channel.exchangeDeclare(MQUtils.EXCHANGE_NAME,“fanout”);
String msg = “Hello Fanout”;
//发布消息到交换机
channel.basicPublish(MQUtils.EXCHANGE_NAME,“”,null,msg.getBytes());
System.out.println(“send:” + msg);
channel.close();
connection.close();
}
}
消费者1
/**
-
发布订阅模式的消费者1
-
两个消费者绑定的消息队列不同
-
通过交换机一个消息能被不同队列的两个消费者同时获取
-
一个队列可以有多个消费者,队列中的消息只能被一个消费者获取
*/
public class SubscribeConsumer1 {
public static void main(String[] args) throws IOException, InterruptedException {
Connection connection = MQUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(MQUtils.QUEUE_NAME,false,false,false,null);
//绑定队列到交换机
channel.queueBind(MQUtils.QUEUE_NAME,MQUtils.EXCHANGE_NAME,“”);
QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
channel.basicConsume(MQUtils.QUEUE_NAME,true,queueingConsumer);
while(true){
QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery();
System.out.println(“Consumer1 receive :” + new String(delivery.getBody()));
}
}
}
消费者2
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V:vip1024b 备注Java获取(资料价值较高,非无偿)
最后
文章中涉及到的知识点我都已经整理成了资料,录制了视频供大家下载学习,诚意满满,希望可以帮助在这个行业发展的朋友,在论坛博客等地方少花些时间找资料,把有限的时间,真正花在学习上,所以我把这些资料,分享出来。相信对于已经工作和遇到技术瓶颈的朋友们,在这份资料中一定都有你需要的内容。
576334161)]
[外链图片转存中…(img-wMofNL1J-1711576334162)]
[外链图片转存中…(img-EWbo58UO-1711576334162)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
[外链图片转存中…(img-FhtpOMwq-1711576334163)]
[外链图片转存中…(img-DL3Nvoj2-1711576334163)]
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V:vip1024b 备注Java获取(资料价值较高,非无偿)
[外链图片转存中…(img-X0pSFr6N-1711576334164)]
最后
文章中涉及到的知识点我都已经整理成了资料,录制了视频供大家下载学习,诚意满满,希望可以帮助在这个行业发展的朋友,在论坛博客等地方少花些时间找资料,把有限的时间,真正花在学习上,所以我把这些资料,分享出来。相信对于已经工作和遇到技术瓶颈的朋友们,在这份资料中一定都有你需要的内容。