RabbitMQ是一款优秀的消息队列中间件,它广泛应用于企业级应用中,可以帮助应用解耦,面对一些业务场景起到一个很强的分流作用等等。为什么挑选RabbitMQ进行学习呢,主要是因为它支持大多数协议,支持AMQP协议,而且官方文档相当全面,今天面向官方文档进行一个基础入门。题主使用的语言是JAVA。
RabbitMQ是基于Erlang语言进行编写的,所以如果想要使用RabbitMQ,首先需要安装Erlang语言的环境。
关于Erlang语言的安装百度有很多也很简单,RabbitMQ也是很容易安装,同时提供了简单的CTL工具供操作。
CTL的官方文档:http://www.rabbitmq.com/man/rabbitmqctl.8.html
今天入门的主题是如何进行消息的发布和消费,在Java中分为几个步骤,其它语言也类似
1.建立连接工厂,生成实例
2.配置host,账号密码等
3.从工厂实例生成Connection连接
4.利用Connection生成信道Channel(RabbitMQ提供信道供客户端与MQ SERVER进行通信,此处是长连接,因为TCP短连接建立销毁的开销太大了)
5.声明队列或者交换器
(第五点根据个人实验,如果是直接声明队列的话,是会生成一条具体队列的,而且会默认选择一个exchange,但是如果声明交换器的话,无需声明队列,RabbitMQ会自动建立队列,而且一个消费者客户端对应的一个queue)
6.开始执行工作(生产者发布消息,消费者消费消息)
关于声明交换器的代码我就不写了,因为在我转载的上一篇来自简书的文章里已经写得很清楚了,这里根据官方文档写一个简单的声明队列的例子
首先需要在Maven环境下引入依赖
com.rabbitmq
amqp-client
4.1.0
生产者例子:
package com.wuweixin;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
public class rabbitmq_persistent_publisher {
public static String persistent_queue = "persistent_queue";
public static void main(String[] args) throws Exception{
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
boolean isPersist = true;
channel.queueDeclare(persistent_queue,isPersist,false,false,null);
int index = 1;
while(index++<1000){
String message = "这是第 "+index+" 条信息";
channel.basicPublish("",persistent_queue, MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes("utf-8"));
System.out.println(message);
}
channel.close();
connection.close();
}
}
消费者例子:
package com.wuweixin;
import com.rabbitmq.client.*;
import java.io.IOException;
public class rabbitmq_persistent_consumer {
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
Connection connection = connectionFactory.newConnection();
final Channel channel = connection.createChannel();
channel.basicQos(1);//告诉MQ SERVER如果未发送确认后,不要继续发送消息给我
channel.queueDeclare(rabbitmq_persistent_publisher.persistent_queue,true,false,false,null);
boolean autoAck = false;//关闭确认消息,由我们自己来控制
final Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String messsage = new String(body,"utf-8");
System.out.println("收到:"+messsage);
try{
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
channel.basicConsume(rabbitmq_persistent_publisher.persistent_queue,autoAck,consumer);
}
}
这样运行起来就可以不断地向队列发布和消费消息了。
这里面有几个点值得注意,就是关于队列持久化和确认问答的要点
1.在生产者端,在声明队列的时候,第二个参数是定义该队列是否是可持久化的,如果选择true的话,那么在发布消息的时候,需要传入的消息属性也必须为可持久化的配置,这两步中,消费者也是一样的配置
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.rabbitmq.client;
import com.rabbitmq.client.AMQP.BasicProperties;
import java.util.Date;
import java.util.Map;
public class MessageProperties {
public static final BasicProperties MINIMAL_BASIC = new BasicProperties((String)null, (String)null, (Map)null, (Integer)null, (Integer)null, (String)null, (String)null, (String)null, (String)null, (Date)null, (String)null, (String)null, (String)null, (String)null);
public static final BasicProperties MINIMAL_PERSISTENT_BASIC = new BasicProperties((String)null, (String)null, (Map)null, Integer.valueOf(2), (Integer)null, (String)null, (String)null, (String)null, (String)null, (Date)null, (String)null, (String)null, (String)null, (String)null);
public static final BasicProperties BASIC = new BasicProperties("application/octet-stream", (String)null, (Map)null, Integer.valueOf(1), Integer.valueOf(0), (String)null, (String)null, (String)null, (String)null, (Date)null, (String)null, (String)null, (String)null, (String)null);
public static final BasicProperties PERSISTENT_BASIC = new BasicProperties("application/octet-stream", (String)null, (Map)null, Integer.valueOf(2), Integer.valueOf(0), (String)null, (String)null, (String)null, (String)null, (Date)null, (String)null, (String)null, (String)null, (String)null);
public static final BasicProperties TEXT_PLAIN = new BasicProperties("text/plain", (String)null, (Map)null, Integer.valueOf(1), Integer.valueOf(0), (String)null, (String)null, (String)null, (String)null, (Date)null, (String)null, (String)null, (String)null, (String)null);
public static final BasicProperties PERSISTENT_TEXT_PLAIN = new BasicProperties("text/plain", (String)null, (Map)null, Integer.valueOf(2), Integer.valueOf(0), (String)null, (String)null, (String)null, (String)null, (Date)null, (String)null, (String)null, (String)null, (String)null);
public MessageProperties() {
}
}
2.关于确认消息
RabbitMQ有一个确认的机制,消费者必须确认消息返回后,MQ SERVER才默认这条消息已经被消费,否则这条消息会被重复消费,同样也是配置一个参数,默认是自动确认的,但最好是我们在编写业务逻辑的时候自己手动确认。
3.还有消费者是否接受消息的一个配置
channel.basicQos(int)
该配置可以设置如果消费者还没返回上一条消息的确认时,是否还接受消息,接受多少条,这样就可以避免RabbitMQ循环发送的平均分配机制可能会压死单一节点
今天的分享就到这里了,谢谢浏览!