Rabbit Mq学习笔记:rabbit mq的五种常用工作模式
下载安装就不介绍了,可以查看Rabbit Mq官方文档。
一、配置可视化RabbitMQ管理界面
1、运行命令行窗口cmd
输入命令rabbitmq-plugins enable rabbitmq_management
,这样就可以添加可视化插件了。
查看可视化插件是否成功:
2、运行RabbitMQ Service - start
启动服务
在浏览器中输入地址:http://127.0.0.1:15672/
输入默认账号: guest 密码: guest
就可以登录查看rabbitmq里的资源信息。
备注:可以运行 rabbitmqctl stop 命令来停止服务
可以运行 rabbitmq-server -detached命令来重启服务并后台运行。
RabbitMQ的日志信息,可以在 C:/Users/Administrator/AppData/Roaming/RabbitMQ/log/文件夹下进行查看,如:C:/Users/Administrator/AppData/Roaming/RabbitMQ/log/rabbit@mywin-PC.log
二、五种工作模式
工具类:
package com.byz.rabbitmq.rabbitmqdemo.utils;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* rabbit mq 连接工具类
*/
public class ConnectionUtil {
private static String host = "localhost";
private static Integer port = 5672;
private static String username = "guest";
private static String password = "guest";
/**
* 初始化连接
*/
public static Connection getConnection() throws IOException, TimeoutException {
/*
connection抽象了socket连接,控制协议版本和授权等问题。
现在我们是在本地连接中间件,所以host使用localhost就可以了,
如果想连接其他机器上的中间件只需要把host改成对应的host name或者ip地址就可以了
*/
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(host);
factory.setPort(port);
factory.setUsername(username);
factory.setPassword(password);
//创建一个通道channel,其中包含了绝大多数的api。
// 值得注意的是,创建channel的时候我们可以使用try-with-resources语法,
// connection和channel都实现了Closeable接口,我们就不需要在代码中再写close相关的代码了
//建立连接
return factory.newConnection();
}
}
1、简单模式(单生产、单消费)
生产者:
package com.byz.rabbitmq.rabbitmqdemo.service;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* 发送消息,消息生产者
*/
public class SendMessage {
private final static String QUEUE_NAME = "hello";
public static void main(String[] args) {
try {
// 初始化连接
Connection connection = ConnectionUtil .getConnection();
//建立通道
Channel channel = connection.createChannel();
//声明一个queue
/**参数:
* 队列名
* 是否持久化
* 是否排外 即只允许该channel访问该队列 一般等于true的话用于一个队列只能有一个消费者来消费的场景
* 是否自动删除 消费完删除
* 其他属性
*/
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//message
String message = "Hello World! Hello World!";
//发送消息
/**参数:
* 交换机
* 队列名
* 其他属性 路由
* 消息body
*/
channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
System.out.println(" [x] Send '" + message + "'");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
消费者:
package com.byz.rabbitmq.rabbitmqdemo.service;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 接收消息
*/
public class ReceiveMessage {
//队列名称(与生产者队列名称保持一致)
private final static String QUEUE_NAME = "hello";
public static void main(String[] args) {
try {
// 初始化连接
Connection connection = ConnectionUtil .getConnection();
//创建连接
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//接收消息(lambda表达式写法)
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" + message + "'");
};
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
2、工作模式(Work queues)
该模式为简单模式的扩展模式,即在简单模式下新增多个消费者,所有消费者消费的消息完全相同。
3、发布/订阅者模式(Publish/Subscribe)
生产者:
package com.byz.rabbitmq.rabbitmqdemo.service;
import com.byz.rabbitmq.rabbitmqdemo.utils.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
/**
* 发布/订阅者模式
* 工作原理:消息生产者生产消息,发送给交换机,由交换机转发给绑定该交换机的队列
* 消息消费者,监听绑定交换机的消息队列,接收消息,处理并回复
*/
public class SendMessageByPubAndSub {
//定义交换机
private final static String EXCHANGE = "exchange_test";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
//创建连接工厂,并初始化工厂参数
//由工厂初始化一个连接
connection = ConnectionUtil.getConnection();
//初始化一个通道
channel = connection.createChannel();
//声明交换机 发布订阅者模式交换机必须声明为:fanout
channel.exchangeDeclare(EXCHANGE,"fanout");
for (int i = 0; i <10; i++) {
//定义消息内容
String message = "publish/subscribe send message:" + i;
//发送消息
channel.basicPublish(EXCHANGE,"",null,message.getBytes("UTF-8"));
System.out.println("发送消息:" + message);
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
消费者:
package com.byz.rabbitmq.rabbitmqdemo.service;
import com.byz.rabbitmq.rabbitmqdemo.utils.ConnectionUtil;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* 发布/订阅者 接收消息
*/
public class ReceiveMessageByPubAndSub {
//定义交换机
private final static String EXCHANGE = "exchange_test";
//定义队列
private final static String QUEUE = "queue_test_01";
public static void main(String[] args) {
try {
//初始化连接工厂
//创建连接
Connection connection = ConnectionUtil.getConnection();
//获取通道
Channel channel = connection.createChannel();
//声明交换机(分发:发布/订阅模式)
channel.exchangeDeclare(EXCHANGE, "fanout");
//声明队列
channel.queueDeclare(QUEUE, false, false, false, null);
//将队列绑定到交换机
channel.queueBind(QUEUE, EXCHANGE, "");
//设置每次分发个数
channel.basicQos(1);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//接收消息内容
String message = new String(body,"UTF-8");
System.out.println("publish/subsecribe 接收消息内容:" + message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//设置手动应答
System.out.println("消息应答");
//手动应答消息
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
//监听队列并设置手动应答
channel.basicConsume(QUEUE,false,consumer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
4、路由模式(Routing)
生产者:
package com.byz.rabbitmq.rabbitmqdemo.service;
import com.byz.rabbitmq.rabbitmqdemo.utils.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.TimeoutException;
/**
* 路由模式
* 生产者:必须定义交换机和路由,生产消息时必须指定分发到哪个交换机的哪个路由上,交换机模式声明为direct。
* 消费者:必须定义交换机、路由和队列,接收消息时必须指定接收哪个交换机的哪个路由上的消息(即队列绑定交换机并指定路由),否则接收不到消息。
*/
public class SendMessageByDirect {
//定义交换机名称
private final static String DIRECT_EXCHANGE_NAME = "direct_exchange_name";
//定义路由名称,info级别
private final static String ROUTING_NAME_INFO = "routing_name_info";
//定义路由名称,waring级别
private final static String ROUTING_NAME_WARING = "routing_name_waring";
//定义路由名称,error级别
private final static String ROUTING_NAME_ERROR = "routing_name_error";
//定义路由名称,debug级别
private final static String ROUTING_NAME_DEBUG = "routing_name_debug";
public static void main(String[] args) {
try {
//初始化连接
Connection connection = ConnectionUtil.getConnection();
//获取通道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(DIRECT_EXCHANGE_NAME,"direct");
//定义消息
String messageInfo = "this is a info message";
String messageDebug = "this is a debug message";
String messageError = "this is a error message";
String messageWaring = "this is a waring message";
//发送消息
channel.basicPublish(DIRECT_EXCHANGE_NAME,ROUTING_NAME_INFO,null,messageInfo.getBytes(Charset.defaultCharset()));
System.out.println("[info] send message:" + messageInfo);
channel.basicPublish(DIRECT_EXCHANGE_NAME,ROUTING_NAME_DEBUG,null,messageDebug.getBytes(Charset.defaultCharset()));
System.out.println("[debug] send message:" + messageDebug);
channel.basicPublish(DIRECT_EXCHANGE_NAME,ROUTING_NAME_ERROR,null,messageError.getBytes(Charset.defaultCharset()));
System.out.println("[error] send message:" + messageError);
channel.basicPublish(DIRECT_EXCHANGE_NAME,ROUTING_NAME_WARING,null,messageWaring.getBytes(Charset.defaultCharset()));
System.out.println("[waring] send message:" + messageWaring);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
消费者:
package com.byz.rabbitmq.rabbitmqdemo.service;
import com.byz.rabbitmq.rabbitmqdemo.utils.ConnectionUtil;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.TimeoutException;
/**
* 路由模式,消费者1
*/
public class ReceiveMessageByDirect1 {
//定义交换机名称
private final static String DIRECT_EXCHANGE_NAME = "direct_exchange_name";
//定义队列名称
private final static String QUEUE_NAME = "queue_name";
//定义路由名称,info级别
private final static String ROUTING_NAME_INFO = "routing_name_info";
//定义路由名称,waring级别
private final static String ROUTING_NAME_WARING = "routing_name_waring";
//定义路由名称,error级别
private final static String ROUTING_NAME_ERROR = "routing_name_error";
//定义路由名称,debug级别
private final static String ROUTING_NAME_DEBUG = "routing_name_debug";
public static void main(String[] args) {
try {
//初始化连接
Connection connection = ConnectionUtil.getConnection();
//获取通道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(DIRECT_EXCHANGE_NAME,"direct");
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//队列绑定到交换机上
channel.queueBind(QUEUE_NAME,DIRECT_EXCHANGE_NAME,ROUTING_NAME_DEBUG);
// channel.queueBind(QUEUE_NAME,DIRECT_EXCHANGE_NAME,ROUTING_NAME_INFO);
// channel.queueBind(QUEUE_NAME,DIRECT_EXCHANGE_NAME,ROUTING_NAME_WARING);
channel.queueBind(QUEUE_NAME,DIRECT_EXCHANGE_NAME,ROUTING_NAME_ERROR);
//设置只分发一次
channel.basicQos(1);
//定义消费者
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//获取消息内容
String message = new String(body, Charset.defaultCharset());
System.out.println("[receive] message:" + message);
//手动应答
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
//监听队列,设置手动应答
channel.basicConsume(QUEUE_NAME,false,consumer);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
5、主题模式(Topics)
生产者:
package com.byz.rabbitmq.rabbitmqdemo.service;
import com.byz.rabbitmq.rabbitmqdemo.utils.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.TimeoutException;
/**
* topic模式
* 路由键匹配类型有两种:
* 1、# 匹配一个或多个 (常用)
* 2、* 匹配一个
* 生产者:指定交换机类型为topic,发送消息时,指定交换机和路由类型
* 消费者:声明队列,绑定队列到指定交换机并指定路由类型,接收消息时只接收路由类型匹配成功的消息
*
*/
public class SendMessageByTopic {
//定义交换机
private final static String EXCHANGE_TOPIC_NAME = "exchange_topic_name";
//定义路由键
private final static String ROUTING_TOPIC_MESSAGE_KEY_ADD = "key.add";
private final static String ROUTING_TOPIC_MESSAGE_KEY_UPDATE = "key.update";
public static void main(String[] args) {
try {
//初始化连接
Connection connection = ConnectionUtil.getConnection();
//创建连接通道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(EXCHANGE_TOPIC_NAME,"topic");
//发送消息
String message = "this is a topic key.add message";
channel.basicPublish(EXCHANGE_TOPIC_NAME,ROUTING_TOPIC_MESSAGE_KEY_ADD,null,message.getBytes(Charset.defaultCharset()));
System.out.println("[topic] send message:" + message);
String messageEdit = "this is a topic key.update message";
channel.basicPublish(EXCHANGE_TOPIC_NAME,ROUTING_TOPIC_MESSAGE_KEY_UPDATE,null,messageEdit.getBytes(Charset.defaultCharset()));
System.out.println("[topic] send messge:" + messageEdit);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
消费者:
package com.byz.rabbitmq.rabbitmqdemo.service;
import com.byz.rabbitmq.rabbitmqdemo.utils.ConnectionUtil;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.TimeoutException;
/**
* topic模式,消息接收类
*/
public class ReceiveMessageByTopic {
//定义交换机
private final static String EXCHANGE_TOPIC_NAME = "exchange_topic_name";
//定义路由键
private final static String ROUTING_TOPIC_MESSAGE_KEY_ALL = "key.#";
//定义队列名称
private final static String QUEUE_TOPIC_NAME = "queue_topic_name";
public static void main(String[] args) {
try {
//初始化连接
Connection connection = ConnectionUtil.getConnection();
//创建通道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_TOPIC_NAME,false,false,false,null);
//绑定队列到交换机上,指定接收消息的路由键
channel.queueBind(QUEUE_TOPIC_NAME,EXCHANGE_TOPIC_NAME,ROUTING_TOPIC_MESSAGE_KEY_ALL);
//指定每次分发个数
channel.basicQos(1);
//接收消息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//获取消息
String message = new String(body, Charset.defaultCharset());
System.out.println("[topic] receive message:" + message);
//设置手动应答
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
//监控队列
channel.basicConsume(QUEUE_TOPIC_NAME,false,consumer);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}