最近在学习RabbitMQ相关的知识,主要是通过一些demo进行理解和掌握,具体的原理机制什么的,理解起来比较困难,所以看得也不多,下面是我的一些学习感悟及demo实例。
接下来关于RabbitMQ的一些学习都是基于以为大神的博客。
在学完大神的博客之后,我对RabbitMQ有了很深入的理解,但是,我发现我所谓的理解脱离了最基础的概念,所以刚学完的时候又恍然大悟,又半知半解,后来跟同事讨论了一下,原来是搞混了生产者、队列、消费者的基础关系。我建议学习的时候要牢记这三者的关系。下面这张图可以很好地帮助理解记忆:
生产者生成消息到队列里面,消费者到队列里面消费消息,生产者消费者并无直接关系。
在学习之前要先自己下载安装一下RabbitMQ。可以去搜一下如何安装下载。
整个rabbitmq的学习,我想通过交换器Exchange的类型来作为线索进行讲解,这也是我理解这个知识的一种方法。
Exchange有四种类型:fanout、direct、topic、header(用的很少,不作讲解)
fanout:这种类型是一种很典型的发布/订阅模式,生产者发布到的Exchange所知道的所有的队列中,然后被与相应队列绑定的消费者所订阅处理。
direct:发布消息的时候会指定一个routingkey,生产者的routingkey和队列的routingkey是对应的,进行一对一的直接生产消费。
topic:主题类型,相比较direct灵活,提供与*的匹配模式,他的功能很强大可以实现其余两种类型的转发器。当一个队列与绑定键#绑定时相当于fanout,当绑定键不包含#与*时相当于direct。
刚刚开始学习一个简单的demo的时候,我们默认的交换器是“”,不指定交换器,通过队列名称来生产与消费消息(这个不明白可以看下面的demo)。
生产者:
package mq.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @description rabbitmq 生产者demo
* @author: gaobh
* @date: 2018/4/23 17:52
* @version: v1.0
*/
public class MqProviderDemo {
/**
* 队列名称
*/
private final static String QUEUE_NAME = "queueDemo2";
public static void main(String[] args) throws IOException, TimeoutException {
//创建链接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//默认链接的主机名,RabbitMQ-Server安装在本机
connectionFactory.setHost("127.0.0.1");
//创建连接
Connection conn = connectionFactory.newConnection();
//创建信息管道
Channel channel = conn.createChannel();
//进行信息声明1.队列名2.是否持久化3.是否局限与链接4.不再使用是否删除5.其他的属性
//设置队列持久化,当rabbitmq服务停止时,队列也存在
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
String msg = "Hello World!";
//在RabbitMQ中,消息是不能直接发送到队列,他需要发送到交换器(exchange)中
// 第一参数空表示使用默认的exchange,
// 第三个参数设置消息持久化(即服务断开后再重启数据任然存在)
// 第四参数是发送的消息(字节数组)
channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes());
System.out.println("发送 message[" + msg + "] to " + QUEUE_NAME + " success!");
//关闭通道和连接
channel.close();
conn.close();
}
}
消费者:
package mq.simple;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @description rabbitmq 消费消息demo
* @author: gaobh
* @date: 2018/4/24 9:20
* @version: v1.0
*/
public class MqConsumerDemo {
/**
* 队列名称
*/
private final static String QUEUE_NAME = "queueDemo2";
public static void main(String[] args) throws IOException, TimeoutException {
//创建连接工厂、创建连接、创建通道与发送端一样
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
Connection conn = connectionFactory.newConnection();
Channel channel = conn.createChannel();
//此处再次声明队列是为了防止消费者先运行此程序,队列不存在时创建队列
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
//声明一个消费者,配置好获取消息的方式(DefaultConsumer替代了3.X版本的QueueingConsumer)
Consumer 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("ReceiveLogsDirect1 Received '" + envelope.getRoutingKey() + "':'" + message + "'");
}
};
//接收
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
demo里面要注意一下我的注释有重要信息:
1、队列与队列中信息的持久化该如何配置;
2、rabbitmq 5.2版本的消费者该如何声明,网上很多例子都是很久之前的还停留在3.x版本的QueueingConsumer声明方式,在新版本中已经不支持了。