一、springboot版本和依賴
- springboot 版本 2.1.5
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
- dependencies
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
二、生產端
1、yml 文件配置
server:
port: 8001
servlet:
context-path: /
spring:
rabbitmq:
addresses: ip:5672,ip:5672,ip:5672
username: guest
password: guest
virtual-host: /
connection-timeout: 15000
publisher-confirms: true
publisher-returns: true
template:
mandatory: true
application:
name: rabbit-producer
http:
encoding:
charset: UTF-8
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: NON_NULL
rabbitmq-exchange: exchange-1
rabbitmq-routingKey: springboot.abc
- address server的ip地址加上端口號
- username passowrd 賬號密碼
- virtual-host 最上層的一個域 ,例如 /order /logistics
- 連接超時時間
- 生產端的相關配置
- publisher-confirms 是否開啓消息確認模式,舉例:生產者發送消息到 broker(mq) ,我不確定我的消息是否100%已經投遞到mq 中,我們會進行線程監聽,mq 會返回一個成功或者是失敗的情況
- publisher-returns 是否開啓發布者退貨模式,舉例:生產者發送routingkey: spring.xxx ,queue routingkey:爲 springboot.xxx 。那麼不匹配路由規則。publisher-returns 設置爲false 的話,這條消息就丟掉了,消失了。設置爲true的話,會將消息 執行到我們指定的一對 exchange 和 queue 上。 需要和 mandatory 一起使用
- mandatory 是否開啓強制性消息
2、編寫發送消息方法
package com.example.producer.component;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.UUID;
/**
* @Author: qiuj
* @Description:
* @Date: 2020-05-31 11:57
*/
@Component
public class Sender {
@Autowired
private RabbitTemplate rabbitTemplate;
@Value("${rabbitmq-exchange}")
private String exchange;
@Value("${rabbitmq-routingKey}")
private String routingKey;
/**
* 這裏就是確認消息的回調監聽接口,用於確認消息是否被broker 所收到
*/
final RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
System.out.println("唯一id:" + correlationData);
System.out.println("消息是否成功投遞" + ack );
System.out.println("如果失敗則會返回錯誤消息" + cause);
}
};
public void sends (Object msg, Map<String,Object> properties) {
// 第一步將消息包裝成boot 支持的方式
MessageHeaders messageHeaders = new MessageHeaders(properties);
Message<?> message = MessageBuilder.createMessage(msg,messageHeaders);
// 指定唯一id
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
// 回調方法
MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
@Override
public org.springframework.amqp.core.Message postProcessMessage(org.springframework.amqp.core.Message message) throws AmqpException {
System.out.println("在發送消息之前的前置方法" + message);
return message;
}
};
// 前置方法
rabbitTemplate.setConfirmCallback(confirmCallback);
rabbitTemplate.convertAndSend(exchange,
routingKey,
message,
messagePostProcessor,
correlationData);
}
}
三、消費端
1、yml 文件配置
server:
port: 8002
spring:
rabbitmq:
addresses: ip:5672,ip:5672,ip:5672
username: guest
password: guest
virtual-host: /
connection-timeout: 15000
listener:
simple:
acknowledge-mode: manual
concurrency: 5
max-concurrency: 10
prefetch: 2
application:
name: rabbit-consumer
http:
encoding:
charset: UTF-8
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: NON_NULL
queue-name: queue-1
queue-durable: true
exchange-name: exchange-1
exchange-topic: topic
exchange-durable: true
exchange-ignoreDeclarationExceptions: true
routingkey: springboot.*
- 消費端的相關配置
- acknowledge-mode 默認auto ,也就是自動簽收消息,生產環境不建議,我們設置爲 manual 手工的進行簽收
- concurrency max-concurrency 監聽器調用線程的最小數量 和最大數量
- prefetch 在單個請求中處理的消息個數,開啓限流,指定每次處理消息最多隻能處理2條消息
2、編寫接受消息方法
package com.example.consumer.component;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* @Author: qiuj
* @Description:
* @Date: 2020-05-30 19:29
*/
@Component
public class RabbitReceive {
/**
* 組合使用監聽
* @RabbitListener @QueueBinding @Queue @Exchange
* @param message
* @param channel
* @throws IOException
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "${queue-name}",durable = "${queue-durable}"),
exchange = @Exchange(
value = "${exchange-name}",
type = "${exchange-topic}",
durable = "${exchange-durable}",
ignoreDeclarationExceptions = "${exchange-ignoreDeclarationExceptions}"
),
key = "${routingkey}"
))
@RabbitHandler
public void onMessage (Message message, Channel channel) throws IOException {
// 1:收到消息以後進行業務端處理
System.out.println("消費消息:" + message.getPayload());
// 2:處理成功之後 獲取deliveryTag 並進行手工的ACK操作,因爲我們配置文件裏配置的是 手工簽收
// spring.rabbitmq.listener.simple.acknowiedge-mode=manual
Long deliveryTag = (Long) message.getHeaders().get(AmqpHeaders.DELIVERY_TAG);
channel.basicAck(deliveryTag,false);
}
}