1、前言
目前消息队列(MQ)在大型系统中被广泛应用,掌握MQ是java程序员的必备技能,下面我们从零开始学习MQ
1.1、什么是MQ
MQ全称为Message Queue,即消息队列, RabbitMQ是由erlang语言开发,基于AMQP(Advanced Message
Queue 高级消息队列协议)协议实现的消息队列,它是一种应用程序之间的通信方法,消息队列在分布式系统开
发中应用非常广泛。RabbitMQ官方地址:http://www.rabbitmq.com/
1.2、开发中消息队列通常有如下应用场景:
1、任务异步处理。
将不需要同步处理的并且耗时长的操作由消息队列通知消息接收方进行异步处理。提高了应用程序的响应时间。
2、应用程序解耦合
MQ相当于一个中介,生产方通过MQ与消费方交互,它将应用程序进行解耦合。
市场上还有哪些消息队列?
ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ、Redis。
为什么使用RabbitMQ呢?
1、使得简单,功能强大。
2、基于AMQP协议。
3、社区活跃,文档完善。
4、高并发性能好,这主要得益于Erlang语言。
5、Spring Boot默认已集成RabbitMQ
1.3、AMQP是什么 ?
AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有 RabbitMQ等。
总结: AMQP是一套公开的消息队列协议,最早在2003年被提出,它旨在从协议层定义消息通信数据的标准格式,
为的就是解决MQ市场上协议不统一的问题。RabbitMQ就是遵循AMQP标准协议开发的MQ服务。
官方:http://www.amqp.org/
2、RabbitMQ安装
RabbitMQ由Erlang语言开发,安装RabbitMQ需要安装Erlang/OTP,并保持版本匹配,如下图:
RabbitMQ的下载地址:http://www.rabbitmq.com/download.html
2.1、下载erlang
去erlang官网下载otp_win64_21.3.exe,以管理员方式运行此文件,安装
erlang安装完成需要配置erlang环境变量: ERLANG_HOME=D:\Program Files\erl9.3 在path中添
加%ERLANG_HOME%\bin;
2.2、安装RabbitMQ
2.2.1安装并运行服务
rabbitmq-service-install 安装服务
rabbitmq-service-remove 移除服务
rabbitmq-service-stop 停止服务
rabbitmq-service- start 启动服务
2.2.2、安装管理插件
- 运行命令行窗口cmd
- 输入命令rabbitmq-plugins enable rabbitmq_management,这样就可以添加可视化插件了。
查看可视化插件是否成功:
在web浏览器中输入地址:http://127.0.0.1:15672/
输入默认账号: guest 密码: guest
3、简单测试
添加maven依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.7.0</version>
</dependency>
创建消息产生者
package com.whwe.rabbitmqdemo.produc;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @ClassName Producer
* @Description TODO
* @Author yueyiming
* @Date 2019/4/26 10:44
* @Version 1.0
* https://blog.csdn.net/hzau_itdog
**/
public class Producer {
//队列名称
private static final String QUEUE = "helloworld";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = null;
Channel channel = null;
//创建连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.20.129");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
try {
connection = connectionFactory.newConnection();
//创建channel通道
channel = connection.createChannel();
// 声明队列,如果Rabbit中没有此队列将自动创建
// queue:队列名称
// durable:是否持久化
// exclusive:队列是否独占此连接
// autoDelete:队列不再使用时是否自动删除此队列
// arguments:队列参数
channel.queueDeclare(QUEUE, true, false, false, null);
String message = "-----helloworld----------小明------" + System.currentTimeMillis();
// 发送消息
// exchange Exchange的名称,如果没有指定,则使用Default Exchange
// routingKey 消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
// props 消息包含的属性
// body 消息体
channel.basicPublish("", QUEUE, null, message.getBytes("utf-8"));
System.out.println("发送消息" + message);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
}
}
}
创建消息消费者
package com.whwe.rabbitmqdemo.conc;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @ClassName Consumer01
* @Description TODO
* @Author yueyiming
* @Date 2019/4/26 10:55
* @Version 1.0
* https://blog.csdn.net/hzau_itdog
**/
public class Consumer01 {
//队列名称
private static final String QUEUE = "helloworld";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = null;
Channel channel = null;
//创建连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.20.129");
connectionFactory.setPort(5672);
try {
connection = connectionFactory.newConnection();
//创建channel通道
channel = connection.createChannel();
// 声明队列,如果Rabbit中没有此队列将自动创建
// queue:队列名称
// durable:是否持久化
// exclusive:队列是否独占此连接
// autoDelete:队列不再使用时是否自动删除此队列
// arguments:队列参数
channel.queueDeclare(QUEUE, true, false, false, null);
//定义消费方法
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
/**
* 消费者接收消息调用此方法
* @param consumerTag 消费者的标签,在channel.basicConsume()去指定
* @param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志(收到消息失败后是否需要重新发送)
* @param properties
* @param body 消息内容
*/
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String exchange = envelope.getExchange();
String routingKey = envelope.getRoutingKey();
//消息id
long deliveryTag = envelope.getDeliveryTag();
//消息内容
String message = new String(body, "utf-8");
System.out.println("exchange------"+exchange);
System.out.println("routingKey------"+routingKey);
System.out.println("deliveryTag------"+deliveryTag);
System.out.println("message------"+message);
}
};
channel.basicConsume(QUEUE,true,consumer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果