1、JSON序列化與反序列化
要實現消息跨平臺,需要配置消息JSON序列化(配置見代碼實現),就可以實現不同語言之間互相發送/接收消息,還可以直接用RabbitMQ控制檯發送消息。
從RabbitMQ控制檯發送消息,指定properties content_type=application/json
2、消息重試機制
見application.yml配置文件,手動模式下,當消費端消費拋異常時,消息會進行重試。消息等待重試時,會阻塞,直到重試都失敗後,纔會消費下一條消息。
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
application.yml
spring:
rabbitmq:
addresses: localhost:5672
username: guest
password: guest
publisher-confirms: true #推送確認
publisher-returns: true #推送退回
listener:
simple:
acknowledge-mode: MANUAL # 手動確認模式
prefetch: 10000 #最多允許多少個未應答
retry:
enabled: true #是否開啓消費者重試(爲false時關閉消費者重試,這時消費端代碼異常會一直重複收到消息)
max-attempts: 3 #最大重試次數
initial-interval: 10S #重試間隔時間,如果重試間隔大於10S,必須設置最大重試間隔,否則只能小於等於10S
max-interval: 10S #最大重試間隔時間,默認10S
RabbitTemplateConfig.java
@Slf4j
@Configuration
public class RabbitTemplateConfig implements RabbitTemplate.ConfirmCallback , RabbitTemplate.ReturnCallback{
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory;
@PostConstruct
public void init() {
//指定 ConfirmCallback
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.setReturnCallback(this);
// 使用 JSON 序列化與反序列化
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
rabbitListenerContainerFactory.setMessageConverter(new Jackson2JsonMessageConverter());
}
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if(!ack){
log.info("發送MQ消息失敗,ID:{}, 原因: {}", correlationData.toString(), cause);
}
}
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
log.info("發送MQ消息回退: {}, {}, exchange:{}, routing:{}" + JSON.toJSONString(message), replyCode, exchange, routingKey);
}
}
Hello1Receiver.java
/**
* 普通模式消費端
*/
@Slf4j
@Component
public class Hello1Receiver {
@RabbitListener(queuesToDeclare = @Queue("hello")) // 需要注意,改註解要寫在方法上,不然JSON序列化會失效
public void process(Hello bean, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws Exception {
// TODO 業務邏輯
TimeUnit.SECONDS.sleep(2);
// 手動確認
channel.basicAck(tag, false);
log.info("hello1消息消費成功params:{}", JSON.toJSONString(bean));
}
}
TopicReceiver.java
/**
* topic模式消費端
*/
@Slf4j
@Component
public class TopicReceiver {
@RabbitListener(bindings = @QueueBinding(
exchange = @Exchange(value = "topic.exchange",type = "topic"),
value = @Queue(value = "consumer_queue"),
key = "key.#"
))
public void key(Hello bean, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws Exception {
// TODO 業務邏輯
// 手動確認
channel.basicAck(tag, false);
log.info("topic-key消息消費成功params:{}", JSON.toJSONString(bean));
}
@RabbitListener(bindings = @QueueBinding(
exchange = @Exchange(value = "topic.exchange",type = "topic"),
value = @Queue(value = "consumer_queue"),
key = "value.#"
))
public void value(Hello bean, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws Exception {
// TODO 業務邏輯
// 手動確認
channel.basicAck(tag, false);
log.info("topic-value消息消費成功params:{}", JSON.toJSONString(bean));
}
}
HelloProducerTest.java
public class HelloProducerTest extends BasicTest{
@Autowired
private AmqpTemplate amqpTemplate;
@Test
public void sendTest() throws Exception {
for (int i = 0; i < 10; i++) {
Hello bean = Hello.builder()
.id(i)
.title("hello")
.content("你好")
.build();
amqpTemplate.convertAndSend("hello", bean);
}
TimeUnit.SECONDS.sleep(5);
}
}
TopicProducerTest.java
public class TopicProducerTest extends BasicTest{
@Autowired
private AmqpTemplate amqpTemplate;
@Test
public void sendTest() {
Hello bean = Hello.builder()
.id(1)
.title("hello")
.content("你好")
.build();
amqpTemplate.convertAndSend("topic.exchange", "key.hello", bean );
amqpTemplate.convertAndSend("topic.exchange", "value.hello", bean );
}
}
demo下載
https://download.csdn.net/download/kuyuyingzi/12235976
參考資料:
https://www.rabbitmq.com/getstarted.html
https://www.jianshu.com/p/911d987b5f11