异常显示:监听器抛出异常
ListenerExecutionFailedException
是一个在使用Spring AMQP与RabbitMQ集成时,当消息监听器执行失败时抛出的异常。这通常意味着在处理消息时发生了某种错误。
解释:
-
ListenerExecutionFailedException
是Spring AMQP中的一个异常,用于指示消息监听器执行失败。 -
这个异常通常包含一个原因,可能是
MessageConversionException
、AmqpException
等。
2024-07-26 16:47:56.638 ERROR 7436 --- [ool-2-thread-12] .l.DirectReplyToMessageListenerContainer : Failed to invoke listener
org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener threw exception
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.java:1693) ~[spring-rabbit-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1583) ~[spring-rabbit-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1498) ~[spring-rabbit-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1486) ~[spring-rabbit-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1477) ~[spring-rabbit-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1421) ~[spring-rabbit-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer$SimpleConsumer.callExecuteListener(DirectMessageListenerContainer.java:1037) [spring-rabbit-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer$SimpleConsumer.handleDelivery(DirectMessageListenerContainer.java:997) [spring-rabbit-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at com.rabbitmq.client.impl.ConsumerDispatcher$5.run(ConsumerDispatcher.java:149) [amqp-client-5.7.3.jar:5.7.3]
at com.rabbitmq.client.impl.ConsumerWorkService$WorkPoolRunnable.run(ConsumerWorkService.java:104) [amqp-client-5.7.3.jar:5.7.3]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_201]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_201]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_201]
Caused by: org.springframework.amqp.AmqpRejectAndDontRequeueException: Reply received after timeout
at org.springframework.amqp.rabbit.core.RabbitTemplate.onMessage(RabbitTemplate.java:2567) ~[spring-rabbit-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.amqp.rabbit.listener.DirectReplyToMessageListenerContainer.lambda$setMessageListener$1(DirectReplyToMessageListenerContainer.java:100) ~[spring-rabbit-2.2.5.RELEASE.jar:2.2.5.RELEASE]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1579) ~[spring-rabbit-2.2.5.RELEASE.jar:2.2.5.RELEASE]
... 11 common frames omitted
造成的原因:代码只是部分
rabbitmq_receiver代码如下:监听支付过期队列,返回支付二维码路径
@Component
public class Receiver {
/**
*
* @param msg
* @return 返回支付二维码的图片路径过去
* 监听过期队列
*/
@RabbitListener(
bindings={@QueueBinding(
value=@Queue(value="ttl_order_queue",autoDelete = "true"),
exchange=@Exchange(value="topic_exchange",type= ExchangeTypes.TOPIC),
key = "#.ttl"
)}
)
public String getMsg(String msg){
SeckillStatus seckillStatus = JSON.parseObject(msg, SeckillStatus.class);
//需要支付的金额
String totalAmount = seckillStatus.getMoney()+"";
//用户名
String username = seckillStatus.getUsername();
//订单编号
String outTradeNo = seckillStatus.getOrderId()+"";
//支付主体
String subject = "支付宝平台";
//打折金额
String undiscountableAmount = null;
//备注
String body = "购物消费";
//支付成功之后,由支付宝回调地址,通知支付状态
//使用花生壳代理以下地址,暴露在互联网上处理
//执行支付
Map<String, Object> pay = PayService.pay(outTradeNo, subject, totalAmount, undiscountableAmount, body, notifyUrl);
System.out.println("支付的详情: "+pay);
String payUrl = (String)pay.get("支付链接");
//生成二维码的图片
String path =TwoCode.createCode(payUrl);//临时存储在桌面上
System.out.println("支付的链接: "+payUrl);
//把二维码图片上传到分布式文件服务器
//上传文件的真实名字
File file = new File(path);
String originalFilename = file.getName();
//获取上传文件的流对象
FileInputStream in = null;
try {
in = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
String imagePath = null;
//执行上传文件到FTP文件服务器
FtpUtil.uploadFile("192.168.138.129", 21, "ftpuser", "ftpuser", "/home/ftpuser/images","/"+getImagePath(), originalFilename, in);
imagePath = "http://192.168.138.129:9999/"+getImagePath()+"/"+originalFilename;
file.delete();
return imagePath;
}
过期队列的config:
/**
* 配置过期队列的类
*/
@Configuration
public class OrderTtlQueueConfig {
//过期队列的名称
public static final String TTL_ORDER_QUEUE="ttl_order_queue";
public static final String TTL_ROUT_KEY="#.ttl"; //#表示匹配所有以.ttl为后缀的路由键
@Bean("ttlOrderQueue")
public Queue ttlOrderQueue(){
/**
* public Queue(String name, boolean durable, boolean exclusive,
* boolean autoDelete, @Nullable Map<String, Object> arguments)
*
*
* 第一个参数name:队列的名称
* 第二人参数durable: 是否持久化
* 第三个参数exclusive: 是否独享
* 第四个参数autoDelete:是否删除
* 第五个参数arguments: Map集合,封装配置参数
* x-message-ttl:表示过期时间的设置,不能随便写
*/
Map<String,Object> arguments=new HashMap<>();
//设置进入这个队列的消息的统一过期时间
arguments.put("x-message-ttl",10000); //过期时间为60秒
//如果过期了,消息转到死信队列
arguments.put("x-dead-letter-exchange",RabbitMQExchangeConfig.DIRECT_EXCHANGE);
//路由键
arguments.put("x-dead-letter-routing-key",DLXconfig.DLX_TTL_ROUT_KEY);
Queue queue=new Queue(TTL_ORDER_QUEUE,true,false,false,arguments);
return queue;
}
@Bean("dlxOrderBind")
public Binding dlxOrderBind(@Autowired @Qualifier("topicExchange") TopicExchange topicExchange){
return BindingBuilder.bind(ttlOrderQueue()).to(topicExchange).with(TTL_ROUT_KEY);
}
}
配置交换机:
/**
* 点对点,规则匹配
*/
@Bean("topicExchange")
public TopicExchange topicExchange(){
return new TopicExchange(TOPIC_EXCHANGE,true,false);
}
rabbitmq_sender
@Component
public class Sender {
@Autowired
private AmqpTemplate amqpTemplate;
public String sendMessage(String msg){
String s= (String) amqpTemplate.convertSendAndReceive(RabbitMQExchangeConfig.TOPIC_EXCHANGE,"order.ttl",msg);
System.out.println(s);
return s;
}
在调用sender下面的sendMassage()时就报这个,org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener threw exception错误,输出codePath为null(不知道为什么sendMassage()返回值为空)
//发送需要支付的订单信息到延时队列(给放入的消息都设置了统一的过期时间的普通的消息队列)
//把对象转成JSON格式
String s = JSON.toJSONString(seckillStatus);
String codePath =sender.sendMessage(s);
System.out.println("codePath: "+codePath);
seckillStatus.setCodePath(codePath);
System.out.println("seckillStatus :"+ seckillStatus);
System.out.println("发送支付订单消息到延时队列成功");
redisTemplate.boundHashOps(queuestatus).put(seckillStatus.getUsername(),seckillStatus);
解决方法:我的解决方法是(我这个rabbitmq没有学的太精,一点拙见,大家就图一乐):
//发送需要支付的订单信息到延时队列(给放入的消息都设置了统一的过期时间的普通的消息队列)
//把对象转成JSON格式
String s = JSON.toJSONString(seckillStatus);
String codePath =receiver.getMsg(s);
System.out.println("codePath: "+codePath);
seckillStatus.setCodePath(codePath);
System.out.println("seckillStatus :"+ seckillStatus);
System.out.println("发送支付订单消息到延时队列成功");
redisTemplate.boundHashOps(queuestatus).put(seckillStatus.getUsername(),seckillStatus);
将sender.sendMessage()换成receiver.getMag()这个错误就消失了,二维码的图片也能正常显示
这个问题是我在写项目的时候遇到的,现在还是一名大三学生!!! 如果有遇到这个情况的小伙伴,可以试一下,如果有编程大佬有更好的思路的话,可以指教一下,我必定虚心学习.