一:队列配置
1)失败队列
package com.future.rabbit.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FailedConfig {
/**
* 处理业务的队列
*/
public final static String FAILED_QUEUE = "retry.failed.queue";
/**
* 处理业务的交换器
*/
public final static String FAILED_EXCHANGE = "retry.failed.exchange";
/**
* 处理业务的路由key
*/
public final static String FAILED_KEY = "retry.failed.key";
/**
* 处理业务的交换器
*
* @return
*/
@Bean
DirectExchange retryFailedExchange() {
return new DirectExchange(FAILED_EXCHANGE);
}
/**
* 处理业务的队列
*
* @return
*/
@Bean
public Queue retryFailedQueue() {
return QueueBuilder
.durable(FAILED_QUEUE)
.build();
}
/**
* 绑定处理队列的数据监听工作
*
* @return
*/
@Bean
public Binding failedRetryBinding() {
return BindingBuilder
.bind(retryFailedQueue())
.to(retryFailedExchange())
.with(FAILED_KEY);
}
}
2)重试队列
package com.future.rabbit.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RetryConfig {
/**
* 重试的队列
*/
public final static String RETRY_QUEUE = "retry.queue";
/**
* 重试的交换器
*/
public final static String RETRY_EXCHANGE = "retry.exchange";
/**
* 处理业务的路由key
*/
public final static String RETRY_KEY = "retry.key";
/**
* 超时时间
*/
private static final Long QUEUE_EXPIRATION = 3000L;
/**
* 重试的交换器
*
* @return
*/
@Bean
DirectExchange retryExchange() {
return new DirectExchange(RETRY_EXCHANGE);
}
/**
* 重试的队列
*
* @return
*/
@Bean
public Queue retryQueue() {
// 设置超时队列
return QueueBuilder.durable(RETRY_QUEUE)
// DLX,dead letter发送到的exchange ,设置死信队列交换器到处理交换器
.withArgument("x-dead-letter-exchange", WorkConfig.WORK_EXCHANGE)
// dead letter携带的routing key,配置处理队列的路由key
.withArgument("x-dead-letter-routing-key", WorkConfig.WORK_KEY)
// 设置过期时间
.withArgument("x-message-ttl", QUEUE_EXPIRATION)
.build();
}
/**
* 绑定处理队列的数据监听工作
*
* @return
*/
@Bean
public Binding retryBinding() {
return BindingBuilder
.bind(retryQueue())
.to(retryExchange())
.with(RETRY_KEY);
}
}
3)工作队列
package com.future.rabbit.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WorkConfig {
/**
* 处理业务的队列
*/
public final static String WORK_QUEUE = "retry.work.queue";
/**
* 处理业务的交换器
*/
public final static String WORK_EXCHANGE = "retry.work.exchange";
/**
* 处理业务的路由key
*/
public final static String WORK_KEY = "retry.work.key";
/**
* 处理业务的交换器
*
* @return
*/
@Bean
DirectExchange retryWorkExchange() {
return new DirectExchange(WORK_EXCHANGE);
}
/**
* 处理业务的队列
*
* @return
*/
@Bean
public Queue retryWorkQueue() {
return QueueBuilder
.durable(WORK_QUEUE)
.build();
}
/**
* 绑定处理队列的数据监听工作
*
* @return
*/
@Bean
public Binding workRetryBinding() {
return BindingBuilder
.bind(retryWorkQueue())
.to(retryWorkExchange())
.with(WORK_KEY);
}
}
二:生产者配置
package com.future.rabbit.handle;
import com.future.rabbit.config.WorkConfig;
import com.future.rabbit.idgenerator.SnowflakeIdWorker;
import com.future.rabbit.pojo.User;
import com.future.rabbit.utils.TimeUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class RetrySender {
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private SnowflakeIdWorker worker;
public void send() {
this.rabbitTemplate.convertAndSend(
WorkConfig.WORK_EXCHANGE,
// routingKey
WorkConfig.WORK_KEY,
new User(worker.genNextId(), "Direct2", 200, 0, TimeUtils.getChinaTime()));
}
}
三:消费者配置
1)正常工作消费
package com.future.rabbit.handle;
import com.future.rabbit.config.FailedConfig;
import com.future.rabbit.config.RetryConfig;
import com.future.rabbit.config.WorkConfig;
import com.future.rabbit.constant.RabbitConstant;
import com.future.rabbit.pojo.User;
import com.future.rabbit.service.impl.SysUserServiceImpl;
import com.future.rabbit.utils.GsonUtil;
import com.rabbitmq.client.Channel;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@AllArgsConstructor
public class WorkReceiver {
private final RabbitTemplate rabbitTemplate;
private final SysUserServiceImpl sysUserService;
/**
* queues是指要监听的队列的名字
*
* @param user
*/
@RabbitListener(queues = WorkConfig.WORK_QUEUE
) //errorHandler = "retryReceiverListenerErrorHandler"
public void receiveDirect(User user,
Channel channel,
Message message) throws Exception {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
log.info("【WorkReceiver监听到消息】" + GsonUtil.gsonString(user));
//业务处理,返回flag
if (flag) {
channel.basicAck(deliveryTag, false);
}
} catch (Exception e) {
log.error(e.getMessage()+e.getCause());
//进入延时队列,进行重试
Integer retry = user.getRetry();
if (retry < RabbitConstant.QUEUE_RETRY_NUM) {
log.info("receiver error,进入延迟队列,重试次数:{}", retry + 1);
user.setRetry(retry + 1);
rabbitTemplate.convertAndSend(
RetryConfig.RETRY_EXCHANGE,
// routingKey
RetryConfig.RETRY_KEY,
user);
} else {
//进入失败队列,进行人工处理
rabbitTemplate.convertAndSend(
FailedConfig.FAILED_EXCHANGE,
// routingKey
FailedConfig.FAILED_KEY,
user);
log.info("receiver failed,进入死信队列");
}
//将上一个重试的队列手动ack
channel.basicAck(deliveryTag, false);
}
}
}
2)失败消费
package com.future.rabbit.handle;
import com.future.rabbit.config.FailedConfig;
import com.future.rabbit.pojo.MessageStruct;
import com.future.rabbit.pojo.User;
import com.future.rabbit.service.impl.MessageServiceImpl;
import com.future.rabbit.utils.GsonUtil;
import com.rabbitmq.client.Channel;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@AllArgsConstructor
public class FailedReceiver {
private final MessageServiceImpl messageService;
/**
* queues是指要监听的队列的名字
*
* @param user
*/
@RabbitListener(queues = FailedConfig.FAILED_QUEUE
) // errorHandler = "retryReceiverListenerErrorHandler"
public void receiveDirect(User user, Channel channel, Message message) throws Exception {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
String userMessage = GsonUtil.gsonString(user);
log.info("【FailedReceiver监听到消息,存到数据库】" + userMessage);
//业务处理,返回flag
if (flag) {
//如果失败消息存储成功,则手动ack
channel.basicAck(deliveryTag, false);
}
} catch (Exception e) {
log.info("receiver error");
}
}
}
四:通用常数
package com.future.rabbit.constant;
/**
* RabbitMQ常量池
*
* @author yangkai.shen
*/
public interface RabbitConstant {
/**
* 直接模式1
*/
String DIRECT_MODE_QUEUE_ONE = "queue.direct.1";
/**
* 队列2
*/
String QUEUE_TWO = "queue.2";
/**
* 队列3
*/
String QUEUE_THREE = "3.queue";
/**
* 分列模式
*/
String FANOUT_MODE_QUEUE = "fanout.mode";
/**
* 主题模式
*/
String TOPIC_MODE_QUEUE = "topic.mode";
/**
* 路由1
*/
String TOPIC_ROUTING_KEY_ONE = "queue.#";
/**
* 路由2
*/
String TOPIC_ROUTING_KEY_TWO = "*.queue";
/**
* 路由3
*/
String TOPIC_ROUTING_KEY_THREE = "3.queue";
/**
* 延迟队列
*/
String DELAY_QUEUE = "delay.queue";
/**
* 延迟队列交换器
*/
String DELAY_MODE_QUEUE = "delay.mode";
/**
* 重试次数
*/
int QUEUE_RETRY_NUM = 3;
/**
* 雪花id机器id
*/
int WORKER_ID = 30;
/**
* 雪花id数据id
*/
int DATA_ID = 14;
}