org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener threw exception

 异常显示:监听器抛出异常

ListenerExecutionFailedException 是一个在使用Spring AMQP与RabbitMQ集成时,当消息监听器执行失败时抛出的异常。这通常意味着在处理消息时发生了某种错误。

解释:

  • ListenerExecutionFailedException 是Spring AMQP中的一个异常,用于指示消息监听器执行失败。

  • 这个异常通常包含一个原因,可能是MessageConversionExceptionAmqpException等。

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()这个错误就消失了,二维码的图片也能正常显示


这个问题是我在写项目的时候遇到的,现在还是一名大三学生!!! 如果有遇到这个情况的小伙伴,可以试一下,如果有编程大佬有更好的思路的话,可以指教一下,我必定虚心学习.

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值