采用高效可靠的传输机制来实现分布式系统中数据交互的一种组件。
作用:解耦、流量消峰、异步处理。
RabitMQ是采用Erlang语言写的消息中间件。
安装erlang:http://www.erlang.org/downloads 双击.exe文件进行安装就好,安装完成之后创建一个名为ERLANG_HOME的环境变量,其值指向erlang的安装目录,同时将%ERLANG_HOME%\bin加入到Path中,最后打开命令行,输入erl,如果出现erlang的版本信息就表示erlang语言环境安装成功。
RabbitMQ,下载地址:http://www.rabbitmq.com/, 同样双击.exe进行安装就好(注:RabbitMQ安装目录不允许有空格)。
安装RabbitMQ-Plugins,这个相当于是一个管理界面,方便我们在浏览器界面查看RabbitMQ各个消息队列以及exchange的工作情况,安装方法是:打开命令行cd进入rabbitmq的sbin目录输入:rabbitmq-plugins enable rabbitmq_management命令,稍等会会发现出现plugins安装成功的提示。
插件安装完之后,在浏览器输入http://localhost:15672进行验证。
生产和消费消息
生产者端客户端代码:
/**
* @author xizhonghuai
* @date 2019年2月18日
* @readme
*/
public class RabbitMQProducer {
/**
* @date 2019年2月18日
* @readme
* @param args
*/
private static final String EXCHANGE_NAME = "exchange demo";
private static final String ROUTING_KEY = "routingkey demo";
private static final String QUEUE_NAME = "queue demo";
private static final String IP_ADDRESS = "192.168.1.116";
private static final int PORT = 5672;// RabbitMQ 服务端默认端口号为5672
public static void main(String[] args) throws IOException, TimeoutException {
// TODO Auto-generated method stub
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(IP_ADDRESS);
factory.setPort(PORT);
factory.setUsername("admin");
factory.setPassword("123456");
Connection connection = factory.newConnection();// 创建连接
Channel channel = connection.createChannel();// 创建信道
// 创建一个type="direct" 、持久化的、非自动删除的交换器
channel.exchangeDeclare(EXCHANGE_NAME, "direct", true, false, null);
// 创建一个持久化、非排他的、非自动删除的队列
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
// 将交换器与队列通过路由键绑定
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);
// 发送一条持久化的消息: hello world !
String message = "Hello World !";
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
System.out.println("send OK");
// 关闭资源
channel.close();
connection.close();
}
}
消费者端客户端代码:
/**
* @author xizhonghuai
* @date 2019年2月18日
* @readme
*/
public class recTEST {
/**
* @date 2019年2月18日
* @readme
* @param args
*/
private static final String QUEUE_NAME = "queue demo";
private static final String IP_ADDRESS = "192.168.1.116";
private static final int PORT = 5672;
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
// TODO Auto-generated method stub
Address[] addresses = new Address[] { new Address(IP_ADDRESS, PORT) };
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("admin");
factory.setPassword("123456");
// 这里的连接方式与生产者的demo 略有不同, 注意辨别区别
Connection connection = factory.newConnection(addresses); // 创建连接
final Channel channel = connection.createChannel(); // 创建信道
channel.basicQos(64); // 设置客户端最多接收未被ack 的消息的个数
channel.basicConsume(QUEUE_NAME, false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
System.out.println("recv message: " + new String(body));
channel.basicAck(envelope.getDeliveryTag(), false);
}
});
channel.close();
connection.close();
}
}
rabbitMQ整体上是一个生产消费者模型,负责消息接收、存储、转发。
生产者产生的消息由两大部分组成,消息体与消息标签(交换机名、路由键)。
消息消费者连接到RabbitMQ服务节点后,接收消息体。
rabbitMQ中内部对象,用于存储消息。多个消费者可以订阅到同一个队列上,这时队列中的消息会被消费者平均分摊,而不是消费者都接收到所有消息。
生产者产生消息后,不是立即投递给消息队列,而是先将消息交给交换机,交换机通过某种路由规则(路由键)去分发消息,消息队列是通过某种绑定规则(绑定键)与交换机绑定。
交换机类似于邮箱筒,路由键类似于信件上的地址、绑定键类似于实际地理位置。
常用交换机的类型:
rabbitMQ中交换机类型有多种,不同的类型路由策略不同。
fanout:把所有消息发送到与该交换机绑定的队列中,不去匹配消息标签中路由 键与绑定键。
direct:匹配消息标签中路由键与绑定键,将符合要求的消息发送到对应的队列中。
topic:与direct类似,但路由键与绑定键不是完全匹配,通过 “.”、“#”模糊匹配。
生产者:
1、生产者与RabbitMQ服务器建立一个连接(Connection)、并开启一个信道(Channel)。
2、生产者声明一个交换机、并设置交换机类型。
3、生产者声明一个队列、并设置队里相关属性,比如是否持久化、是否排他、是否自动删除等。
4、设置绑定键将队列与交换机绑定起来。
5、生产者发送消息、消息包括消息体与消息标签(交换机名称、路由键)
6、相应交换机接收到消息后匹配路由键与绑定键,然后把消息体发送到对应队列。
7、关闭信道(Channel)。
8、关闭连接(Connection)。
消费者:
1、消费者与RabbitMQ建立一个连接(Connection)、并开启一个信道(Channel)。
2、请求队列中消息
3、接收到消息后,返回ACK。
4、关闭信道(Channel)。
5、关闭连接(Connection)。
不管是生产客户端还是消费客户端,都要与RabbitMQ服务节点建立一个连接,这个连接是一个TCP 连接。而信道(Channel)是建立在TCP连接上的一个基于AMQP协议的虚拟连接。