RabbitMQ:http://www.rabbitmq.com/
- 是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、C、用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不错
- 缺点:使用Erlang开发,阅读和修改源码难度大
什么是AMQP?
- AMQP(advanced message queuing protocol)在2003年时被提出,最早用于解决金融领不同平台之间的消息传递交互问题,就是是一种协议,兼容JMS
- 更准确说的链接协议 binary- wire-level-protocol 直接定义网络交换的数据格式,类似http
- 具体的产品实现比较多,RabbitMQ就是其中一种
特性:
AMQP和JMS的主要区别:
1.AMQP可跨平台语言生产消费,java生产的消息可以Python进行消费,可以用HTTP进行类比,不关心实现接口的语言,JMS则必须是java写的生产端和消费端。
2.AMQP的消息类型是Byt[],而JMS的消息类型是TextMessage/ObjectMessage/StreamMessage等。
搞个虚拟机装centos系统然后安装docker
#更新yum
yum update
yum install epel-release -y
yum clean all
yum list
#安装运行docker
yum install docker-io -y
systemctl start docker
#检测安装结果
docker info
systemctl start docker #运行Docker守护进程
systemctl stop docker #停止Docker守护进程
systemctl restart docker #重启Docker守护进程
#列举全部 容器 :
docker ps -a
#列举当前运行的容器:
docker ps
#检查容器内部信息:
docker inspect 容器名称
#删除镜像:
docker rmi IMAGE_NAME
#强制移除镜像不管是否有容器使用该镜像 增加 -f 参数
#删除前到停掉
#停止某个容器:
docker stop 容器名称
#启动某个容器:
docker start 容器名称
#移除某个容器:
docker rm 容器名称 (容器必须是停止状态)
#拉取镜像
docker pull rabbitmq:management
docker run -d --hostname rabbit_host1 --name xd_rabbit -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=123456 -p 15672:15672 -p 5672:5672 rabbitmq:management
#说明
-d 以守护进程方式在后台运行
-p 15672:15672 management 界面管理访问端口
-p 5672:5672 amqp 访问端口
--name:指定容器名
--hostname:设定容器的主机名,它会被写到容器内的 /etc/hostname 和 /etc/hosts,作为容器主机IP的别名,并且将显示在容器的bash中
-e 参数
RABBITMQ_DEFAULT_USER 用户名
RABBITMQ_DEFAULT_PASS 密码
4369 erlang 发现口
5672 client 端通信口
15672 管理界面 ui 端口
25672 server 间内部通信口
ip:15672访问管理界面
后续如果关闭虚拟机后再启动服务就用
#1.查容器名
docker ps -a
#2.根据容器名启动
docker start 容器名称或容器id
如下图:
创建一个空的maven工程(我用的jdk1.8的)然后在pom里导入引用包
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<skipTests>trueskipTests>
properties>
<dependencies>
<dependency>
<groupId>com.rabbitmqgroupId>
<artifactId>amqp-clientartifactId>
<version>5.10.0version>
dependency>
dependencies>
导入所需包之后便可以写一个组简单的生产消费,根据官方样例代码
根据官方样例改造成自己的
send.java
public class Send {
// 队列名称
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
// 连接信息
factory.setHost("20.18.24.143");
factory.setUsername("admin");
factory.setPassword("123456");
factory.setVirtualHost("devTest");
factory.setPort(5672);
// 继承
try (Connection connection = factory.newConnection();
// 创建信道
Channel channel = connection.createChannel()) {
/**
* 队列名称
* 持久化配置:mq重启后还在
* 是否独占:只能有一个消费者监听队列;当connection关闭是否删除队列,一般是false,发布订阅是独占
* 自动删除: 当没有消费者的时候,自动删除掉,一般是false
* 其他参数
*
* 队列不存在则会自动创建,如果存在则不会覆盖,所以此时的时候需要注意属性
*/
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello World!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
System.out.println(" [x] Sent '" + message + "'");
}
}
}
Recv.java代码
public class Recv {
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
// 连接信息
factory.setHost("20.18.24.143");
factory.setUsername("admin");
factory.setPassword("123456");
factory.setVirtualHost("devTest");
factory.setPort(5672);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
// 消费
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
super.handleDelivery(consumerTag, envelope, properties, body);
// 一般固定,一般称为会话名称
System.out.println("consumerTag: "+consumerTag);
// 可以获取交换机、路由键等信息
System.out.println("envelope: "+envelope);
//
System.out.println("properties: "+properties);
//
System.out.println("body: "+new String(body,"utf-8"));
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
}
}
先启动Recv消费者代码再启动生产者代码Send
控制台打印如下:
[*] Waiting for messages. To exit press CTRL+C
consumerTag: amq.ctag-fwM_uUThzXI3cZBV6U6fvg
envelope: Envelope(deliveryTag=1, redeliver=false, exchange=, routingKey=hello)
properties: #contentHeader(content-type=null, content-encoding=null, headers=null, delivery-mode=null, priority=null, correlation-id=null, reply-to=null, expiration=null, message-id=null, timestamp=null, type=null, user-id=null, app-id=null, cluster-id=null)
body: Hello World!
期初控制台只打印到CTRL+C那里,后面没有,只当生产者发送到channel中后消费者才有的消费,才有后面的日志。