目录[-]
Rabbit需求文档
1、消息平台的背景
随着系统之间的数据交互越来越频繁,系统之间需要进行异步通信,如何降低系统之间耦合度,实现各系统之间的数据异步交互,通信并且不影响平台正常运行,已经成为我们的越来越重视的环节之一,为此,我们采用目前主流消息中间件RabbitMQ来实现我们系统的异步通讯。
RabbitMQ是基于AMQP协议标准来实现,AMQP主要是面向消息、队列、路由的消息队列协议,具有一定的安全性和可靠性,RabbitMQ用于在分布式系统中存储转发消息,有良好的易用性、扩展性、安全性以及高可用性等。
2、消息平台的使用
2.1使用须知
2.1.1Exchange(交换器):
一个exchange可以绑定多个消息队列,消息队列又可以绑定routekey,用户发布消息是通过这个交换器去指定为哪一个消息队列做消息持久化保存(持久化可以设置),当不指定routekey,那么就默认向所有绑定这个exchange的queue中发送消息,如果有就到绑定了该routekey的queue中发送消息,exchange、queue、route以及绑定关系需要通过中间平台去定义,不建议开发者在代码里去创建对应关系
MessageQueue(消息队列):消息队列,存储消息
route:路由
2.1.2系统使用说明
系统接收方:各个系统可以向RabbitMQ平台申请创建N个队列,用来接收来自其他系统传递的消息我们的队列都是持久化类型的队列以确保接收的数据能够durable,一个队列可以接收不同publisher传递的消息,也可以是指定publisher传递的消息,规则看上文
客户端启动监听程序,接收来自RabbitMQ服务器传来的指定队列存储的消息,目前消息传输类型为Bytes(大小?),用户可以设置接收消息条数,可以设置回执,如果不回执,系统不会再次接收消息,监听断开,消息重新放回待读取区
消息发送方:
用来向相应的队列传输消息,可以指定某个队列,也可以指定exchange绑定的队列,也可以是带有route规则的队列,目前根据现在的需求,exchange的 direct类型已经可以实现目前的基本业务需求了,如果今后需要拓展,再根据相应需求去完善
2.2传输类型
不得不说,Exchange传输有以下几种类型:
2.2.1 fanout:
通过exchange传输数据到绑定队列,如果没有队列绑定到该exchange上面,那么消息自动删除
2.2.2 direct:
通过exchange、routekey去匹配消息队列,规则是匹配exchange,然后查找绑定的queues是否有相同的routekey,如果相同则向该队列保存消息
2.2.3 topic:
和direct类型大体是一样的匹配规则,不同的是topic类型的routekey可以传递 “.*”,“.#”位置 “*”、“#”位置可以不固定,通配符*指定的是一个单词,#可以指定多个单词,也可是零个
具体实列代码:
3.1 publisher
3.1.1 说明
A、 channel.exchangeDeclare(EXCHANGE_NAME, "direct", true);
用于创建exchange的,参数1:exchange名称,参数2:exchange类型,参数3:exchange是否持久化,也就是断线会自动保存。
B、 channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
发送消息的具体实现方法,
参数1:队列名
参数2:routekey
说明:routekey如果为空字符串“”,那么就默认发送到exchange所绑定的queue,如果指定routekey,那么在exchange传递数据时,会添加routekey过滤,也就是说队列既要满足绑定exchange也要满足绑定routekey值匹配(用户可以在queue里面绑定routekey和exchange)
参数3:AMQP.BasicProperties AMQP基本参数,请看文档
参数4:消息内容
C、 channel.close(); 关闭连接
connection.close();
3.1.2 代码
public static final String EXCHANGE_NAME = "zidingyi";
public static boolean sendMsg(String message) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("guest");//用户名
factory.setPassword("guest");//密码
factory.setPort(5672);//端口号
factory.setHost("localhost");//ip
Connection connection = null;
Channel channel = null;
try {
connection = factory.newConnection();//创建连接工厂
channel = connection.createChannel();//创建通道
// 创建exchange,第二个参数是类型 第三个 持久化
// channel.exchangeDeclare(EXCHANGE_NAME, "direct", true);
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
channel.close();
connection.close();
}
return true;
}
3.2 consumer
3.2.1 说明
A、 channel.basicQos(4);
从消息队列里面每次请求四条数据
B、 doWork(message);
这里是我们对这条消息做业务处理用的,方法名可以自定义
C、 factory.setAutomaticRecoveryEnabled(true)
当网络出现问题时,可以实现自行恢复
D、 channel.basicAck(envelope.getDeliveryTag(), false);
参数1:回发ACK 参数 tag,参数2:是否多个
E、 channel.basicConsume("zidingyi2", false, consumer);
参数1:队列名
参数2:是否需要回执true/fasle 需要/不需要
参数3:消费者
F、 envelope.getDeliveryTag()
3.2.2 代码
public static void getMsg() throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
channel.basicQos(4);
final Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
try {
doWork(message);
} finally {
System.out.println(" [x] Done");
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
channel.basicConsume("zidingyi2", false, consumer);
// /**
// * 第二个参数设置是否回执
// */
// channel.basicConsume("zidingyi2", true, consumer);
}
private static void doWork(String task) {
for (char ch : task.toCharArray()) {
if (ch == '.') {
try {
Thread.sleep(1000);
} catch (InterruptedException _ignored) {
Thread.currentThread().interrupt();
}
}
}
}