pom文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
Mq配置文件
package com.example.demo.mq.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* @author dlh
* @date 2022/8/2 9:58
*/
@Component
@Slf4j
public class RabbitMqConfig implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback {
@Autowired
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void init() {
//保证消息正确的到达broker
rabbitTemplate.setConfirmCallback(this);
//保证路由正确
rabbitTemplate.setReturnsCallback(this);
}
/**
* 消息消费回调
*
* @param
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack) {
log.info("消息消费成功!!");
} else {
log.error("消息消费失败!", cause);
}
}
@Override
public void returnedMessage(ReturnedMessage returned) {
}
}
交换机及队列绑定关系
package com.example.demo.mq.config;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import java.util.HashMap;
import java.util.Map;
/**
* 交换机与队列及绑定关系
*
* @author dlh
* @date 2022/8/2 8:37
*/
@Configuration
public class BinDingConfig {
@Value("${spring.rabbitmq.host}")
private String host;
@Value("${spring.rabbitmq.port}")
private int port;
@Value("${spring.rabbitmq.username}")
private String username;
@Value("${spring.rabbitmq.password}")
private String password;
/**
* 获取连接工厂
*
* @return
*/
@Bean
public CachingConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost("/");
return connectionFactory;
}
/**
* 设置手动ack应答机制
*
* @return
*/
@Bean(name = "singleListenerContainer")
public SimpleRabbitListenerContainerFactory listenerContainerFactory() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setConcurrentConsumers(1);
//最大并发消费者
factory.setMaxConcurrentConsumers(10);
factory.setPrefetchCount(1);
factory.setDefaultRequeueRejected(true);
//手动确认。
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
return factory;
}
/**
* 初始化mq
*
* @return
*/
@Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());
return rabbitTemplate;
}
/* 正常配置 **********************************************************************************************************/
/**
* 正常交换机,开启持久化
* 注意一个交换机可以有多个队列.........
*/
@Bean
DirectExchange normalExchange() {
return new DirectExchange("normalExchange", true, false);
}
@Bean
public Queue normalQueue() {
// durable: 是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
// exclusive: 默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
// autoDelete: 是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
Map<String, Object> args = deadQueueArgs();
// 队列设置最大长度
args.put("x-max-length", 5);
//注意队列中的长度到达时会抛弃队列中所有的数据,接收新的数据
args.put("x-message-ttl", 60 * 1000);
return new Queue("normalQueue", true, false, false, args);
}
//原先我这边是配置了两个队列 我为了测试方便所以只使用了一个队列
// @Bean
// public Queue ttlQueue() {
// Map<String, Object> args = deadQueueArgs();
// // 队列设置消息过期时间 60 秒
// args.put("x-message-ttl", 60 * 1000);
// return new Queue("ttlQueue", true, false, false, args);
// }
//
// @Bean
// Binding ttlRouteBinding() {
// return BindingBuilder.bind(ttlQueue()).to(normalExchange()).with("ttlRouting");
// }
@Bean
Binding normalRouteBinding() {
return BindingBuilder.bind(normalQueue()).to(normalExchange()).with("normalRouting");
}
/* 死信配置 **********************************************************************************************************/
/**
* 死信交换机
*/
@Bean
DirectExchange deadExchange() {
return new DirectExchange("deadExchange", true, false);
}
/**
* 死信队列
*/
@Bean
public Queue deadQueue() {
return new Queue("deadQueue", true, false, false);
}
@Bean
Binding deadRouteBinding() {
return BindingBuilder.bind(deadQueue()).to(deadExchange()).with("deadRouting");
}
/**
* 转发到 死信队列,配置参数
*/
private Map<String, Object> deadQueueArgs() {
Map<String, Object> map = new HashMap<>();
// 绑定该队列到私信交换机
map.put("x-dead-letter-exchange", "deadExchange");
map.put("x-dead-letter-routing-key", "deadRouting");
return map;
}
}
消息生产者
package com.example.demo.mq.producer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.UUID;
/**
* @author dlh
* @date 2022/8/2 8:36
*/
@Component
@Slf4j
public class orderProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送消息
*
* @param content
*/
public void sendMsg(String content) {
//设置消息的id
CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("normalExchange", "normalRouting", content, correlationId);
// rabbitTemplate.convertAndSend("normalExchange", "ttlRouting", content, correlationId);
}
}
消费者
package com.example.demo.mq.consumer;
import com.alibaba.fastjson.JSON;
import com.example.demo.log.MsgLog;
import com.rabbitmq.client.MessageProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
import java.io.IOException;
/**
* @author dlh
* @date 2022/8/2 8:36
*/
@Slf4j
@Component
public class orderConsumer {
@RabbitHandler
@RabbitListener(queues = {"ttlQueue","normalQueue"})
public void listenerMsg(Message msg, String content, Channel channel) throws IOException {
log.info("开始处理收到的消息>>>:{}", content);
if (msg.getBody() != null) {
try {
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
log.info("确认收到消息手动ack成功~:{}");
} catch (IOException e) {
log.error("手动ack时出现问题", e, e.getMessage());
//重新发送消息到队尾
channel.basicPublish(msg.getMessageProperties().getReceivedExchange(),
msg.getMessageProperties().getReceivedRoutingKey(), MessageProperties.PERSISTENT_TEXT_PLAIN,
JSON.toJSONBytes(new Object()));
e.printStackTrace();
}
}
}
}
测试用例
package com.example.demo;
import com.example.demo.mq.producer.orderProducer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(classes = MqSpringbootstarterApplication.class)
class MqSpringbootstarterApplicationTests {
@Autowired
private com.example.demo.mq.producer.orderProducer orderProducer;
@Test
void contextLoads() {
for (int i = 1; i <= 15; i++) {
try {
orderProducer.sendMsg("恭喜获得一星亚索" + i + "只");
System.err.println("mag send success ~");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}