RabbitMQ学习笔记5-五种模式之三(publish/subscribe、routing、topic)

本文详细介绍了RabbitMQ的五种消息传递模式:发布/订阅(publish/subscribe)、路由(routing)、主题(topic)、头(header)和扇出(fanout)。每种模式都包括模式描述、代码示例(生产者、消费者)和演示效果,帮助读者深入理解RabbitMQ的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

exchange介绍

讲到发布订阅模式,就不能不提一下rabbitmq的exchange路由器。
exchange有4种模式,分别是header、fanout、direct和topic。其中fanout对应的是publish/subscribe模式,direct对应的是routing模式,topic对应的是topic模式

header

header exchange(头交换机)和主题交换机有点相似,但是不同于主题交换机的路由是基于路由键,头交换机的路由值基于消息的header数据。主题交换机路由键只有是字符串,而头交换机可以是整型和哈希值。

fanout

一个生产者,多个消费者,每一个消费者都有自己的一个队列,生产者没有将消息直接发送到队列,而是发送到了交换机,每个队列绑定交换机,生产者发送的消息经过交换机,到达队列,实现一个消息被多个消费者获取的目的。需要注意的是,如果将消息发送到一个没有队列绑定的exchange上面,那么该消息将会丢失,这是因为在rabbitMQ中exchange不具备存储消息的能力,只有队列具备存储消息的能力。
在这里插入图片描述

direct

这种模式添加了一个路由键,生产者发布消息的时候添加路由键,消费者绑定队列到交换机时添加键值,这样就可以接收到需要接收的消息。
在这里插入图片描述

topic

基本思想和路由模式是一样的,只不过路由键支持模糊匹配,符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词。
在这里插入图片描述

publish/subscribe模式

模式

在这里插入图片描述

描述

发布/订阅模式,是通过exchange路由器分发到不同queue队列中,其中queue队列需要订阅exchange。其实发布/订阅是exchang路由的一种类型,type=fanout,这种模式不需要匹配rountingKey,即为发布/订阅模式。特点:每个消费者获取到的消息都是一样的。

代码

生产者

package com.lin.rabbit.ps;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.lin.rabbit.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class PsProvider {
	public static void main(String[] args) throws IOException, TimeoutException {
		//获取连接
		Connection con = ConnectionUtils.getConnection();
		//创建通道
		Channel channel = con.createChannel();
		//声明交换机
		channel.exchangeDeclare(PsConstant.PS_ROUTING_NAME, "fanout");
		//发送信息
		String msg = "hello, this is publish/subscribe model!";
		channel.basicPublish(PsConstant.PS_ROUTING_NAME, "", null, msg.getBytes("UTF-8"));
		System.out.println("send msg:"+msg);
		//关闭通道和连接
		channel.close();
		con.close();
	}
}

消费者1

package com.lin.rabbit.ps;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.lin.rabbit.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties;
public class PsConsumer1 {
	public static void main(String[] args) throws IOException, TimeoutException {
		//获取连接
		Connection con = ConnectionUtils.getConnection();
		//创建通道
		final Channel channel = con.createChannel();
		//声明队列
		channel.queueDeclare(PsConstant.PS_1_QUEUE_NAME, false, false, false, null);
		//队列与路由器绑定
		channel.queueBind(PsConstant.PS_1_QUEUE_NAME,PsConstant.PS_ROUTING_NAME, "");
		//获取消息
		DefaultConsumer defaultConsumer = 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("receiver "+PsConstant.PS_1_QUEUE_NAME+" msg:"+msg);
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally {
					channel.basicAck(envelope.getDeliveryTag(), false);
				}
			}
			
		};
		
		channel.basicConsume(PsConstant.PS_1_QUEUE_NAME, false, defaultConsumer);
	}
}

消费者2

package com.lin.rabbit.ps;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.lin.rabbit.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties;
public class PsConsumer2 {
	public static void main(String[] args) throws IOException, TimeoutException {
		//获取连接
		Connection con = ConnectionUtils.getConnection();
		//创建通道
		final Channel channel = con.createChannel();
		//声明队列
		channel.queueDeclare(PsConstant.PS_2_QUEUE_NAME, false, false, false, null);
		//队列与路由器绑定
		channel.queueBind(PsConstant.PS_2_QUEUE_NAME,PsConstant.PS_ROUTING_NAME, "");
		//获取消息
		DefaultConsumer defaultConsumer = 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("receiver "+PsConstant.PS_2_QUEUE_NAME+" msg:"+msg);
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally {
					channel.basicAck(envelope.getDeliveryTag(), false);
				}
			}
			
		};
		
		channel.basicConsume(PsConstant.PS_2_QUEUE_NAME, false, defaultConsumer);
	}
}

辅助类

package com.lin.rabbit.ps;
public class PsConstant {
	public static String PS_ROUTING_NAME ="ps-routing";
	public static String PS_1_QUEUE_NAME ="ps1-queue";
	public static String PS_2_QUEUE_NAME ="ps2-queue";
}

演示效果

1) 先运行一下生产者产生exchange,启动消费者1和消费者2
2) 启动生产者
在这里插入图片描述
3) 查看消费者1
在这里插入图片描述
4) 查看消费者2
在这里插入图片描述
5) 查看控制台queue
在这里插入图片描述
6) 查看控制台exchange
在这里插入图片描述
在这里插入图片描述

routing模式

模式

在这里插入图片描述

描述

路由模式,是通过exchange路由器分发到不同queue队列中,其中queue队列需要绑定exchange。其是routing路由的一种类型,type=direct,这种模式是通过rountingKey的全匹配来路由,通过rountingKey将不同消息发送到不同queue队列中。特点:每个消费者只能获得rountingKey对应的消息。

代码

生产者

package com.lin.rabbit.routing;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.lin.rabbit.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class RoutingProvider {
	public static void main(String[] args) throws IOException, TimeoutException {
		//获取连接
		Connection con = ConnectionUtils.getConnection();
		//创建通道
		Channel channel = con.createChannel();
		//声明交换机
		channel.exchangeDeclare(RoutingConstant.ROUTING_ROUTING_NAME, "direct");
		//每次一条记录
		channel.basicQos(1);
		//发送信息
		String msgerror = "hello, this is routing model! for error!";
		channel.basicPublish(RoutingConstant.ROUTING_ROUTING_NAME, "error", null, msgerror.getBytes("UTF-8"));
		System.out.println("send msg:"+msgerror);
		
		String msginfo = "hello, this is routing model! for info!";
		channel.basicPublish(RoutingConstant.ROUTING_ROUTING_NAME, "info", null, msginfo.getBytes("UTF-8"));
		System.out.println("send msg:"+msginfo);
		//关闭通道和连接
		channel.close();
		con.close();
	}
}

消费者1

package com.lin.rabbit.routing;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.lin.rabbit.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties;
public class RoutingConsumer1 {
	public static void main(String[] args) throws IOException, TimeoutException {
		//获取连接
		Connection con = ConnectionUtils.getConnection();
		//创建通道
		final Channel channel = con.createChannel();
		//声明队列
		channel.queueDeclare(RoutingConstant.ROUTING_1_QUEUE_NAME, false, false, false, null);
		//每次一条记录
		channel.basicQos(1);
		//队列与路由器绑定
		channel.queueBind(RoutingConstant.ROUTING_1_QUEUE_NAME,RoutingConstant.ROUTING_ROUTING_NAME, "error");
		
		DefaultConsumer defaultConsumer = 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("receiver "+RoutingConstant.ROUTING_1_QUEUE_NAME+" msg:"+msg);
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally {
					channel.basicAck(envelope.getDeliveryTag(), false);
				}
			}
		};
		channel.basicConsume(RoutingConstant.ROUTING_1_QUEUE_NAME, false, defaultConsumer);
	}
}

消费者2

package com.lin.rabbit.routing;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.lin.rabbit.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties;
public class RoutingConsumer2 {
	public static void main(String[] args) throws IOException, TimeoutException {
		//获取连接
		Connection con = ConnectionUtils.getConnection();
		//创建通道
		final Channel channel = con.createChannel();
		//声明队列
		channel.queueDeclare(RoutingConstant.ROUTING_2_QUEUE_NAME, false, false, false, null);
		//每次一条记录
		channel.basicQos(1);
		//队列与路由器绑定
		channel.queueBind(RoutingConstant.ROUTING_2_QUEUE_NAME,RoutingConstant.ROUTING_ROUTING_NAME, "error");
		channel.queueBind(RoutingConstant.ROUTING_2_QUEUE_NAME,RoutingConstant.ROUTING_ROUTING_NAME, "info");
		channel.queueBind(RoutingConstant.ROUTING_2_QUEUE_NAME,RoutingConstant.ROUTING_ROUTING_NAME, "warning");
		
		DefaultConsumer defaultConsumer = 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("receiver "+RoutingConstant.ROUTING_2_QUEUE_NAME+" msg:"+msg);
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally {
					channel.basicAck(envelope.getDeliveryTag(), false);
				}
			}
		};
		channel.basicConsume(RoutingConstant.ROUTING_2_QUEUE_NAME, false, defaultConsumer);
	}
}

辅助类

package com.lin.rabbit.routing;
public class RoutingConstant {
	public static String ROUTING_ROUTING_NAME ="routing-routing";
	public static String ROUTING_1_QUEUE_NAME ="routing1-queue";
	public static String ROUTING_2_QUEUE_NAME ="routing2-queue";
}


演示效果

1) 先运行一下生产者产生exchange,启动消费者1和消费者2
2) 启动生产者
在这里插入图片描述
3) 查看消费者1
在这里插入图片描述
4) 查看消费者2
在这里插入图片描述
5) 查看控制台queue
在这里插入图片描述
6) 查看控制台exchange
在这里插入图片描述
在这里插入图片描述

topic模式

模式

在这里插入图片描述

描述

主题模式,是通过exchange路由器分发到不同queue队列中,其中queue队列需要绑定exchange。其是routing路由的一种类型,type=topic,这种模式是通过rountingKey进行点通配符匹配(注意通配符是在“.”后面起效的,#代表0个或多个,*代表一个)来路由,通过rountingKey将不同消息发送到不同queue队列中。特点:每个消费者只能获得rountingKey对应的消息。

代码

生产者

package com.lin.rabbit.topic;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.lin.rabbit.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class TopicProvider {
	public static void main(String[] args) throws IOException, TimeoutException {
		//获取连接
		Connection con = ConnectionUtils.getConnection();
		//创建通道
		Channel channel = con.createChannel();
		//声明交换机
		channel.exchangeDeclare(TopicConstant.TOPIC_ROUTING_NAME, "topic");
		//每次一条记录
		channel.basicQos(1);
		//发送信息
		String msgadd = "hello, this is topic model! for good.add!";
		channel.basicPublish(TopicConstant.TOPIC_ROUTING_NAME, "good.add", null, msgadd.getBytes("UTF-8"));
		System.out.println("send msg:"+msgadd);
		String msgdelete = "hello, this is topic model! for good.delete!";
		channel.basicPublish(TopicConstant.TOPIC_ROUTING_NAME, "good.delete", null, msgdelete.getBytes("UTF-8"));
		System.out.println("send msg:"+msgdelete);
		//关闭通道和连接
		channel.close();
		con.close();
	}
}

消费者1

package com.lin.rabbit.topic;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.lin.rabbit.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties;
public class TopicConsumer1 {
	public static void main(String[] args) throws IOException, TimeoutException {
		//获取连接
		Connection con = ConnectionUtils.getConnection();
		//创建通道
		final Channel channel = con.createChannel();
		//声明队列
		channel.queueDeclare(TopicConstant.TOPIC_1_QUEUE_NAME, false, false, false, null);
		//每次一条记录
		channel.basicQos(1);
		//队列与路由器绑定
		channel.queueBind(TopicConstant.TOPIC_1_QUEUE_NAME,TopicConstant.TOPIC_ROUTING_NAME, "good.add");
	DefaultConsumer defaultConsumer = 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("receiver "+TopicConstant.TOPIC_1_QUEUE_NAME+" msg:"+msg);
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally {
					channel.basicAck(envelope.getDeliveryTag(), false);
				}
			}
		};
		channel.basicConsume(TopicConstant.TOPIC_1_QUEUE_NAME, false, defaultConsumer);
	}
}

消费者2

package com.lin.rabbit.topic;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.lin.rabbit.utils.ConnectionUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.AMQP.BasicProperties;
public class TopicConsumer2 {
	public static void main(String[] args) throws IOException, TimeoutException {
		//获取连接
		Connection con = ConnectionUtils.getConnection();
		//创建通道
		final Channel channel = con.createChannel();
		//声明队列
		channel.queueDeclare(TopicConstant.TOPIC_2_QUEUE_NAME, false, false, false, null);
		//每次一条记录
		channel.basicQos(1);
		//队列与路由器绑定
		channel.queueBind(TopicConstant.TOPIC_2_QUEUE_NAME,TopicConstant.TOPIC_ROUTING_NAME, "good.#");
		DefaultConsumer defaultConsumer = 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("receiver "+TopicConstant.TOPIC_2_QUEUE_NAME+" msg:"+msg);
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}finally {
					channel.basicAck(envelope.getDeliveryTag(), false);
				}
			}
		};
		channel.basicConsume(TopicConstant.TOPIC_2_QUEUE_NAME, false, defaultConsumer);
	}
}

辅助类

package com.lin.rabbit.topic;
public class TopicConstant {
	public static String TOPIC_ROUTING_NAME ="topic-routing";
	public static String TOPIC_1_QUEUE_NAME ="topic1-queue";
	public static String TOPIC_2_QUEUE_NAME ="topic2-queue";
}

演示效果

1) 先运行一下生产者产生exchange,启动消费者1和消费者2
2) 启动生产者
在这里插入图片描述
3) 查看消费者1
在这里插入图片描述
4) 查看消费者2
在这里插入图片描述
5) 查看控制台queue
在这里插入图片描述
6) 查看控制台exchange
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linmoo1986

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值