项目结构
项目依赖jar包
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.12</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--AMQP依赖,包含RabbitMQ-->
<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>
</dependency>
<!--Jackson-->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
</dependencies>
生产者代码
启动类:
/**
* @author 南风
* @create 2024/6/5 17:10
*/
@Configuration
@Slf4j
public class MqConfirmConfig implements ApplicationContextAware {
/**
* 可以不要 return 回调
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
RabbitTemplate bean = applicationContext.getBean(RabbitTemplate.class);
bean.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
@Override
public void returnedMessage(ReturnedMessage returned) {
System.out.println("收到消息的return callback"+returned.getMessage() +returned.getExchange() +returned.getRoutingKey() +returned.getReplyCode() +returned.getReplyText());
}
});
}
}
application.yml配置文件
spring:
rabbitmq:
host: 192.168.248.135
port: 5672
username: guest
password: guest
# 消息的回调机制 异步执行
publisher-confirm-type: correlated
# 回调机制
publisher-returns: true # 消息是否投递成功 建议关闭
connection-timeout: 1s
生产者发送消息:
@SpringBootTest
public class SpringAmqpTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void testSendMessage2Queue() {
String queueName = "simple.queue";
String msg = "hello, amqp!";
rabbitTemplate.convertAndSend(queueName, msg);
System.out.println("发送成功");
}
@Test
void testSendMessageWorkQueue() {
String queueName = "work.queue";
for (int i=0;i < 50;i++ ) {
String msg = "work, queue!————————"+i;
rabbitTemplate.convertAndSend(queueName, msg);
}
}
@Test
void testSendMessageFanoutExchange() {
String msg = "hello, fanout!";
String exchangeName = "fanout";
rabbitTemplate.convertAndSend(exchangeName, "", msg);
}
@Test
void testSendMessageDirectExchange() {
String msg = "hello, direct!";
String exchangeName = "direct";
rabbitTemplate.convertAndSend(exchangeName, "yellllow", msg);
}
@Test
void testSendMessageTopicExchange() {
String msg = "hello, topic!";
String exchangeName = "topic";
rabbitTemplate.convertAndSend(exchangeName, "yellllow.blue", msg);
}
/**
* 消息的确认机制
*/
@Test
void testSendMessageDirectExchangeAck() throws InterruptedException {
String msg = "hello, direct!";
String exchangeName = "direct1";
CorrelationData correlationData = new CorrelationData();
correlationData.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
@Override
public void onFailure(Throwable ex) {
System.out.println("消息回调失败" +ex);
}
@Override
public void onSuccess(CorrelationData.Confirm result) {
if(result.isAck()){
System.out.println("消息重试 消息发送成功");
}else {
System.out.println("消息重试发送失败 需要进行重试" +result.getReason());
}
}
});
CorrelationData cd = new CorrelationData();
cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
@Override
public void onFailure(Throwable ex) {
System.out.println("消息回调失败" +ex);
}
@Override
public void onSuccess(CorrelationData.Confirm result) {
if (result.isAck()) {
System.out.println("消息发送成功");
} else {
System.out.println("消息发送失败 需要进行重试" +result.getReason());
rabbitTemplate.convertAndSend("direct", "yellllow", "消息重发",correlationData);
}
}
});
rabbitTemplate.convertAndSend(exchangeName, "yellllow", msg,cd);
Thread.sleep(2000);
}
}
消费者
启动类:
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
public MessageConverter jacksonMessageConvertor(){
Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
/**
* 唯一id
*/
jackson2JsonMessageConverter.setCreateMessageIds(true);
return jackson2JsonMessageConverter;
}
}
配置文件:
spring:
rabbitmq:
host: 192.168.248.135
port: 5672
# virtual-host: my_vhost
username: guest
password: guest
listener:
simple:
prefetch: 1 # 每次从队列中获取的消息数量 消费完1条消息才能再从队列中获取
concurrency: 1 # 并发消费数量
acknowledge-mode: auto
retry:
enabled: true
max-attempts: 3
multiplier: 1
initial-interval: 1000ms
stateless: true
消息的补充机制 处理消息重试失败后的配置
**
* @author 南风
* @create 2024/6/7 10:26 处理消息重试失败后的配置
*/
@Configuration
@ConditionalOnProperty(prefix = "spring.rabbitmq.listener.simple.retry", havingValue = "true",name = "enabled")
public class ErrorDirectConfig {
@Bean
public DirectExchange errorDirectExchange() {
return new DirectExchange("error.direct.exchange");
}
@Bean
public Queue errorQueue() {
return new Queue("error.queue");
}
@Bean
public Binding bindingErrorQueue() {
return BindingBuilder.bind(errorQueue()).to(errorDirectExchange()).with("error");
}
@Bean
public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate) {
return new RepublishMessageRecoverer(rabbitTemplate, "error.direct.exchange", "error");
}
}
消息的消费者:
@Slf4j
@Component
public class MqListener {
@RabbitListener(queues = "simple.queue")
public void listenSimpleQueue(String msg){
System.out.println("消费者收到了simple.queue的消息:【" + msg +"】");
throw new RuntimeException("出异常了");
}
@RabbitListener(queues = "work.queue")
public void listenWorkQueue1(String msg){
System.out.println("work1消费者收到了work.queue的消息:【" + msg +"】");
}
@RabbitListener(queues = "work.queue")
public void listenWorkQueue2(String msg) throws InterruptedException {
System.err.println("work2消费者收到了work.queue的消息:【 "+ msg +"】");
Thread.sleep(200);
}
@RabbitListener(queues = "fanout.queue1")
public void listenFanoutQueue1(String msg) throws InterruptedException {
System.err.println("fanout.queue1收到了消费者的消息:【 "+ msg +"】");
}
@RabbitListener(queues = "fanout.queue2")
public void listenFanoutQueue2(String msg) throws InterruptedException {
System.err.println("fanout.queue2收到了消费者的消息:【 "+ msg +"】");
}
@RabbitListener(queues = "direct.queue1")
public void listenDirectQueue1(String msg) {
System.err.println("direct.queue1收到了消费者的消息:【 "+ msg +"】");
}
@RabbitListener(queues = "direct.queue2")
public void listenDirectQueue2(String msg) {
System.err.println("direct.queue2收到了消费者的消息:【 "+ msg +"】");
}
@RabbitListener(queues = "topic.queue1")
public void listenTopicQueue1(String msg) {
System.err.println("topic.queue1收到了消费者的消息:【 "+ msg +"】");
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "topic.queue2", durable = "true"),
exchange = @Exchange(name = "topic", type = ExchangeTypes.TOPIC),
key = {"#.blue"}))
public void listenTopicQueue2(String msg) {
System.err.println("topic.queue2收到了消费者的消息:【 "+ msg +"】");
}
}