RabbitMq 七大发布消息之helloword最简单的发布和消费消息
一、概述
这篇文章我们讲解rabbitmq的Publish/Subscribe 发布/订阅模式,也称为fanout 广播模式,在项目中经常会用到。
通过官方模型可以看出来较之前两种模式,广播模式多了一个交换机的场景。
由图可知,生产者不再直接绑定队列了,而改为生产者绑定交换机,再由交换机绑定队列,而不同的消费者从不同的队列中获取消息,但此时的队列是属于临时队列的,即一旦队列中的消息被消费完全就会自动删除释放内存。
里面type类型为fanout的就是广播模式的交换机。
二、广播模式的消息发送流程
1.生产者生产消息,且只需要将消息发送给交换机,由交换机决定需要将消息发送给哪个队列,此处的队列是临时创建,用完即删。
2.交换机把消息发送给绑定的所有队列。
3.可以拥有多个消费者,每个消费者都有一个临时队列,每个队列都绑定到一个交换机上。
4.最终每个消费者都能从自己的队列中获取到消息,实现一条消息同时被多个消费者消费。
三、生产者、消费者代码
工具类:
package utils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Author:
* @Despriction:
* @Package: utils
* @Date:Created in 2020/3/23 8:44
* @Modify By:
*/
public class RabbitMqUtil {
private static ConnectionFactory connectionFactory;
static {
//第一步:创建rabbitmq的连接工厂
connectionFactory = new ConnectionFactory();
//第二步:设置连接的rabbitmq服务器的连接ip
connectionFactory.setHost("192.168.4.6");
//第三步:连接端口号,默认的为5672
connectionFactory.setPort(5672);
//第四步:设置连接哪个虚拟主机
connectionFactory.setVirtualHost("/ems");
//第五步:设置连接虚拟主机的用户和密码
connectionFactory.setUsername("ems");
connectionFactory.setPassword("123");
}
//获取rabbitmq的连接
public static Connection getConnection() {
//第六步:获取连接对象
Connection connection = null;
try {
connection = connectionFactory.newConnection();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
return connection;
}
public static void getClose(Connection connection, Channel channel) {
try {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
生产者:
package fanout;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.MessageProperties;
import org.junit.Test;
import utils.RabbitMqUtil;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Author:
* @Despriction: Publish/Subscribe 订阅发布 生产消费模式
* @Package: helloword
* @Date:Created in 2020/3/19 11:14
* @Modify By:
*/
public class Provider {
@Test
public void sendMsg() throws IOException, TimeoutException {
//通过公用方法获取rabbit连接
Connection connection = RabbitMqUtil.getConnection();
//第七步:创建连接通道
Channel channel = connection.createChannel();
//第八步:通道指定交换机 若不存在则会自动创建
/**
* 参数1:交换机名称
* 参数2:交换机type 类型,此处指定为fanout 广播模式
*/
channel.exchangeDeclare("logs","fanout");
//发送消息
/**
* 参数1:交换机名称
* 参数2:路由名称,广播模式暂时用不到路由
* 参数3:持久化参数
* 参数4:需要发送的消息内容
*/
channel.basicPublish("logs","",null,"Publish/Subscribe fanout消息发布模式".getBytes());
RabbitMqUtil.getClose(connection, channel);
}
}
消费者1:
package fanout;
import com.rabbitmq.client.*;
import utils.RabbitMqUtil;
import java.io.IOException;
/**
* @Author:
* @Despriction:
* @Package: fanout
* @Date:Created in 2020/3/24 14:44
* @Modify By:
*/
public class Consumer1 {
public static void main(String args[]) throws IOException {
//通过公用方法获取rabbit连接
Connection connection = RabbitMqUtil.getConnection();
//创建连接通道
Channel channel = connection.createChannel();
//指定交换机
/**
* 参数1:交换机名称
* 参数2:交换机type 类型,此处指定为fanout 广播模式
*/
channel.exchangeDeclare("logs","fanout");
//创建一个临时队列,queueName就表示这个队列的名称
String queueName = channel.queueDeclare().getQueue();
//将交换机和临时队列进行绑定
/**
* 参数1:临时队列的名称
* 参数2:交换机的名称
* 参数3:路由的key,此处暂时用不到
*/
channel.queueBind(queueName,"logs","");
//消费
//消费消息
/**
* 参数1:队列名称,即将要消费哪一个队列的消息
* 参数2:开启消息的自动确认机制
* 参数3:消费时的回调接口,常用来处理业务逻辑,一般都是Consumer接口的实现类,此处用默认的DefaultConsumer
*/
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者-1:" + new String(body));
}
});
}
}
消费者2:
package fanout;
import com.rabbitmq.client.*;
import utils.RabbitMqUtil;
import java.io.IOException;
/**
* @Author:
* @Despriction:
* @Package: fanout
* @Date:Created in 2020/3/24 15:30
* @Modify By:
*/
public class Consumer2 {
public static void main(String args[]) throws IOException {
//通过公用方法获取rabbit连接
Connection connection = RabbitMqUtil.getConnection();
//创建连接通道
Channel channel = connection.createChannel();
//指定交换机
/**
* 参数1:交换机名称
* 参数2:交换机type 类型,此处指定为fanout 广播模式
*/
channel.exchangeDeclare("logs","fanout");
//创建一个临时队列,queueName就表示这个队列的名称
String queueName = channel.queueDeclare().getQueue();
//将交换机和临时队列进行绑定
/**
* 参数1:临时队列的名称
* 参数2:交换机的名称
* 参数3:路由的key,此处暂时用不到
*/
channel.queueBind(queueName,"logs","");
//消费
//消费消息
/**
* 参数1:队列名称,即将要消费哪一个队列的消息
* 参数2:开启消息的自动确认机制
* 参数3:消费时的回调接口,常用来处理业务逻辑,一般都是Consumer接口的实现类,此处用默认的DefaultConsumer
*/
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者-2:" + new String(body));
}
});
}
}
执行完生产者,登录rabbit管理界面可以看到如下图所示
执行完消费者可以看到rabbit界面的队列:新建了两个临时队列,其中AD就表示 autodelete (自动删除),Excl表示 exclusive (独占的)
控制台打印:
最终实现同一条消息被两个消费者消费掉了。