一.数据持久化
1.队列持久化
//队列申明,durable:true队列持久化
channel.queueDeclare(Constant.QUEUE_NAME, true, false, false, null);
2.消息持久化
/**
* exchange:名称
*
* routingKey:路由键,#匹配0个或多个单词,*匹配一个单词,在topic exchange做消息转发用
*
* mandatory:为true时如果exchange根据自身类型和消息routeKey无法找到一个符合条件的queue,那么会调用basic.return方法将消息返还给生产者。
* (默认为false)false时出现上述情形broker会直接将消息扔掉
*
* immediate:为true时如果exchange在将消息route到queue(s)时发现对应的queue上没有消费者,那么这条消息不会放入队列中。
* 当与消息routeKey关联的所有queue(一个或多个)都没有消费者时,该消息会通过basic.return方法返还给生产者。
* <P>MessageProperties.PERSISTENT_TEXT_PLAIN</>
*
* props:需要注意的是BasicProperties.deliveryMode,1:不持久化 2:持久化 这里指的是消息的持久化,
* 配合channel(durable=true),queue(durable)可以实现,即使服务器宕机,消息仍然保留
* BasicProperties:
* private String contentType; // content-type属性用于描述消息体的数据格式 如 JSON = application/json
* private String contentEncoding;
* private Map<String, Object> headers;
* private Integer deliveryMode; // 表示在将消息投递给任何消费者之前,是否希望先将它持久化到磁盘上,1表示非持久化消息,2表示持久化消息。
* private Integer priority; // 用于指定队列中消息的优先级
* private String correlationId;
* private String replyTo;
* private String expiration; // 设置消息的有效期,超过10秒没有被消费者接收后会被自动删除
* private String messageId;
* private Date timestamp;
* private String type;
* private String userId; // 携带一些信息以便消费者应用程序在处理消息之前进行验证
* private String appId; // 携带一些信息以便消费者应用程序在处理消息之前进行验证
* private String clusterId;
*
* body:要发送的信息
*/
channel.basicPublish("", Constant.QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, eCriminal.getZfbaCode().getBytes());
二.消费者设置
1.启用Qos和ack机制
//同一时刻服务器只发送1条消息给消费者(能者多劳,消费消息快的,会消费更多的消息)
//当RabbitMQ的队列达到1条Unacked消息时,不会再推送消息给Consumer
//保证在接收端一个消息没有处理完时不会接收另一个消息,即消费者端发送了ack后才会接收下一个消息。
//在这种情况下生产者端会尝试把消息发送给下一个空闲的消费者。
channel.basicQos(1);
//声明队列的消费者O
Consumer consumer1 = new DefaultConsumer(channel){
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println("customerA 消费消息:"+message);
try {
dataHandle.consumerDataHandle(message);
}catch (Exception e){
// 业务处理的异常应该捕获 另外保存
log.error("customerA 消费消息异常:{}",message);
}
//手动返回结果: 一定要放在最后 通过该方法后 就算手动ack 该消息被消费成功;在这之前的异常,都会把当前消费数据返回队列
// channel.basicQos(1);==> 如果不处理数据 业务异常 数据 会阻塞继续消费
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
//定义的消费者监听队列 autoAck:true自动返回结果,false手动返回
channel.basicConsume(Constant.QUEUE_NAME, false,consumer1);