RabbitMQ五种模式学习笔记

第一种 simple 简单模式
模型如图
在这里插入图片描述
这里的P可以理解成消息的生产者,C理解成消息的接受者(消费者), 中间红色区域为队列。
首先创建获取链接的工具类看代码

package com.rabbitmq.utils;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class ConnectionUtils {
	
	public static Connection getConnection() throws IOException, TimeoutException{
		ConnectionFactory factory = new ConnectionFactory();
		factory.setHost("127.0.0.1");
		factory.setPort(5672);
		factory.setVirtualHost("/v2_test");
		factory.setUsername("guest");
		factory.setPassword("guest");
		return factory.newConnection();
		
	}

}

创建消息发送者 代码如下

package com.rabbitmq.simple;
import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.utils.ConnectionUtils;
public class Sender {
	private static final String QNM = "I`m QNM";
	public static void main(String[] args) throws IOException, TimeoutException {
		//获取连接
		Connection connection = ConnectionUtils.getConnection();
		//创建消息通道
		Channel channel = connection.createChannel();
		/**
		 * queue 队列名称
		 * durable 是否持久化,是的话会将次队列持久化保存到Erlang自带的Mnesia数据库中,RabbitMQ重启后会读取该数据库
		 *    	   (注意,该参数只是持久化队列,并非消息,想要确保消息的可靠性,必须要将消息也进行持久化设置) 
		 * exclusive 是否为排他队列  1:connection关闭时,该队列是否自动删除,2:该队列是否私有
		 *           当设置为true的时候,一个队列只允许一个消费者,一般情况设置为false 
		 * autoDelete 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除,
		 *            可以通过RabbitMQ Management,查看某个队列的消费者数量,当consumers = 0时队列就会自动删除
		 */
		channel.queueDeclare(QNM, false, false, false, null);
		String msg = "Hello World";
		/**
		 * 发送消息
		 * 
		 * exchange 交换机名称
		 * routingKey 路由关键字
		 * props 未做研究,只知道这里可以设置消息持久化  MessageProperties.PERSISTENT_TEXT_PLAIN
		 * body 消息
		 */
		channel.basicPublish("", QNM, null, msg.getBytes());
		channel.close();
		connection.close();
	}

}

创建消息消费者 代码如下

package com.rabbitmq.simple;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.utils.ConnectionUtils;

public class Receiver {
	private static final String QNM = "I`m QNM";
	public static void main(String[] args) throws IOException, TimeoutException {
		Connection connection = ConnectionUtils.getConnection();
		Channel channel = connection.createChannel();
		//创建队列声明 主要为了防止消息接收者先运行此程序,队列还不存在时创建队列
		channel.queueDeclare(QNM, false, false, false, null);
		//定义一个消费者
		DefaultConsumer consumer = 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(msg);
			}
		};
		//自动确认
		boolean autoAck = true;
		channel.basicConsume(QNM, autoAck, consumer);

	}

}

此时先运行消费者,再运行生产者,消费者会收到消息Hello world

第二种 Work queues工作模式
模型如图
在这里插入图片描述
一对多的关系,一个消息生产者对应多个消息消费者,生产者提供的消息其中一部分被C1消费,另一部分被C2消费。
消息分配模式共有两种:
轮询分配:比如共有两个消费者,生产者产生100个消息,一个消费者拿1.3.5.7…99,另一个拿2.4.6…100,每人拿50个。不会考虑每个消费者的处理速度等问题,哪怕C1需要1秒执行完,C2需要10秒执行完
公平分配:谁处理的快,就给谁分配的多。
先看轮询分配 生产者代码如下

package com.rabbitmq.work.avg;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.utils.ConnectionUtils;

public class Sender {
	private static final String QNM = "I`m QNM";
	public static void main(String[] args) throws IOException, TimeoutException {
		Connection connection = ConnectionUtils.getConnection();
		Channel channel = connection.createChannel();
		channel.queueDeclare(QNM, false, false, false, null);
		for (int i = 0; i < 100; i++) {
			String msg = i+"_Hello word";
			channel.basicPublish("", QNM, null, msg.getBytes());
			System.out.println("Sender:"+msg);
		}
		channel.close();
		connection.close();
	}

}

接收者1代码

package com.rabbitmq.work.avg;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.utils.ConnectionUtils;

public class Receiver1 {
	private static final String QNM = "I`m QNM";
	public static void main(String[] args) throws IOException, TimeoutException {
		Connection connection = ConnectionUtils.getConnection();
		Channel channel = connection.createChannel();
		channel.queueDeclare(QNM, false, false, false, null);
		DefaultConsumer consumer = 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(msg);
					//模拟处理耗时
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		};
		boolean autoAck = true;
		channel.basicConsume(QNM, autoAck, consumer);
		
	}

}

接收者2代码

package com.rabbitmq.work.avg;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.utils.ConnectionUtils;

public class Receiver2 {
	private static final String QNM = "I`m QNM";
	public static void main(String[] args) throws IOException, TimeoutException {
		Connection connection = ConnectionUtils.getConnection();
		Channel channel = connection.createChannel();
		channel.queueDeclare(QNM, false, false, false, null);
		DefaultConsumer consumer = 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(msg);
				//模拟处理耗时
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		};
		boolean autoAck = true;
		channel.basicConsume(QNM, autoAck, consumer);
		
	}

}

经测试,接收者1和2分别接处理50条数据,消费者1速度快,2速度慢
再看公平分配:

//一次只收一个
channel.basicQos(1);

公平分配需要关闭自动确认

boolean autoAck = false;
channel.basicConsume(QNM,autoAck,consumer);

代码手动确认

//手动确认消息处理成功
channel.basicAck(envelope.getDeliveryTag(), false);

其中一个接收者整体代码如下

package com.rabbitmq.work.fair;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.utils.ConnectionUtils;

public class Receiver {
	private static final String QNM = "I`m QNM";
	public static void main(String[] args) throws IOException, TimeoutException {
		Connection connection = ConnectionUtils.getConnection();
		Channel channel = connection.createChannel();
		channel.queueDeclare(QNM, false, false, false, null);
		//一次只收一个
		channel.basicQos(1);
		DefaultConsumer consumer = 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(msg);
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				//手动确认消息处理成功
				channel.basicAck(envelope.getDeliveryTag(), false);
			}
		};
		boolean autoAck = false;
		channel.basicConsume(QNM,autoAck,consumer);
		
	}

}

经测试,每个接收者处理的消息数量不同,速度快的处理的多,速度慢的处理的少。减少了整体耗时,提高了效率。

第三种 发布订阅模式
模型如下
在这里插入图片描述
生产者将消息发送到交换机,消费者的队列与该交换机绑定,生产者发送100条消息,两个消费者各接收100条消息
生产者不再将消息发送到队列,而是发送到交换机
不再声明队列,而是声明交换机

//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME, EXCHANGE_TYPE);

交换机类型为fanout,会将消息发送到每个与他绑定的队列上
生产者整体代码如下

package com.rabbitmq.ps;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.utils.ConnectionUtils;

public class Sender {
	private static final String EXCHANGE_NAME = "exchange_fanout";
	private static final String EXCHANGE_TYPE = "fanout";
	public static void main(String[] args) throws IOException, TimeoutException {
		Connection connection = ConnectionUtils.getConnection();
		Channel channel = connection.createChannel();
		//声明交换机
		channel.exchangeDeclare(EXCHANGE_NAME, EXCHANGE_TYPE);
		String msg = "hello ps";
		channel.basicPublish(EXCHANGE_NAME, "", null, msg.getBytes());
		System.out.println("Sender:"+msg);
		channel.close();
		connection.close();
	}

}

消费者1整体代码如下

package com.rabbitmq.ps;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.utils.ConnectionUtils;

public class Receiver {
	private static final String EXCHANGE_NAME = "exchange_fanout";
	private static final String QUEUE_NAME = "exhchange_queue_name";
	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);
		//队列与交换机进行绑定,不存在routingKey
		channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
		channel.basicQos(1);
		DefaultConsumer consumer = 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("Rec:"+msg);
				channel.basicAck(envelope.getDeliveryTag(), false);
			}
		};
		boolean autoAck = false;
		channel.basicConsume(QUEUE_NAME,autoAck,consumer);
	}

}

消费者2与消费者1唯一不同之处就是队列名字,重新起一个队列名。这里就不再贴重复代码了。经测试,两个接受者都收到了生产者发送的消息

第四种 Routing路由模式
模型如下
在这里插入图片描述
路由模式需要将交换机模式改为direct

//第三个参数 true,表示将该交换机持久化
channel.exchangeDeclare(EXCHANGE_ROUT_NAME, "direct",true);

生产者完整代码

package com.rabbitmq.rout;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.MessageProperties;
import com.rabbitmq.utils.ConnectionUtils;

public class Sender {
	private static final String EXCHANGE_ROUT_NAME = "exchange_rout_name";
	public static void main(String[] args) throws IOException, TimeoutException {
		Connection connection = ConnectionUtils.getConnection();
		Channel channel = connection.createChannel();
		//第三个参数 true,表示将该交换机持久化
		channel.exchangeDeclare(EXCHANGE_ROUT_NAME, "direct",true);
		String msg = "";
		String routingKey = "";
		for (int i = 0; i < 50; i++) {
		//模拟不同的routingKey和不同的消息内容
			int flag = i%3;
			if(flag == 0){
				msg = "This is a boy`message";
				routingKey = "boy";
			}else{
				msg = "This is a girl`message";
				routingKey = "girl";
			}
			channel.basicPublish(EXCHANGE_ROUT_NAME, routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes());
		}
		channel.close();
		connection.close();
		
	}

}

消费者1代码

package com.rabbitmq.rout;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.utils.ConnectionUtils;

public class Rexeiver {
	private static final String EXCHANGE_ROUT_NAME = "exchange_rout_name";
	private static final String QUEUE_NAME = "queue1";
	public static void main(String[] args) throws IOException, TimeoutException {
		Connection connection = ConnectionUtils.getConnection();
		Channel channel = connection.createChannel();
		channel.queueDeclare(QUEUE_NAME, true, false, false, null);
		channel.basicQos(1);
		channel.queueBind(QUEUE_NAME, EXCHANGE_ROUT_NAME, "boy", null);
		DefaultConsumer consumer = 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(msg);
				channel.basicAck(envelope.getDeliveryTag(), false);
			}
		};
		boolean autoAck = false;
		channel.basicConsume(QUEUE_NAME,autoAck,consumer);
	}

}

接收者2比接收者1多了

channel.queueBind(QUEUE_NAME, EXCHANGE_ROUT_NAME, "girl", null);

队列名称不同
整体代码如下

package com.rabbitmq.rout;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.utils.ConnectionUtils;

public class Rexeiver2 {
	private static final String EXCHANGE_ROUT_NAME = "exchange_rout_name";
	private static final String QUEUE_NAME = "queue2";
	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);
		channel.queueBind(QUEUE_NAME, EXCHANGE_ROUT_NAME, "boy", null);
		channel.queueBind(QUEUE_NAME, EXCHANGE_ROUT_NAME, "girl", null);
		DefaultConsumer consumer = 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(msg);
				channel.basicAck(envelope.getDeliveryTag(), false);
			}
		};
		boolean autoAck = false;
		channel.basicConsume(QUEUE_NAME,autoAck,consumer);
	}

}

经测试:接收1可以收到routingKey为boy的消息,接收2可以收到routingKey为boy、girl的消息
结果分析:发送者将所有的消息发送到交换机。而接收者1使用queue1与交换机绑定,而queue1只会获取routingKey为boy的消息;同理,接收者2使用queue2与交换机绑定,所以queue2可以收到routingKey为boy和girl的消息。

第五种 topics模式
模型如下
在这里插入图片描述
topics模式和路由模式类似但比路由和发布订阅模式强大,引入routingKey通配符
生产者代码如下

package com.rabbitmq.topic;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.utils.ConnectionUtils;

public class Sender {
	private static final String EXCHANGE_NAME = "topic exchange";
	public static void main(String[] args) throws IOException, TimeoutException {
		Connection connection = ConnectionUtils.getConnection();
		Channel channel = connection.createChannel();
		//这里声明模式为topic
		channel.exchangeDeclare(EXCHANGE_NAME, "topic");
		String msg = "";
		String routingKey = "";
		for (int i = 0; i <50; i++) {
			int flag = i%4;	
			if(flag == 0){
				 routingKey = "user.add";
				 msg = "User Message.add";
			}else if(flag == 1){
				 routingKey = "user.delete";
				 msg = "User Message.delete";
			}else if(flag == 2){
				 routingKey = "user.update";
				 msg = "User Message.update";
			}else{
				 routingKey = "user.select";
				 msg = "User Message.select";
			}
			channel.basicPublish(EXCHANGE_NAME,routingKey, null, msg.getBytes());
		}
		channel.close();
		connection.close();
		
		
	}

}

接收者1代码如下

package com.rabbitmq.topic;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.utils.ConnectionUtils;

public class Receiver1 {
	private static final String EXCHANGE_NAME = "topic exchange";
	private static final String QUEUE_NAME = "topic queue1";
	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 routingKey = "user.#";
		channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, routingKey );
		channel.basicQos(1);
		DefaultConsumer consumer = 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("Rec1:"+msg);
				channel.basicAck(envelope.getDeliveryTag(), false);
			}
		};
		boolean autoAck = false;
		channel.basicConsume(QUEUE_NAME, autoAck, consumer);
	}

}

接收者2代码如下

package com.rabbitmq.topic;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.utils.ConnectionUtils;

public class Receiver2 {
	private static final String EXCHANGE_NAME = "topic exchange";
	private static final String QUEUE_NAME = "topic queue2";
	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 routingKey = "user.add";
		channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, routingKey );
		channel.basicQos(1);
		DefaultConsumer consumer = 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("Rec2:"+msg);
				channel.basicAck(envelope.getDeliveryTag(), false);
			}
		};
		boolean autoAck = false;
		channel.basicConsume(QUEUE_NAME, autoAck, consumer);
	}

}

其中不同之处为
接收者1

String routingKey = "user.#";

接收者2

String routingKey = "user.add";

经测试 接收1可以收到所有以user.开头的routingKey的所有消息,接收者2只可以收到routingKey为user.add的消息。

刚开始学习,知识细节不是很详细,如有问题欢迎大家及时指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值