一、主题模式—>topic
主题模式与路由模式相似,但是,主题模式是一种模糊的匹配方式。交换机为topic模式,路由key可选 *(匹配明确的一个单词) 或 #(匹配0到多个单词).其路由的*和#类似于数据库中的模糊匹配。设置模糊的绑定方式,“*”操作符将“.”视为分隔符,匹配单个字符;“#”操作符没有分块的概念,它将任意“.”均视为关键字的匹配部分,能够匹配多个字符。 比如路由key为*.s.*只能接收com.s.com这样形式的队列消息,*是指有且只能有一个;#.s.#可以接收com.s.som、s.com、com.s、s、com.com.s.com.com等。
主题模式的生产者代码如下:
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
//所有的中间件技术都是基于tcp/ip协议基础之上构建新的协议规范,只不过rabbitmq遵循的是amqp
//1.创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("ip");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try {
//创建连接Connection
connection = connectionFactory.newConnection("生产者");
//通过连接获取通道Channel
channel = connection.createChannel();
//创建交换机
String exchangeName = "direct_msg_topic";
//设置交换机类型
String exchangeType = "topic";
//声明交换机 参数1:交换机名字 参数2:交换机类型 参数3:交换机是否持久化
channel.exchangeDeclare(exchangeName, exchangeType, true);
//声明队列名字
String queueName1 = "queue4";
String queueName2 = "queue5";
String queueName3 = "queue6";
/*
*创建队列
*参数1: 队列名称 如果队列不存在自动创建
*参数2: 用来定义队列特性是否要持久化 true 持久化队列 false 不持久化(服务重启后队列还保存,但不保存消息)
*参数3: exclusive 是否独占队列 true 独占队列 false 不独占
*参数4: autoDelete: 是否在消费完成后自动删除队列 true 自动删除 false 不自动删除
*参数5: 额外附加参数
*/
channel.queueDeclare(queueName1, true, false, false, null);
channel.queueDeclare(queueName2, true, false, false, null);
channel.queueDeclare(queueName3, true, false, false, null);
//绑定队列和交换机 参数1:队列名字 参数2:交换机名字 参数3:路由key
channel.queueBind(queueName1, exchangeName, "*.s.*");
channel.queueBind(queueName2, exchangeName, "#.s.#");
channel.queueBind(queueName3, exchangeName, "*.s");
Scanner sc = new Scanner(System.in);
//准备消息内容
String message ="hello,s2";
//发送消息给队列queue
channel.basicPublish(exchangeName, "com.s.rabbitmq", null, message.getBytes());
System.out.println("发送成功!");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
//7.关闭连接
// if (channel!=null&&channel.isOpen()){
// channel.close();
// }
// if (connection!=null&& connection.isOpen()){
// connection.close();
// }
//8.关闭通道
}
}
}
路由模式消费者代码如下:
public class Consumer {
public static Runnable runnable = new Runnable() {
@Override
public void run() {
//创建工厂
ConnectionFactory factory = new ConnectionFactory();
//连接
factory.setHost("ip");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("admin");
factory.setPassword("admin");
//获取队列名称
final String queueName = Thread.currentThread().getName();
Connection connection = null;
Channel channel = null;
try {
//获取连接
connection = factory.newConnection("消费者");
//从连接中获取通道
channel = connection.createChannel();
//定义接收消息回调
channel.basicConsume(queueName, true, new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
System.out.println(delivery.getEnvelope().getDeliveryTag());
System.out.println(queueName + ":收到消息:" + new String(delivery.getBody(), "UTF-8"));
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println("接收失败了。。。。");
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
};
public static void main(String[] args) {
new Thread(runnable, "queue4").start();
new Thread(runnable, "queue5").start();
new Thread(runnable, "queue6").start();
}
}
在代码中,用三个不同的路由key去绑定交换机和队列:*.s.* ; #.s.# ; *.s。运行生产者代码后,在图形管理界面会生产一个direct_msg_topic交换机,其类型为topic,并且绑定了不同路由key的队列4、5、6。然后发送一条路由key为com.s.rabbit的消息给队列。发送成功后,根据匹配规则只有队列4、5是可以接收到消息的。在图形管理界面查看,的确如此。启动消费者代码,在消费者中只有队列4、5得到消息。
现在将生产者代码中的发送消息给队列的路由key改为s.rabbit,然后运行生产者代码,可以在图形界面看到只有队列5、6存储了一条信息;运行消费者代码,只有队列5、6接收到信息。
现在将生产者代码中的发送消息给队列的路由key改为s,然后运行生产者代码,可以在图形界面看到只有队列5存储了一条信息;运行消费者代码,只有队列5接收到信息
二、work模式
1、轮询模式
轮询分发就是将消息队列中的消息,依次发送给所有消费者。一个消息只能被一个消费者获取。
生产者代码如下:
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
//所有的中间件技术都是基于tcp/ip协议基础之上构建新的协议规范,只不过rabbitmq遵循的是amqp
//1.创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("ip");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try {
//创建连接Connection
connection = connectionFactory.newConnection("生产者");
//通过连接获取通道Channel
channel = connection.createChannel();
for(int i=1;i<+20;i++){
//准备消息内容
String message =""+i;
//发送消息给队列queue
channel.basicPublish(“queue7”,null,message.getBytes());
}
System.out.println("发送成功!");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
//7.关闭连接
// if (channel!=null&&channel.isOpen()){
// channel.close();
// }
// if (connection!=null&& connection.isOpen()){
// connection.close();
// }
//8.关闭通道
}
}
}
消费者1代码如下:
public class Consumer {
public static void main(String[] args) {
//创建工厂
ConnectionFactory factory = new ConnectionFactory();
//连接
factory.setHost("ip");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("admin");
factory.setPassword("admin");
//获取队列名称
final String queueName = Thread.currentThread().getName();
Connection connection = null;
Channel channel = null;
try {
//获取连接
connection = factory.newConnection("消费者1");
//从连接中获取通道
channel = connection.createChannel();
//定义接收消息回调
channel.basicConsume(queueName, true, new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
System.out.println(delivery.getEnvelope().getDeliveryTag());
System.out.println(new String(delivery.getBody(), "UTF-8"));
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println("接收失败了。。。。");
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
消费者2代码同消费者1的代码。
运行生产者和消费者1、2 的代码后,
消费者1输出:
1 3 5 7 9 11 13 15 17 19
消费者2输出:
2 4 6 8 10 12 14 16 18 20
这就是轮询分发,一人一条。
2、公平分发
消费者设置每次从队列里取出一条数据,并且关闭自动回复机制,每次取出一条数据,手动回复并继续取下一条数据。
生产者代码如下
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
//所有的中间件技术都是基于tcp/ip协议基础之上构建新的协议规范,只不过rabbitmq遵循的是amqp
//1.创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("ip");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try {
//创建连接Connection
connection = connectionFactory.newConnection("生产者");
//通过连接获取通道Channel
channel = connection.createChannel();
for(int i=1;i<+20;i++){
//准备消息内容
String message ="i";
//发送消息给队列queue
channel.basicPublish(“queue7”,null,message.getBytes());
}
System.out.println("发送成功!");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
//7.关闭连接
// if (channel!=null&&channel.isOpen()){
// channel.close();
// }
// if (connection!=null&& connection.isOpen()){
// connection.close();
// }
//8.关闭通道
}
}
}
消费者1、2代码如下
public class Consumer1 {
public static void main(String[] args) {
//创建工厂
ConnectionFactory factory = new ConnectionFactory();
//连接
factory.setHost("ip");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("admin");
factory.setPassword("admin");
//获取队列名称
final String queueName = Thread.currentThread().getName();
Connection connection = null;
Channel channel = null;
try {
//获取连接
connection = factory.newConnection("消费者2");
//从连接中获取通道
channel = connection.createChannel();
//每次只向队列取一条消息
channel.basicQos(1);
//定义接收消息回调
channel.basicConsume(queueName, false, new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
System.out.println(new String(delivery.getBody(), "UTF-8"));
//手动应答
channal.basicACK(delivery.Envelope().getDeliveryTag(), false);
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println("接收失败了。。。。");
}
});
} catch (Exception e) {
}
}
}
}
消费者2代码如下:
public class Consumer2 {
public static void main(String[] args) {
//创建工厂
ConnectionFactory factory = new ConnectionFactory();
//连接
factory.setHost("ip");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("admin");
factory.setPassword("admin");
//获取队列名称
final String queueName = Thread.currentThread().getName();
Connection connection = null;
Channel channel = null;
try {
//获取连接
connection = factory.newConnection("消费者2");
//从连接中获取通道
channel = connection.createChannel();
//每次只向队列取一条消息
channel.basicQos(1);
//定义接收消息回调
channel.basicConsume(queueName, false, new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
System.out.println(new String(delivery.getBody(), "UTF-8"));
//消费者休息2s处理业务
Thread.sleep(2000);
//手动应答
channal.basicACK(delivery.Envelope().getDeliveryTag(), false);
}
}, new CancelCallback() {
@Override
public void handle(String s) throws IOException {
System.out.println("接收失败了。。。。");
}
});
} catch (Exception e) {
}
}
}
}
运行生产者和消费者1、2的代码后
消费者1会输出:
1 2 3 4 6 7 8 9 11 12 13 14 16 17 18 19 20
消费者2 会输出:5 10 15
这就是公平分发,能者多劳