rabbitmq发送消息异常时,使用切面写进数据库,定时任务进行重新发送

前言

场景:当消费者消费消息出现异常时,利用注解和切面进行处理,写进数据库中,然后通过定时任务进行重发.


提示:以下是本篇文章正文内容,下面案例可供参考

一、保存和修改注解

在生产者中标注MqMsgSave注解,把发送的消息存在数据库中
在消费者中标注MqMsgEdit注解,改变消息发送成功的状态

@Target(ElementType.METHOD)
@Retention(RUNTIME)
@Documented
public @interface MqMsgSave{
	//需要记录的消息对象参数位置
	int argsIndex();
//消息类型,表明是哪种消息,如果发送失败调相应的接口重发消息
	int msgType();
}


@Target(ElementType.METHOD)
@Retention(RUNTIME)
@Documented
public @interface MqMsgEdit{
//需要记录的消息对象参数位置
	int argsIndex();
//消息类型,表明是哪种消息,如果发送失败调相应的接口重发消息
}

//新建一个消息类,用来报错消息发送状态和次数

public class MessageHistoryLog implements Serializable {
	private Long id;
	private String content;
	private String sendResponse
	private Integer status;
	private Integer type;
	@DateTimeFormat(
	pattern = "yyyy-MM-dd HH:mm:ss"
	)
	@JsonFormat(
	pattern = "yyyy-MM-dd HH:mm:ss",
	timezone = "GMT+8"
	)
	private Date createTime;
	@DateTimeFormat(
	pattern = "yyyy-MM-dd HH:mm:ss"
	)
	@JsonFormat(
	pattern = "yyyy-MM-dd HH:mm:ss",
	timezone = "GMT+8"
	)
	private Data updateTime;
} 

二、MqMsgSaceAspect

public class MqMsgSaceAspect{
	@Autowired 
	private MqHistoryLogService logService;
	@Pointcut("@annotation(xxx.MqMsgSave)")
	private void pointCut(){
	}
	//MqMsgSave 就是标注在生产者方法上注解的信息,JoinPoint就是方法上参数的所有信息
	@AfterReturning(value = "pointCut()&& @annotation(mqMsgSave)",returning = "rvt")
	@Async("baseExecutor")
	public void afterReturning(JoinPoint joinPoint ,MqMsgSave mqMsgSave,Object rvt ){
		Object obj = joinPoint.getArgs()[0];
		//0代表生产者发送中,消费者没消费
		getMessageHistoryLog(obj,mqMsgSave.getmsgTYpe(),0)
	}
	@AfterThrowing(value = "pointCut()&& @annotation(mqMsgSave)",throwing= "exception")
	@Async("baseExecutor")
	public void afterThrowing(JoinPoint joinPoint ,MqMsgSave mqMsgSave,Exception exception ){
		Object obj = joinPoint.getArgs()[mqMsgSave.argsIndex()];
		//2代表发送消息失败
		getMessageHistoryLog(obj,mqMsgSave.getmsgTYpe(),2)
	}
	private void getMessageHistoryLog(Object obj,int type,int status){
		MessageHistoryLog log = new MessageHistoryLog();
		long id = ReflectionUtil.getFieldValue(obj,"id");
		String content = JSON.toJSONString(obj);
		log.setId(id);
		log.setStatus(status);
		log.setContent(content);
		log.setType(type);
		try{
		MessageHistoryLog logDTO  = 	logService.selectById(id);
		if(logDTO==null){
			log.setCreateTime(new Date());
			logService.save(log);
		}else{
		log.setCreateTime(logDTO.getCreateTime());
		log.setUpdateTime(new Date());
		logService.updateById(log);
		}
		}catch(Exception e){
			log.errir("xxxxxxx")
		}
	}
}

三、MqMsgEditAspect


public class MqMsgEditAspect{
	@Autowired
	private MqHistoryLogService logService;
	
	@Autowired
	private MyErrorLogService errorLogService;
	@PointCut("@annotation(xxx.MqMsgEdit)")
	private void pointCut(){
	}
	
	@AfterReturning(value = "pointCut() && @annotation(mqMsgEdit)",returning = "res")
	public void afterReturning(JoinPoint joinPoint,MqMsgEdit mqMsgEdit,Object res){
		Object obj = joinPoint.getArgs()[mqMsgEdit.argsIndex()];
		editMqHistoryLog(obj,res,1);
	}
	
	@AfterThrowing(value = "pointCut() && @annotation(mqMsgEdit)",returning = "res")
	public void afterThrowing(JoinPoint joinPoint,MqMsgEdit mqMsgEdit,Object res){
		Object obj = joinPoint.getArgs()[mqMsgEdit.argsIndex()];
		editMqHistoryLog(obj,res,2);
	}
	
	private void editMqHistoryLog(Object obj,Object res,int status){
	Object idObj = ReflectionUtil.getFieldValue(obj,"id");
	long id = (long) idObj ;
	MessageHistoryLog logDTO  = 	logService.selectById(id);
	if(logDTO  !=null){
	logDTO.setStatus(status);
		if(status ==2 && isRetryMax(logDTO)){
		//如果重试超过最大次数,直接设置为发送成功。避免资源浪费
			logDTO.setStatus(1);
		}
		log.setUpdateTime(new Date());
		logService.updateById(logDTO);
		}	
	}
	private boolean isRetryMax(MessageHistoryLog logDTO ){
	//计算这个消息总共有多少次
		int selectCount = errorLogService.selectCount(logDTO.getId);
		//这边可以建一个类,消费者消息消息出现问题后,把信息存储到这个类中,然后通过定时任务发送
		MyHistoryErrorLogDTO myHistoryErrorLogDTO = new MyHistoryErrorLogDTO();
		myHistoryErrorLogDTO .setId(xx);
		myHistoryErrorLogDTO.setContent(xxx);
		myHistoryErrorLogDTO.setType(xxxx);
		boolean isRetryMax = selectCount >=5;
		if(!isRetryMax){
		//如果小于5次,继续插入
			errorLogService.add(myHistoryErrorLogDTO );
		}
		return isRetryMax ;
	}
}
	
	

四、定时任务

定时任务逻辑:就是获取失败的消息,然后进行重发即可,我后面会写一遍springboot整合 elasticJob 的分布式定时任务。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值