消息队列

消息队列是企业开发不可或缺的一部分。 掌握各种队列的使用和了解队列的不同和相同点。也是自己进步的一部分呐。
这次介绍Kafka、RabbitMQ、ZeroMQ、RocketMQ、ActiveMQ17个方面中和对比做为消息队列使用时的差异。
最后将使用最常用的RabbitMQ和ActiveMQ来举例。

哇偶~今天有点晚。阳光都跑到jiojio上去了。

一、资料文档

Kafka:中。有kafka作者自己写的书,网上资料也有一些。 rabbitmq:多。有一些不错的书,网上资料多。
zeromq:少。没有专门写zeromq的书,网上的资料多是一些代码的实现和简单介绍。
rocketmq:少。没有专门写rocketmq的书,网上的资料良莠不齐,官方文档很简洁,但是对技术细节没有过多的描述。
activemq:多。没有专门写activemq的书,网上资料多。


二、开发语言

Kafka:Scala
rabbitmq:Erlang
zeromq:c
rocketmq:java
activemq:java


三、支持的协议

Kafka:自己定义的一套(基于TCP)
rabbitmq:AMQP
zeromq:TCP、UDP
rocketmq:自己定义的一套
activemq:OpenWire、STOMP、REST、XMPP、AMQP


四、消息存储
Kafka:内存、磁盘、数据库。支持大量堆积。

kafka的最小存储单元是分区,一个topic包含多个分区,kafka创建主题时,这些分区会被分配在多个服务器上,通常一个broker一台服务器。
分区首领会均匀地分布在不同的服务器上,分区副本也会均匀的分布在不同的服务器上,确保负载均衡和高可用性,当新的broker加入集群的时候,部分副本会被移动到新的broker上。
根据配置文件中的目录清单,kafka会把新的分区分配给目录清单里分区数最少的目录。
默认情况下,分区器使用轮询算法把消息均衡地分布在同一个主题的不同分区中,对于发送时指定了key的情况,会根据key的hashcode取模后的值存到对应的分区中。

rabbitmq:内存、磁盘。支持少量堆积。

rabbitmq的消息分为持久化的消息和非持久化消息,不管是持久化的消息还是非持久化的消息都可以写入到磁盘。
持久化的消息在到达队列时就写入到磁盘,并且如果可以,持久化的消息也会在内存中保存一份备份,这样可以提高一定的性能,当内存吃紧的时候会从内存中清除。非持久化的消息一般只存在于内存中,在内存吃紧的时候会被换入到磁盘中,以节省内存。

这里可以一个引入镜像队列机制,可将重要队列“复制”到集群中的其他broker上,
保证这些队列的消息不会丢失。
配置镜像的队列,都包含一个主节点master和多个从节点slave,如果master失效,
加入时间最长的slave会被提升为新的master,除发送消息外的所有动作都向master发送,
然后由master将命令执行结果广播给各个slave,
rabbitmq会让master均匀地分布在不同的服务器上,
而同一个队列的slave也会均匀地分布在不同的服务器上,保证负载均衡和高可用性。

zeromq:消息发送端的内存或者磁盘中。不支持持久化。
activemq:内存、磁盘、数据库。支持少量堆积。
rocketmq:磁盘。支持大量堆积。

commitLog文件存放实际的消息数据,每个commitLog上限是1G,满了之后会自动新建一个commitLog文件保存数据。ConsumeQueue队列只存放offset、size、tagcode,非常小,分布在多个broker上。ConsumeQueue相当于CommitLog的索引文件,消费者消费时会从consumeQueue中查找消息在commitLog中的offset,再去commitLog中查找元数据。

ConsumeQueue存储格式的特性,保证了写过程的顺序写盘(写CommitLog文件),大量数据IO都在顺序写同一个commitLog,满1G了再写新的。加上rocketmq是累计4K才强制从PageCache中刷到磁盘(缓存),所以高并发写性能突出。

activemq:内存、磁盘、数据库。支持少量堆积。


五、消息事务

Kafka:支持
rabbitmq:支持。 客户端将信道设置为事务模式,只有当消息被rabbitMq接收,事务才能提交成功,否则在捕获异常后进行回滚。使用事务会使得性能有所下降 。
zeromq:不支持
rocketmq:支持
activemq:支持


六、负载均衡
Kafka:支持负载均衡。

1>一个broker通常就是一台服务器节点。对于同一个Topic的不同分区,Kafka会尽力将这些分区分布到不同的Broker服务器上,zookeeper保存了broker、主题和分区的元数据信息。分区首领会处理来自客户端的生产请求,kafka分区首领会被分配到不同的broker服务器上,让不同的broker服务器共同分担任务。
每一个broker都缓存了元数据信息,客户端可以从任意一个broker获取元数据信息并缓存起来,根据元数据信息知道要往哪里发送请求。
2>kafka的消费者组订阅同一个topic,会尽可能地使得每一个消费者分配到相同数量的分区,分摊负载。
3>当消费者加入或者退出消费者组的时候,还会触发再均衡,为每一个消费者重新分配分区,分摊负载。
kafka的负载均衡大部分是自动完成的,分区的创建也是kafka完成的,隐藏了很多细节,避免了繁琐的配置和人为疏忽造成的负载问题。
4>发送端由topic和key来决定消息发往哪个分区,如果key为null,那么会使用轮询算法将消息均衡地发送到同一个topic的不同分区中。如果key不为null,那么会根据key的hashcode取模计算出要发往的分区。

rabbitmq:对负载均衡的支持不好。

1>消息被投递到哪个队列是由交换器和key决定的,交换器、路由键、队列都需要手动创建。

rabbitmq客户端发送消息要和broker建立连接,需要事先知道broker上有哪些交换器,有哪些队列。通常要声明要发送的目标队列,如果没有目标队列,会在broker上创建一个队列,如果有,就什么都不处理,接着往这个队列发送消息。假设大部分繁重任务的队列都创建在同一个broker上,那么这个broker的负载就会过大。(可以在上线前预先创建队列,无需声明要发送的队列,但是发送时不会尝试创建队列,可能出现找不到队列的问题,rabbitmq的备份交换器会把找不到队列的消息保存到一个专门的队列中,以便以后查询使用)

使用镜像队列机制建立rabbitmq集群可以解决这个问题,形成master-slave的架构,master节点会均匀分布在不同的服务器上,让每一台服务器分摊负载。slave节点只是负责转发,在master失效时会选择加入时间最长的slave成为master。

当新节点加入镜像队列的时候,队列中的消息不会同步到新的slave中,除非调用同步命令,但是调用命令后,队列会阻塞,不能在生产环境中调用同步命令。

2>当rabbitmq队列拥有多个消费者的时候,队列收到的消息将以轮询的分发方式发送给消费者。每条消息只会发送给订阅列表里的一个消费者,不会重复。

这种方式非常适合扩展,而且是专门为并发程序设计的。

如果某些消费者的任务比较繁重,那么可以设置basicQos限制信道上消费者能保持的最大未确认消息的数量,在达到上限时,rabbitmq不再向这个消费者发送任何消息。

3>对于rabbitmq而言,客户端与集群建立的TCP连接不是与集群中所有的节点建立连接,而是挑选其中一个节点建立连接。

但是rabbitmq集群可以借助HAProxy、LVS技术,或者在客户端使用算法实现负载均衡,引入负载均衡之后,各个客户端的连接可以分摊到集群的各个节点之中。

zeromq:去中心化,不支持负载均衡。本身只是一个多线程网络库。
rocketmq:支持负载均衡。

一个broker通常是一个服务器节点,broker分为master和slave,master和slave存储的数据一样,slave从master同步数据。

1>nameserver与每个集群成员保持心跳,保存着Topic-Broker路由信息,同一个topic的队列会分布在不同的服务器上。

2>发送消息通过轮询队列的方式发送,每个队列接收平均的消息量。发送消息指定topic、tags、keys,无法指定投递到哪个队列(没有意义,集群消费和广播消费跟消息存放在哪个队列没有关系)。

tags选填,类似于 Gmail 为每封邮件设置的标签,方便服务器过滤使用。目前只支 持每个消息设置一个 tag,所以也可以类比为
Notify 的 MessageType 概念。

keys选填,代表这条消息的业务关键词,服务器会根据 keys 创建哈希索引,设置后, 可以在 Console 系统根据
Topic、Keys 来查询消息,由于是哈希索引,请尽可能 保证 key 唯一,例如订单号,商品 Id 等。

3>rocketmq的负载均衡策略规定:Consumer数量应该小于等于Queue数量,如果Consumer超过Queue数量,那么多余的Consumer
将不能消费消息。这一点和kafka是一致的,rocketmq会尽可能地为每一个Consumer分配相同数量的队列,分摊负载。

activemq:支持负载均衡。可以基于zookeeper实现负载均衡。


七、集群方式
Kafka:天然的‘Leader-Slave’无状态集群,每台服务器既是Master也是Slave。

分区首领均匀地分布在不同的kafka服务器上,分区副本也均匀地分布在不同的kafka服务器上,所以每一台kafka服务器既含有分区首领,同时又含有分区副本,每一台kafka服务器是某一台kafka服务器的Slave,同时也是某一台kafka服务器的leader。

kafka的集群依赖于zookeeper,zookeeper支持热扩展,所有的broker、消费者、分区都可以动态加入移除,而无需关闭服务,与不依靠zookeeper集群的mq相比,这是最大的优势。

rabbitmq:支持简单集群,'复制’模式,对高级集群模式支持不好。

rabbitmq的每一个节点,不管是单一节点系统或者是集群中的一部分,要么是内存节点,要么是磁盘节点,集群中至少要有一个是磁盘节点。

在rabbitmq集群中创建队列,集群只会在单个节点创建队列进程和完整的队列信息(元数据、状态、内容),而不是在所有节点上创建。

引入镜像队列,可以避免单点故障,确保服务的可用性,但是需要人为地为某些重要的队列配置镜像。

zeromq:去中心化,不支持集群。

rocketmq:常用 多对’Master-Slave’ 模式,开源版本需手动切换Slave变成Master

Name Server是一个几乎无状态节点,可集群部署,节点之间无任何信息同步。

Broker部署相对复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave的对应关系通过指定相同的BrokerName,不同的BrokerId来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个。每个Broker与Name
Server集群中的所有节点建立长连接,定时注册Topic信息到所有Name Server。

Producer与Name Server集群中的其中一个节点(随机选择)建立长连接,定期从Name
Server取Topic路由信息,并向提供Topic服务的Master建立长连接,且定时向Master发送心跳。Producer完全无状态,可集群部署。

Consumer与Name Server集群中的其中一个节点(随机选择)建立长连接,定期从Name
Server取Topic路由信息,并向提供Topic服务的Master、Slave建立长连接,且定时向Master、Slave发送心跳。Consumer既可以从Master订阅消息,也可以从Slave订阅消息,订阅规则由Broker配置决定。

客户端先找到NameServer, 然后通过NameServer再找到 Broker。

一个topic有多个队列,这些队列会均匀地分布在不同的broker服务器上。rocketmq队列的概念和kafka的分区概念是基本一致的,kafka同一个topic的分区尽可能地分布在不同的broker上,分区副本也会分布在不同的broker上。

rocketmq集群的slave会从master拉取数据备份,master分布在不同的broker上。

activemq:支持简单集群模式,比如’主-备’,对高级集群模式支持不好。


八、管理界面

Kafka:一般
rabbitmq:好
zeromq:无
rocketmq:无
activemq:一般


九、可用性

Kafka:非常高(分布式)
rabbitmq:高(主从)
zeromq:高
rocketmq:非常高(分布式)
activemq:高(主从)


十、消息重复

Kafka:支持at least once、at most once

rabbitmq:支持at least once、at most once

zeromq:只有重传机制,但是没有持久化,消息丢了重传也没有用。既不是at least once、也不是at mostonce、更不是exactly only once

rocketmq:支持at least once

activemq:支持at least once


十一、吞吐量TPS

Kafka:极大 Kafka按批次发送消息和消费消息。发送端将多个小消息合并,批量发向Broker,消费端每次取出一个批次的消息批量处理。
rabbitmq:比较大
zeromq:极大
rocketmq:大 rocketMQ接收端可以批量消费消息,可以配置每次消费的消息数,但是发送端不是批量发送。
activemq:比较大


十二、订阅形式和消息分发
Kafka:基于topic以及按照topic进行正则匹配的发布订阅模式。

【发送】

发送端由topic和key来决定消息发往哪个分区,如果key为null,那么会使用轮询算法将消息均衡地发送到同一个topic的不同分区中。如果key不为null,那么会根据key的hashcode取模计算出要发往的分区。

【接收】

1>consumer向群组协调器broker发送心跳来维持他们和群组的从属关系以及他们对分区的所有权关系,所有权关系一旦被分配就不会改变除非发生再均衡(比如有一个consumer加入或者离开consumer
group),consumer只会从对应的分区读取消息。

2>kafka限制consumer个数要少于分区个数,每个消息只会被同一个 Consumer
Group的一个consumer消费(非广播)。

3>kafka的 Consumer Group订阅同一个topic,会尽可能地使得每一个consumer分配到相同数量的分区,不同
Consumer Group订阅同一个主题相互独立,同一个消息会被不同的 Consumer Group处理。

rabbitmq:提供了4种:direct, topic ,Headers和fanout。

【发送】

先要声明一个队列,这个队列会被创建或者已经被创建,队列是基本存储单元。

由exchange和key决定消息存储在哪个队列。

direct>发送到和bindingKey完全匹配的队列。

topic>路由key是含有"."的字符串,会发送到含有“*”、“#”进行模糊匹配的bingKey对应的队列。

fanout>与key无关,会发送到所有和exchange绑定的队列

headers>与key无关,消息内容的headers属性(一个键值对)和绑定键值对完全匹配时,会发送到此队列。此方式性能低一般不用

【接收】

rabbitmq的队列是基本存储单元,不再被分区或者分片,对于我们已经创建了的队列,消费端要指定从哪一个队列接收消息。

当rabbitmq队列拥有多个消费者的时候,队列收到的消息将以轮询的分发方式发送给消费者。每条消息只会发送给订阅列表里的一个消费者,不会重复。

这种方式非常适合扩展,而且是专门为并发程序设计的。

如果某些消费者的任务比较繁重,那么可以设置basicQos限制信道上消费者能保持的最大未确认消息的数量,在达到上限时,rabbitmq不再向这个消费者发送任何消息。

zeromq:点对点(p2p)
rocketmq:基于topic/messageTag以及按照消息类型、属性进行正则匹配的发布订阅模式

【发送】

发送消息通过轮询队列的方式发送,每个队列接收平均的消息量。发送消息指定topic、tags、keys,无法指定投递到哪个队列(没有意义,集群消费和广播消费跟消息存放在哪个队列没有关系)。

tags选填,类似于 Gmail 为每封邮件设置的标签,方便服务器过滤使用。目前只支 持每个消息设置一个 tag,所以也可以类比为
Notify 的 MessageType 概念。

keys选填,代表这条消息的业务关键词,服务器会根据 keys 创建哈希索引,设置后, 可以在 Console 系统根据
Topic、Keys 来查询消息,由于是哈希索引,请尽可能 保证 key 唯一,例如订单号,商品 Id 等。

【接收】

1>广播消费。一条消息被多个Consumer消费,即使Consumer属于同一个ConsumerGroup,消息也会被ConsumerGroup中的每个Consumer都消费一次。

2>集群消费。一个 Consumer Group中的Consumer实例平均分摊消费消息。例如某个Topic有 9
条消息,其中一个Consumer Group有3个实例,那么每个实例只消费其中的 3
条消息。即每一个队列都把消息轮流分发给每个consumer。

activemq:点对点(p2p)、广播(发布-订阅)

点对点模式,每个消息只有1个消费者;

发布/订阅模式,每个消息可以有多个消费者。

【发送】

点对点模式:先要指定一个队列,这个队列会被创建或者已经被创建。

发布/订阅模式:先要指定一个topic,这个topic会被创建或者已经被创建。

【接收】

点对点模式:对于已经创建了的队列,消费端要指定从哪一个队列接收消息。

发布/订阅模式:对于已经创建了的topic,消费端要指定订阅哪一个topic的消息。


十三、顺序消息
Kafka:支持。

设置生产者的max.in.flight.requests.per.connection为1,可以保证消息是按照发送顺序写入服务器的,即使发生了重试。

kafka保证同一个分区里的消息是有序的,但是这种有序分两种情况

1>key为null,消息逐个被写入不同主机的分区中,但是对于每个分区依然是有序的

2>key不为null , 消息被写入到同一个分区,这个分区的消息都是有序。

rabbitmq:不支持

zeromq:不支持

rocketmq:支持

activemq:不支持
十四、消息确认
Kafka:支持。

1>发送方确认机制

ack=0,不管消息是否成功写入分区

ack=1,消息成功写入首领分区后,返回成功

ack=all,消息成功写入所有分区后,返回成功。

2>接收方确认机制

自动或者手动提交分区偏移量,早期版本的kafka偏移量是提交给Zookeeper的,这样使得zookeeper的压力比较大,更新版本的kafka的偏移量是提交给kafka服务器的,不再依赖于zookeeper群组,集群的性能更加稳定。

rabbitmq:支持。

1>发送方确认机制,消息被投递到所有匹配的队列后,返回成功。如果消息和队列是可持久化的,那么在写入磁盘后,返回成功。支持批量确认和异步确认。

2>接收方确认机制,设置autoAck为false,需要显式确认,设置autoAck为true,自动确认。

当autoAck为false的时候,rabbitmq队列会分成两部分,一部分是等待投递给consumer的消息,一部分是已经投递但是没收到确认的消息。如果一直没有收到确认信号,并且consumer已经断开连接,rabbitmq会安排这个消息重新进入队列,投递给原来的消费者或者下一个消费者。

未确认的消息不会有过期时间,如果一直没有确认,并且没有断开连接,rabbitmq会一直等待,rabbitmq允许一条消息处理的时间可以很久很久。

zeromq:支持。

rocketmq:支持。

activemq:支持。


十五、消息回溯

Kafka:支持指定分区offset位置的回溯。
rabbitmq:不支持
zeromq:不支持
rocketmq:支持指定时间点的回溯。
activemq:不支持


十六、消息重试
Kafka:不支持,但是可以实现。

kafka支持指定分区offset位置的回溯,可以实现消息重试。

rabbitmq:不支持,但是可以利用消息确认机制实现。

rabbitmq接收方确认机制,设置autoAck为false。

当autoAck为false的时候,rabbitmq队列会分成两部分,一部分是等待投递给consumer的消息,一部分是已经投递但是没收到确认的消息。如果一直没有收到确认信号,并且consumer已经断开连接,rabbitmq会安排这个消息重新进入队列,投递给原来的消费者或者下一个消费者。

zeromq:不支持,

rocketmq:支持。

消息消费失败的大部分场景下,立即重试99%都会失败,所以rocketmq的策略是在消费失败时定时重试,每次时间间隔相同。

1>发送端的 send 方法本身支持内部重试,重试逻辑如下:

a)至多重试3次;

b)如果发送失败,则轮转到下一个broker;

c)这个方法的总耗时不超过sendMsgTimeout 设置的值,默认 10s,超过时间不在重试。

2>接收端。

Consumer 消费消息失败后,要提供一种重试机制,令消息再消费一次。Consumer 消费消息失败通常可以分为以下两种情况:

  1. 由于消息本身的原因,例如反序列化失败,消息数据本身无法处理(例如话费充值,当前消息的手机号被

注销,无法充值)等。定时重试机制,比如过 10s 秒后再重试。

  1. 由于依赖的下游应用服务不可用,例如 db 连接不可用,外系统网络不可达等。

即使跳过当前失败的消息,消费其他消息同样也会报错。这种情况可以 sleep 30s,再消费下一条消息,减轻 Broker 重试消息的压力。

activemq:不支持


十七、并发度
Kafka:高

一个线程一个消费者,kafka限制消费者的个数要小于等于分区数,如果要提高并行度,可以在消费者中再开启多线程,或者增加consumer实例数量。

rabbitmq:极高

本身是用Erlang语言写的,并发性能高。

可在消费者中开启多线程,最常用的做法是一个channel对应一个消费者,每一个线程把持一个channel,多个线程复用connection的tcp连接,减少性能开销。

当rabbitmq队列拥有多个消费者的时候,队列收到的消息将以轮询的分发方式发送给消费者。每条消息只会发送给订阅列表里的一个消费者,不会重复。

这种方式非常适合扩展,而且是专门为并发程序设计的。

如果某些消费者的任务比较繁重,那么可以设置basicQos限制信道上消费者能保持的最大未确认消息的数量,在达到上限时,rabbitmq不再向这个消费者发送任何消息。

zeromq:高

rocketmq:高

1>rocketmq限制消费者的个数少于等于队列数,但是可以在消费者中再开启多线程,这一点和kafka是一致的,提高并行度的方法相同。

修改消费并行度方法

a) 同一个 ConsumerGroup 下,通过增加 Consumer 实例数量来提高并行度,超过订阅队列数的 Consumer实例无效。

b) 提高单个 Consumer 的消费并行线程,通过修改参数consumeThreadMin、consumeThreadMax

2>同一个网络连接connection,客户端多个线程可以同时发送请求,连接会被复用,减少性能开销。

activemq:高

单个ActiveMQ的接收和消费消息的速度在1万笔/秒(持久化 一般为1-2万, 非持久化 2
万以上),在生产环境中部署10个Activemq就能达到10万笔/秒以上的性能,部署越多的activemq broker
在MQ上latency也就越低,系统吞吐量也就越高。

今天就先从这几个角度去对比一下几个消息队列的不同之处。这里只是浅浅的研究一下。混个眼熟。等到那天用到了可以深究。
接下来举两个队列例子代码吧。就拿常用的ActiveMQ和RabbitMQ来啦。
先来ActiveMQ的叭~
这里提供建立方法和学习。具体的传参入参还是要按需求来的哈。
发送者

package cn.com.winpeace.main;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;


public class Sender {

    public static void main(String[] args) {
        // ConnectionFactory :连接工厂,JMS 用它创建连接
        ConnectionFactory connectionFactory;
        // Connection :JMS 客户端到JMS Provider 的连接
        Connection connection = null;
        // Session: 一个发送或接收消息的线程
        Session session;
        // Destination :消息的目的地;消息发送给谁.
        Destination destination;
        // MessageProducer:消息发送者
        MessageProducer producer;
        // TextMessage message;
        // 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
        connectionFactory = new ActiveMQConnectionFactory(
                ActiveMQConnection.DEFAULT_USER,
                ActiveMQConnection.DEFAULT_PASSWORD,
                "tcp://192.168.0.10:61616");
        try {
            // 构造从工厂得到连接对象
            connection = connectionFactory.createConnection();
            // 启动
            connection.start();
            // 获取操作连接
            session = connection.createSession(Boolean.TRUE,
                    Session.AUTO_ACKNOWLEDGE);
            
            // 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
            destination = session.createQueue("error");
            // 得到消息生成者【发送者】
            producer = session.createProducer(destination);
            // 设置不持久化,此处学习,实际根据项目决定
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);
            // 构造消息,此处写死,项目就是参数,或者方法获取
            sendMessageForError(session, producer);
            
            
            // 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
            destination = session.createQueue("turn");
            // 得到消息生成者【发送者】
            producer = session.createProducer(destination);
            // 设置不持久化,此处学习,实际根据项目决定
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);
            // 构造消息,此处写死,项目就是参数,或者方法获取
            sendMessageForTurn(session, producer);
            
            
            // 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
            destination = session.createQueue("event");
            // 得到消息生成者【发送者】
            producer = session.createProducer(destination);
            // 设置不持久化,此处学习,实际根据项目决定
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);
            // 构造消息,此处写死,项目就是参数,或者方法获取
            sendMessageForEvent(session, producer);
            
            
            // 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
            destination = session.createQueue("sales");
            // 得到消息生成者【发送者】
            producer = session.createProducer(destination);
            // 设置不持久化,此处学习,实际根据项目决定
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);
            // 构造消息,此处写死,项目就是参数,或者方法获取
            sendMessageForSales(session, producer);
            
            // 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
            destination = session.createQueue("sale");
            // 得到消息生成者【发送者】
            producer = session.createProducer(destination);
            // 设置不持久化,此处学习,实际根据项目决定
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);
            // 构造消息,此处写死,项目就是参数,或者方法获取
            sendMessageForSale(session, producer);
            
            session.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != connection)
                    connection.close();
            } catch (Throwable ignore) {
            }
        }
    }
    
    public static void sendMessageForError(Session session, MessageProducer producer)
            throws Exception {
    	 String JSONString = "{dd}";
    	 TextMessage message = session
                 .createTextMessage(JSONString);
         // 发送消息到目的地方
         producer.send(message);
    }
    
    public static void sendMessageForTurn(Session session, MessageProducer producer)
            throws Exception {
    	String JSONString = "{dd}";
    	 TextMessage message = session
                 .createTextMessage(JSONString);
         // 发送消息到目的地方
         producer.send(message);
    }
    
    public static void sendMessageForEvent(Session session, MessageProducer producer)
            throws Exception {
    	 String JSONString = "{dd}";
    	 TextMessage message = session
                 .createTextMessage(JSONString);
         // 发送消息到目的地方
         producer.send(message);
    }
    
    public static void sendMessageForSales(Session session, MessageProducer producer)
            throws Exception {
    	 String JSONString = "{dd}";
    	 TextMessage message = session
                 .createTextMessage(JSONString);
         // 发送消息到目的地方
         producer.send(message);
    }
    
    public static void sendMessageForSale(Session session, MessageProducer producer)
            throws Exception {
    	String JSONString = "{dd}";
    	 TextMessage message = session
                 .createTextMessage(JSONString);
         // 发送消息到目的地方
         producer.send(message);
    }
}

接收者

import java.sql.Connection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.log4j.Logger;

import cn.com.winpeace.util.DBTools;
import cn.com.winpeace.util.PropertiesUtils;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

/**
 *
 */
public class Receiver {

	static Logger log = Logger.getLogger(Receiver.class);

	static String insertEnd = " SELECT 1 FROM dual;";
	/**
	 * 主程序入口
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		
		// 加载属性配置
		Map<String, String> propsMap = PropertiesUtils.loadProperties("system.properties");
		// 取得DB连接信息
		String driver = propsMap.get("DRIVER");
		String url = propsMap.get("URL");
		String user = propsMap.get("USER");
		String password = propsMap.get("PASSWORD");
		DBTools db = new DBTools();
		Connection conn;
		
        // ConnectionFactory :连接工厂,JMS 用它创建连接
        ConnectionFactory connectionFactory;
        // Connection :JMS 客户端到JMS Provider 的连接
        javax.jms.Connection connection = null;
        // Session: 一个发送或接收消息的线程
        Session session;
        // Destination :消息的目的地;消息发送给谁.
        Destination destination;
        // 消费者,消息接收者
        MessageConsumer consumer1;
        MessageConsumer consumer2;
        MessageConsumer consumer3;
        MessageConsumer consumer4;
        connectionFactory = new ActiveMQConnectionFactory(
                ActiveMQConnection.DEFAULT_USER,
                ActiveMQConnection.DEFAULT_PASSWORD,
                "tcp://localhost:61616");
        
		try {
			// 建立数据库连接
			db.init(driver, url, user, password);
			conn = db.getConn();
			conn.setAutoCommit(false);

			// 构造从工厂得到连接对象
			connection = connectionFactory.createConnection();
			// 启动
			connection.start();
			// 获取操作连接
			session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);

			// 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
			destination = session.createQueue("error");
			consumer1 = session.createConsumer(destination);
			
			destination = session.createQueue("turn");
			consumer2 = session.createConsumer(destination);
			
			destination = session.createQueue("event");
			consumer3 = session.createConsumer(destination);
			
			destination = session.createQueue("sales");
			consumer4 = session.createConsumer(destination);
			
			// 无限循环,通过修改配置文件runflg=0退出
			while(true){
				if(PropertiesUtils.getProperty("runflg.properties", "runflg").equals("0")){
			         System.out.println("program has already exited");
			         log.info("program has already exited");
			         return;
			    }
				
				int waitTime = Integer.parseInt(PropertiesUtils.getProperty("system.properties", "waittime"));
				int sleepTime = Integer.parseInt(PropertiesUtils.getProperty("system.properties", "sleeptime"));
				
				// 错误日志
				insertErrlog(consumer1, waitTime, db, conn);
				
				// 交班日志
				insertTurn(consumer2, waitTime, db, conn);
				
				// 操作记录
				insertEvent(consumer3, waitTime, db, conn);
				
				// 销售数据
				insertSales(consumer4, waitTime, db, conn);
				
				// 睡眠1分钟后再次循环
				log.info("sleep 1 minutes.");
				Thread.sleep(sleepTime);
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(db != null){
				db.close();
			}
            try {
                if (null != connection)
                    connection.close();
            } catch (Throwable ignore) {
            }
		}
	}
	
	public static void insertErrlog(MessageConsumer consumer, int waitTime, DBTools db, Connection conn) throws Exception {
		//设置接收者接收消息的时间,为了便于测试,这里谁定为100s
		TextMessage message = (TextMessage) consumer.receive(waitTime);
		try{
			if (null != message) {
				System.out.println("收到消息:" + message.getText());
				Map<String, Object> response = new Gson().fromJson(message.getText(),
					new TypeToken<Map<String, Object>>() {}.getType());
				List<Map<String, Object>> mapList = (List<Map<String, Object>>) response.get("errlogs");
			

				String insertKey = " INTO errlog (EventTime, StoreID, MachID, errID, errInfo) VALUES ";
				String insertSql = "INSERT ALL ";
				for (Map<String, Object> map : mapList) {
					insertSql += insertKey;
					insertSql += "('" + map.get("EventTime") + "', '"
						+ map.get("StoreID") + "', '"
						+ map.get("MachID") + "', "
						+ map.get("errID") + ", '"
						+ map.get("errInfo") + "'), ";
				}
				insertSql = insertSql.substring(0, insertSql.lastIndexOf(","));
				insertSql += insertEnd;
				System.out.println("insertSql:" + insertSql);
				
				db.excuteSql(insertSql);
				conn.commit();
			}
		} catch(Exception e) {
			conn.rollback();
			System.out.println("errlog错误日志insert异常");
			log.info("errlog错误日志insert异常");
			throw e;
		}
	}
	
	public static void insertTurn(MessageConsumer consumer, int waitTime, DBTools db, Connection conn) throws Exception {
		//设置接收者接收消息的时间,为了便于测试,这里谁定为100s
		TextMessage message = (TextMessage) consumer.receive(waitTime);
		try{
			if (null != message) {
				System.out.println("收到消息:" + message.getText());
				Map<String, Object> response = new Gson().fromJson(message.getText(),
					new TypeToken<Map<String, Object>>() {}.getType());
				List<Map<String, Object>> mapList = (List<Map<String, Object>>) response.get("turnlogs");
				// 获取当前时间
				SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 设置日期格式
				String now = df.format(new Date());// new Date()为获取当前系统时间
				
				String insertKey = " INTO turnlog (LOGINID, MACHID, SYSTEMDATE, TURN, PAYEE, STARTTIME, OUTTIME, STARTAMOUNT, "
						+ "CLOSEFLAG, TRUNMODE, CHECKAMOUNT, SYSAMOUNT, STOREID, UPLOADTIME) VALUES ";
				String insertSql = "INSERT ALL ";
				for (Map<String, Object> map : mapList) {
					insertSql += insertKey;
					insertSql += "(" + map.get("LoginID") + ", '"
						+ map.get("MachID") + "', '"
						+ map.get("SystemDate") + "', "
						+ map.get("Turn") + ", '"
						+ map.get("CasherID") + "', '"
						+ map.get("StartTime") + "', '"
						+ map.get("OutTime") + "', "
						+ map.get("StartAmount") + ", "
						+ map.get("CloseFlag") + ", "
						+ map.get("TranMode") + ", "
						+ "NULL, "
						+ "NULL, '"
						+ map.get("StoreID") + "', '"
						+ now + "'), ";
				}
				insertSql = insertSql.substring(0, insertSql.lastIndexOf(","));
				insertSql += insertEnd;
				System.out.println("insertSql:" + insertSql);
				
				db.excuteSql(insertSql);
				conn.commit();
			}
		} catch(Exception e) {
			conn.rollback();
			System.out.println("turnlog交班日志insert异常");
			log.info("turnlog交班日志insert异常");
			throw e;
		}
	}
	
	public static void insertEvent(MessageConsumer consumer, int waitTime, DBTools db, Connection conn) throws Exception {
		//设置接收者接收消息的时间,为了便于测试,这里谁定为100s
		TextMessage message = (TextMessage) consumer.receive(waitTime);
		try{
			if (null != message) {
				System.out.println("收到消息:" + message.getText());
				Map<String, Object> response = new Gson().fromJson(message.getText(),
					new TypeToken<Map<String, Object>>() {}.getType());
				List<Map<String, Object>> mapList = (List<Map<String, Object>>) response.get("eventlogs");
			
				String insertKey = " INTO eventlog (USERNAME, EVENTTIME, MACHID, EVENT, STATUS, RECEIPTID, AMOUNT, "
						+ "GOODSCODE, QTY, ACCREDIT, TRANMODE, TYPE, STOREID) VALUES ";
				String insertSql = "INSERT ALL ";
				for (Map<String, Object> map : mapList) {
					insertSql += insertKey;
					insertSql += "('" + map.get("UserName") + "', '"
						+ map.get("EventTime") + "', '"
						+ map.get("MachID") + "', '"
						+ map.get("Event") + "', "
						+ map.get("Status") + ", '"
						+ map.get("ReceiptID") + "', "
						+ map.get("Amount") + ", '"
						+ map.get("GoodsCode") + "', "
						+ map.get("Qty") + ", "
						+ "NULL, "
						+ "NULL, "
						+ "NULL, '"
						+ map.get("StoreID") + "'), ";
				}
				insertSql = insertSql.substring(0, insertSql.lastIndexOf(","));
				insertSql += insertEnd;
				System.out.println("insertSql:" + insertSql);
				
				db.excuteSql(insertSql);
				conn.commit();
			}
		} catch(Exception e) {
			conn.rollback();
			System.out.println("turnlog交班日志insert异常");
			log.info("turnlog交班日志insert异常");
			throw e;
		}
	}
	
	public static void insertSales(MessageConsumer consumer, int waitTime, DBTools db, Connection conn) throws Exception {
		//设置接收者接收消息的时间,为了便于测试,这里谁定为100s
		TextMessage message = (TextMessage) consumer.receive(waitTime);
		try{
			if (null != message) {
				System.out.println("收到消息:" + message.getText());
				Map<String, Object> response = new Gson().fromJson(message.getText(),
					new TypeToken<Map<String, Object>>() {}.getType());
				
				// 获取当前时间
				SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 设置日期格式
				String now = df.format(new Date());// new Date()为获取当前系统时间
				
				List<Map<String, Object>> mapList1 = (List<Map<String, Object>>) response.get("purchase");
				String insertKey1 = "INSERT ALL INTO purchase (STOREID, BUYDATE, RECEIPTID, BUYTYPE, STATUS, BUYTIME, PAYEE, TOTALAMOUNT, "
						+ "TOTALDISCOUNT, DISCOUNT, CUSTOMERID, RETURNREASON, TURN, INVNO, MEMO, DAILYDATE, CREATEDATE, UPLOADTIME) VALUES ";
				String insertSql1 = "INSERT ALL ";
				for (Map<String, Object> map : mapList1) {
					insertSql1 += insertKey1;
					insertSql1 += "('" + map.get("StoreID") + "', '"
						+ map.get("BuyDate") + "', '"
						+ map.get("ReceiptID") + "', '"
						+ map.get("BuyType") + "', "
						+ map.get("Status") + ", '"
						+ map.get("BuyTime") + "', '"
						+ map.get("CasherID") + "', "
						+ map.get("TotalAmount") + ", "
						+ map.get("TotalDiscount") + ", "
						+ map.get("Discount") + ", '"
						+ map.get("MemCard") + "', '"
						+ map.get("ReturnReason") + "', "
						+ map.get("Turn") + ", '"
						+ map.get("InvNO") + "', "
						+ "NULL, "
						+ "NULL, '"
						+ now + "', '"
						+ now + "'), ";
				}
				insertSql1 = insertSql1.substring(0, insertSql1.lastIndexOf(","));
				insertSql1 += insertEnd;
				System.out.println("insertSql1:" + insertSql1);
				db.excuteSql(insertSql1);
				conn.commit();
				
				List<Map<String, Object>> mapList2 = (List<Map<String, Object>>) response.get("purchaseitem");
				String insertKey2 = "INSERT INTO purchaseitem (BUYDATE, RECEIPTID, ORD, GOODSID, QTY, PRICE, AMOUNT, "
						+ "DEPOSIT, COUNTERID, SALESMAN, DIS, RETFLAG, MEMO, BARCODE, STOREID, CREATEDATE) VALUES ";
				String insertSql2 = "INSERT ALL ";
				for (Map<String, Object> map : mapList2) {
					insertSql2 += insertKey2;
					insertSql2 += "('" + map.get("BuyDate") + "', '"
						+ map.get("ReceiptID") + "', "
						+ map.get("Ord") + ", "
						+ map.get("GoodsID") + ", "
						+ map.get("Qty") + ", "
						+ map.get("Price") + ", "
						+ map.get("Amount") + ", "
						+ map.get("Deposit") + ", "
						+ "NULL, '"
						+ map.get("CasherID") + "', "
						+ map.get("Dis") + ", "
						+ map.get("RetFlag") + ", "
						+ "NULL, '"
						+ map.get("BarCode") + "', '"
						+ map.get("StoreID") + "', '"
						+ now + "'), ";
				}
				insertSql2 = insertSql2.substring(0, insertSql2.lastIndexOf(","));
				insertSql2 += insertEnd;
				System.out.println("insertSql2:" + insertSql2);
				db.excuteSql(insertSql2);
				conn.commit();
				
				List<Map<String, Object>> mapList3 = (List<Map<String, Object>>) response.get("payment");
				String insertKey3 = "INSERT INTO payment (BUYDATE, RECEIPTID, ORD, PAYWAY, "
						+ "PAYAMOUNT, CARDID, RATIO, STOREID, CREATEDATE, PROPERTY) VALUES ";
				String insertSql3 = "INSERT ALL ";
				for (Map<String, Object> map : mapList3) {
					insertSql3 += insertKey3;
					insertSql3 += "('" + map.get("BuyDate") + "', '"
						+ map.get("ReceiptID") + "', "
						+ map.get("Ord") + ", '"
						+ map.get("TypeCode") + "', "
						+ map.get("PayAmount") + ", '"
						+ map.get("CardID") + "', "
						+ map.get("Ratio") + ", '"
						+ map.get("StoreID") + "', '"
						+ now + "', "
						+ map.get("Property") + "), ";
				}
				insertSql3 = insertSql3.substring(0, insertSql3.lastIndexOf(","));
				insertSql3 += insertEnd;
				System.out.println("insertSql3:" + insertSql3);
				db.excuteSql(insertSql3);
				conn.commit();
			}
		} catch(Exception e) {
			conn.rollback();
			System.out.println("purchase销售数据insert异常");
			log.info("purchase销售数据insert异常");
			throw e;
		}
	}
}

RabbitMQ的话和Active差不多啦。这里就只举例发送者的例子。这里用到了一个工具类。
发送者

package cn.com.winpeace.quartz;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.hibernate.SQLQuery;
import org.hibernate.criterion.CriteriaSpecification;

import com.google.gson.Gson;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import cn.com.winpeace.dao.Dao;
import cn.com.winpeace.dao.DaoFactory;
import cn.com.winpeace.util.DateUtil;
import cn.com.winpeace.util.FileUtil;
import cn.com.winpeace.util.Propeller;
import cn.com.winpeace.util.PropertiesUtils;
import cn.com.winpeace.util.RabbitMQUtil;

/**
 * @ClassName: ToXbrainAsysRealSale
 * @Description: 实时销售数据发送至B系统
 * @author: YPF
 * @date: 2019年1月15日 下午3:45:58
 */
public class ToXbrainAsysRealSale {

	// 获取类名
	private String className = this.getClass().getSimpleName();
	// log输出
	private static final Logger logger = Logger.getLogger(ToXbrainAsysRealSale.class);
	DateUtil dateUtil=new DateUtil();
	// 获取当前时间
	private  String curTime = dateUtil.getDateToMinute();

	/**
	 * 
	 * @Title: 实时销售数据发送至B系统
	 * @Description: 主程序入口
	 * @throws Exception
	 *             void
	 * @author YPF
	 * @date 2019年1月15日下午3:50:17
	 */
	public synchronized void excute() throws Exception {
		// 获取上次发送时间
		String fileUrl = PropertiesUtils.getProperty("common.properties", "toxbrain_asys_fileurl");
		Propeller pro = FileUtil.getPropellerFile(fileUrl, className);

		logger.info(className + " 实时销售数据发送至B系统started...");
		if (pro == null) {
			throw new Exception("上次上传时间读取为空....");
		}
		logger.info("从文件读取数据为-->>" + pro);

		/**
		 * 使用RabbitMQ发送到消息队列当中
		 */
		Channel channel = null;
		Connection conn = null;
		try {
			ConnectionFactory connectionFactory = RabbitMQUtil.getConnectionFactory();
			conn = RabbitMQUtil.getConnection(connectionFactory);

			// 创建信息管道
			channel = conn.createChannel();
			String queueName = "asysRealSaleOrder";
			// 声明队列
			channel.queueDeclare(queueName, true, false, false, null);
			// 发送消息
			sendMessageRealSaleOrder(channel, queueName, pro);
			

			logger.info(className + "实时销售数据  发送成功。");
			//更新文件时间上传时间
			FileUtil.updatePropellerFile(curTime, fileUrl, className);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 关闭连接、通道
			if (channel != null) {
				channel.close();
			}
			if (conn != null) {
				conn.close();
			}

		}

	}

	/**
	 * @Title: sendMessageRealWarehouseStock
	 * @Description: 实时销售数据主档消息主方法
	 * @param channel
	 * @param queueName
	 * @param pro
	 * @throws Exception
	 *             void
	 * @author YPF
	 * @date 2019年1月15日下午5:32:34
	 */
	public void sendMessageRealSaleOrder(Channel channel, String queueName, Propeller pro) throws Exception {

		Dao<?> dao = DaoFactory.getDefaultDao();

		long startT = System.currentTimeMillis();
		logger.info("*************************** data time : " + startT);
		
		// 取得数据库数据做成JSON传输
		try {
			String condition = " BETWEEN  to_date('" + pro.getUploadTime() + "','yyyy-MM-dd :hh24:mi:ss') AND to_date('"
					+ curTime + "','yyyy-MM-dd :hh24:mi:ss') ";

			StringBuffer sqlPurchase = new StringBuffer();
			sqlPurchase.append("select ");
			sqlPurchase.append(" o.storeid as storeid, ");
			sqlPurchase.append(" TO_CHAR(o.uploadtime, 'YYYY-MM-DD HH24:MI:SS') as uploadtime");
			sqlPurchase.append(" from real_if_purchase o ");
			sqlPurchase.append(" where  ");
			sqlPurchase.append(" o.updatetime " + condition + " ");
			SQLQuery sqlPurchaseQuery = dao.createSQLQuery(sqlPurchase.toString());
			sqlPurchaseQuery.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
			List<Map<String, Object>> purchaseList = sqlPurchaseQuery.list();

			logger.info("----实时销售数据发送至B系统头档取得-----");

			StringBuffer sqlPurchaseItem = new StringBuffer();
			sqlPurchaseItem.append("select ");
			sqlPurchaseItem.append(" d.storeid as storeid, ");
			sqlPurchaseItem.append(" d.BARCODE as barcode ");
			sqlPurchaseItem.append(" from real_if_purchase o ,real_if_purchaseitem d");
			sqlPurchaseItem.append(" where  ");
			sqlPurchaseItem.append(" o.updatetime " + condition + " ");
			SQLQuery sqlPurchaseItemQuery = dao.createSQLQuery(sqlPurchaseItem.toString());
			sqlPurchaseItemQuery.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
			List<Map<String, Object>> purchaseItemList = sqlPurchaseItemQuery.list();

			logger.info("----实时销售数据发送至B系统明细取得-----");

			StringBuffer sqlPayment = new StringBuffer();
			sqlPayment.append("select ");
			sqlPayment.append(" d.storeid as storeid, ");
			sqlPayment.append(" d.payamount as payamount ");
			sqlPayment.append(" from real_if_purchase o ,real_if_payment d");
			sqlPayment.append(" where  ");
			sqlPayment.append(" o.updatetime " + condition + " ");
			SQLQuery sqlPaymentQuery = dao.createSQLQuery(sqlPayment.toString());
			sqlPaymentQuery.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
			List<Map<String, Object>> payMentList = sqlPaymentQuery.list();

			logger.info("----实时销售数据发送至B系统支付方式取得-----");

			if (purchaseList == null || purchaseList.isEmpty()) {
				logger.info("---实时销售数据不存在!---");
				return;
			}

			int headCnt = purchaseList.size();
			int itemCnt = purchaseItemList.size();
			int payCnt = payMentList.size();
			
			// 作成传输数据
			Map<String, Object> data = new HashMap<String, Object>();
			data.put("header", purchaseList);
			data.put("items", purchaseItemList);
			data.put("payment", payMentList);
			
			// 转为json数据
			Gson gson = new Gson();
			String dataStr = gson.toJson(data);

			// 发送到消息目的地
			channel.basicPublish("xbrain", queueName, null, dataStr.getBytes());
			long endT = System.currentTimeMillis();
			long minutes = ((endT-startT)/1000)/60;
			long second = ((endT-startT)/1000)%60; 
			logger.info("**********实时销售数据 start--end :"+pro.getUploadTime()+"--"+curTime+" ==总件数header:"+headCnt+" 总件数item:"+itemCnt
					+" 总件数payment:"+payCnt+" 执行时间:"+minutes+"分"+second+"秒");
		} catch (Exception e) {
			logger.info("实时销售数据同步接口程序  发送异常!");
			logger.info(e.getMessage());
			e.printStackTrace();
			throw new Exception();
		}
	}
}

尤其注意工具类URL设置方式。网上的教程试了好多次还是没好用。
工具类

package cn.com.winpeace.util;

import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import org.jboss.security.auth.spi.Users.User;

import com.rabbitmq.client.Channel; 
import com.rabbitmq.client.Connection; 

/**
 * RabbitMQ队列工具类
 * @ClassName: RabbitMQUtil 
 * @Description: TODO
 * @author: YPF
 * @date: 2018年11月23日 下午5:49:28
 */
public class RabbitMQUtil {
	
	public  static String   username = PropertiesUtils.getProperty("common.properties", "username");
	public static String password = PropertiesUtils.getProperty("common.properties", "password");
	public static String ip = PropertiesUtils.getProperty("common.properties", "ip");
	
	public static ConnectionFactory getConnectionFactory() throws KeyManagementException, NoSuchAlgorithmException, URISyntaxException {
		ConnectionFactory connection =new ConnectionFactory();
		connection.setUri("amqp://" + username + ":" + password + "@" + ip + ":5672/xbrain");
		return connection;
	}
	
	public static Connection getConnection(ConnectionFactory confactory ) throws IOException {
		return confactory.newConnection();
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值