1、配置连接
@Configuration
public class RabbitConfig {
@Value("${spring.rabbitmq.username}")
private String userName;
@Value("${spring.rabbitmq.host}")
private String host;
@Value("${spring.rabbitmq.port}")
private String port;
@Value("${spring.rabbitmq.password}")
private String password;
@Value("${spring.rabbitmq.virtual-host}")
private String virtualHost;
@Bean
public CachingConnectionFactory cachingConnectionFactory() {
CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setHost(host);
factory.setPort(Integer.parseInt(port));
factory.setUsername(userName);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setChannelCacheSize(25);
return factory;
}
@Bean
public RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory){
RabbitTemplate rabbitTemplate = new RabbitTemplate();
rabbitTemplate.setMessageConverter(new MqMessageConverter());
rabbitTemplate.setConnectionFactory(connectionFactory);
rabbitTemplate.setMandatory(true);
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
System.out.println("ConfirmCallback:"+"相关数据:"+correlationData);
System.out.println("ConfirmCallback:"+"确认情况:"+ack);
System.out.println("ConfirmCallback:"+"原因:"+cause);
});
rabbitTemplate.setReturnsCallback(returnedMessage -> {
System.out.println("ReturnCallback: " + "消息:" + JSONUtil.toJsonStr(returnedMessage));
});
return rabbitTemplate;
}
@Bean
public SimpleMessageListenerContainer simpleMessageListenerContainer(CachingConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setConcurrentConsumers(4);
container.setMaxConcurrentConsumers(8);
container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
return container;
}
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
}
2、自定义序列化
public class MqMessageConverter implements MessageConverter {
private final Jackson2JsonMessageConverter converter;
public MqMessageConverter() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
this.converter = new Jackson2JsonMessageConverter(mapper);
}
@NotNull
@Override
public Message toMessage(@NotNull Object object, @NotNull MessageProperties messageProperties) {
return converter.toMessage(object, messageProperties);
}
@NotNull
@Override
public Object fromMessage(@NotNull Message message) {
return converter.fromMessage(message);
}
}
3、配置交换机与消息队列
@Configuration
public class DirectRabbitConfig {
private static final Map<String, Object> arguments = getArguments();
private static Map<String, Object> getArguments() {
Map<String, Object> arguments = new HashMahMap<>();
arguments.put("x-dead-message-ttl", 60000);
arguments.put("x-dead-letter-exchange", "directExchange");
arguments.put("x-dead-letter-routing-key", "directKeyMessage");
return arguments;
}
@Bean
public TopicExchange topicExchange() {
return new TopicExchange("topicExchange", true, false);
}
@Bean
public DirectExchange directExchange() {
return new DirectExchange("directExchange", true, false);
}
@Bean
public Queue bizQueue() {
return new Queue("biz", true, false, false, arguments);
}
@Bean
public Queue directQueue() {
Map<String, Object> args = new HashMap<>();
args.put("x-dead-message-ttl", 60000);
return new Queue(RabbitmqConstant."directQueue", true, false, false, args);
}
@Bean
public Binding bizBinding() {
return BindingBuilder.bind(bizQueue()).to(topicExchange()).with("biz");
}
@Bean
public Binding directBinding() {
return BindingBuilder.bind(directQueue()).to(directExchange()).with("directKeyMessage";
}
}
4、配置消费者
@Slf4j
@Component
@RequiredArgsConstructor
public class BizConsumer {
@RabbitListener(queues = "biz")
public void bizListen(Message message, Channel channel) throws Exception {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
String body = new String(message.getBody(), StandardCharsets.UTF_8);
JSONObject messageJson = JSONUtil.parseObj(body);
try {
} catch (Exception e) {
if (MAX_RETRY_COUNT <= (retryCount + 1)) {
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
log.error("❌ 消息处理失败,正在重试,当前重试次数为:{}, retryCount);
throw new RuntimeException(e);
}
}
}
5、配置死信消费者
@Slf4j
@Component
@RequiredArgsConstructor
public class DeadLetterConsumer {
@RabbitListener(queues = "directQueue")
public void deadLetterListen(Message message, Channel channel) throws IOException {
log.error("[{}] \uD83D\uDC80 死信队列接收到消息 ", LocalDateTime.now());
log.error("消息内容: {}", RabbitMqUtil.getMessage(message));
log.error("🔔 等待人工处理");
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
6、发送消息
@Slf4j
public class RabbitMqUtil {
private static final RabbitTemplate rabbitTemplate = SpringUtil.getBean(RabbitTemplate.class);
public static <T> T getMessage(Class<T> clazz, Message message) {
String body = new String(message.getBody(), StandardCharsets.UTF_8);
return JSONUtil.toBean(body, clazz);
}
public static JSONObject getMessage(Message message) {
String body = new String(message.getBody(), StandardCharsets.UTF_8);
return JSONUtil.parseObj(body);
}
public static <T> void sendMqMessage(String topic, T t) {
rabbitTemplate.convertAndSend(RabbitmqConstant.TOPIC_EXCHANGE, topic, new JSONObject(t));
}
public static void sendMqJsonMessage(String topic, JSONObject jsonObject) {
rabbitTemplate.convertAndSend(RabbitmqConstant.TOPIC_EXCHANGE, topic, jsonObject);
}
}