rabbitMQ模型
初识RabbitMQ:
rabbitMQ是一个开源的消息代理和队列服务器,通过AMQP协议来完成不同应用之间的数据共享。
rabbitMQ是通过elang语言来开发。
什么是AMQP协议
(Advanced message queue protocol)高级消息队列
1)是一个二进制协议
2)AMQP是一个应用层协议的规范,可以有很多不同的消息中间件产品(中间件都需要遵循改规范)
server:是消息队列节点
virtual host:虚拟主机
exchange:交换机(消息投递到交换机上)
message queue:消息队列(被消费者监听消费)
交换机和消息队列有一个绑定关系
AMQP的核心概念
1.server:又称broker,接收客户端连接,实现AMQP实体服务
2.Connection:连接,应用程序与server/broker建立网络连接
3.channel:网络通道,几乎所有的操作都是在channel中进行的,是进行消息对象的通道,客户端可以建立多个channel,每一个channel表示一个会话任务
4.message:服务器与应用程序之间传递数据的载体,有properties(消息属性,用来修饰消息,比如消息的优先级,延时投递等)和Body(消息体)
5.virtual host:虚拟主机
6.exchange:交换机,消息直接投递到交换机上,然后交换机根据消息的路由key来路由到对应绑定的队列上
7.queue:队列,用来保存消息的载体,有消费者监听,然后消费消息
8.bingding:绑定exchange和queue的虚拟连接,bingding中可以包含route_key
9.route_key:路由key,他的作用是在交换机上通过route_key来把消息路由到哪个队列上
RabbitMQ安装教程
https://segmentfault.com/a/1190000018916099?utm_source=tag-newest
简单使用RabbitMQ
生产者:
public class RabbitMQProducter {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置连接工厂属性
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("test-virtual");
connectionFactory.setUsername("yihao");
connectionFactory.setPassword("yihao");
//3.通过连接工厂创建连接对象
Connection connection = connectionFactory.newConnection();
//4.通过连接创建channel
Channel channel = connection.createChannel();
//通过channel发送消息
for (int i=0;i<10;i++){
String message = "hello yihao------"+i;
//void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;
/**
* exchange:交换机名称(这里我没有指定交换机,那我们的消息会发送到默认的交换机上)
* routingKey:路由key
* props:消息属性
* body:消息体
*/
channel.basicPublish("","yihao-queue",null,message.getBytes());
}
channel.close();
connection.close();
}
}
消费者
public class RabbitMQConsumer {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置连接工厂属性
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("test-virtual");
connectionFactory.setUsername("yihao");
connectionFactory.setPassword("yihao");
//3.通过连接工厂创建连接对象
Connection connection = connectionFactory.newConnection();
//4.通过连接创建channel
Channel channel = connection.createChannel();
//声明队列
String queueName ="yihao-queue";
/**
*queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
*Map<String, Object> arguments) throws IOException;
* queue:队列名称
* durable:是否持久化,队列的声明默认是保存在内存中的,如果rabbitMQ重启会丢失,如果想重启之后还存在则开启持久化
* exclusive:当连接关闭时,该队列是否会自动删除
* autoDelete:是否自动删除,如最后一个消费者断开连接之后队列是否自动被删除
* arguments:队列的其他属性,是map
*/
channel.queueDeclare(queueName,true,false,true,null);
//将消费者与channel绑定
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
StringBuilder sb = new StringBuilder();
for (byte b : body) {
sb.append((char) b);
}
System.out.println(sb.toString());
//channel.basicAck(envelope.getDeliveryTag(), false);//这个可以确认是否处理消息
}
});
}
}
效果展示
交换机属性详解
1.作用:接受生产者的消息,然后根据路由键,把消息投递到跟交换机绑定的对应的队列上
2.交换机的属性:
name:交换机的名称
Type:交换机的类型(direct,topic,fanout,hreaders)
Durability:是否需要持久化
autoDelete:假如没有队列绑定到该交换机,那么该交换机是否自动删除
Internal:不常用,默认为false
argurements:扩展参数,用户扩展AMQP定制化协议
3.交换机的类型
3.1直接交换机
所有发送到direct exchange的消息都被被投递到与routekey名称相同的queue上。
在 direct模式下,可以使用自带的默认的exchange,即default exchange,所以不需要交换机和任何队列绑定,消息将会投递到route_key名称和队列相同的队列上。
**代码演示:
直连交换机生产者 DirectExchangeProducter**
public class DirectExchangeProducter {
public static void main(String[] args) throws IOException, TimeoutException {
//创建连接
Connection connection = MyConnectionFactory.getConnection();
//创建channel
Channel channel = connection.createChannel();
//定义交换机名称
String exchangeName="yihao.directExchange";
//定义路由key
String routingKey="yihao.directExchange.key";
//消息定义
String messageBody="hello yihao";
channel.basicPublish(exchangeName,routingKey,null,messageBody.getBytes());
channel.close();
connection.close();
}
}
直连交换机消费者DirectExchangeConsumer
public class DirectExchangeConsumer {
public static void main(String[] args) throws IOException {
//创建连接
Connection connection = MyConnectionFactory.getConnection();
//创建通道
Channel channel = connection.createChannel();
//定义交换机名称
String exchangeName="yihao.directExchange";
//交换机类型
String exchangeType="direct";
//队列名称
String queueName="yihao.directQueue";
//定义路由key
String routingKey="yihao.directExchange.key";
//声明一个交换机
channel.exchangeDeclare(exchangeName,exchangeType,true,false,null);
//声明一个队列
channel.queueDeclare(queueName,true,false,false,null);
//交换机和队列绑定(根据队列名称和交换机名称,通过路由key绑定)
channel.queueBind(queueName,exchangeName,routingKey);
//将消费者与channel绑定
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
StringBuilder sb = new StringBuilder();
for (byte b : body) {
sb.append((char) b);
}
System.out.println(sb.toString());
//channel.basicAck(envelope.getDeliveryTag(), false);//这个可以确认是否处理消息
}
});
}
}
3.2主题交换机topic exchange
就是在队列上设置绑定到topic交换机上的路由key,可以通过通配符来匹配。规则是:
比如:log.#:可以匹配一个单词,也可以匹配多个单词,比如可以匹配到log.a,log.b,log.a.b;
log.*:可以匹配一个单词,比如log.a,log.b,但是不能匹配log.a.b
代码示例:
主题交换机生产者TopicExchangeProducter:
public class TopicExchangeProducter {
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = MyConnectionFactory.getConnection();
Channel channel = connection.createChannel();
String topicExchangeName="topic.exchange";
String routingKey1="topic.key.1";
String routingKey2="topic.key.2";
channel.basicPublish(topicExchangeName,routingKey1,null,"topic测试交换机1".getBytes());
channel.basicPublish(topicExchangeName,routingKey2,null,"topic测试交换机2".getBytes());
channel.close();
connection.close();
}
}
主题交换机消费者TopicExchangeConsumer
public class TopicExchangeConsumer {
public static void main(String[] args) throws IOException {
Connection connection = MyConnectionFactory.getConnection();
Channel channel = connection.createChannel();
String topicExchangeName="topic.exchange";
String queueName="topic.queue";
String exchangeType="topic";
String routingKey="topic.#";
//声明交换机
channel.exchangeDeclare(topicExchangeName,exchangeType,true,true,false,null);
//声明一个队列
channel.queueDeclare(queueName,true,false,true,null);
//队列绑定到交换机
channel.queueBind(queueName,topicExchangeName,routingKey);
//将消费者与channel绑定
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
StringBuilder sb = new StringBuilder();
for (byte b : body) {
sb.append((char) b);
}
System.out.println(sb.toString());
//channel.basicAck(envelope.getDeliveryTag(), false);//这个可以确认是否处理消息
}
});
}
}
3.3扇形交换机 fanout exchange
就是消息通过从交换机到队列上不会通过路由key,所以该模式是最快的,只要和交换机绑定的,那么消息就会分发到与之绑定的队列上
代码演示
扇形交换机消息生产者FanoutExchangeProducter
public class FanoutExchangeProducter {
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = MyConnectionFactory.getConnection();
Channel channel = connection.createChannel();
String fanoutExchangeName="fanout.exchange";
String routingKey="fanout.key";
channel.basicPublish(fanoutExchangeName,routingKey,null,"fanout测试扇形交换机".getBytes());
channel.close();
connection.close();
}
}
扇形交换机消息消费者FanoutExchangeConsumer
public class FanoutExchangeConsumer {
public static void main(String[] args) throws IOException {
Connection connection = MyConnectionFactory.getConnection();
Channel channel = connection.createChannel();
String fanoutExchangeName="fanout.exchange";
String exchangeType="fanout";
String queueName ="";
//这里的routingKey是什么都无所谓,不会起作用到
String routingKey="";
channel.exchangeDeclare(fanoutExchangeName,exchangeType,true,true,false,null);
channel.queueDeclare(queueName,true,false,true,null);
channel.queueBind(queueName,fanoutExchangeName,routingKey);
//将消费者与channel绑定
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
StringBuilder sb = new StringBuilder();
for (byte b : body) {
sb.append((char) b);
}
System.out.println(sb.toString());
//channel.basicAck(envelope.getDeliveryTag(), false);//这个可以确认是否处理消息
}
});
}
}