Caused by: org.springframework.amqp.AmqpException: No method found for class [B

前言

  • spring boot 2.2.13.RELEASE

错误内容:Caused by: org.springframework.amqp.AmqpException: No method found for class [B

11:06:57.392 [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#6-1] WARN  o.s.a.r.l.ConditionalRejectingErrorHandler - [log,129] - Execution of Rabbit message listener failed.
org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener threw exception
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.java:1722)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1612)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1527)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1515)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1506)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1450)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:976)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:922)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1297)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1203)
	at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.amqp.AmqpException: No method found for class [B
	at org.springframework.amqp.rabbit.listener.adapter.DelegatingInvocableHandler.getHandlerForPayload(DelegatingInvocableHandler.java:151)
	at org.springframework.amqp.rabbit.listener.adapter.DelegatingInvocableHandler.getMethodFor(DelegatingInvocableHandler.java:271)
	at org.springframework.amqp.rabbit.listener.adapter.HandlerAdapter.getMethodFor(HandlerAdapter.java:84)
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandlerAndProcessResult(MessagingMessageListenerAdapter.java:148)
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:135)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1608)
	... 10 common frames omitted

对错误的直接理解

org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#6-1 对象中,没有适合处理 class [B 的方法。

对错误的再次理解

使用 rabbitTemplate.convertAndSend 发送的消息,默认带有消息头contentType。spring 根据 contentType 找到适合的 处理方法处理。参考这里

我打印了一下正确的Message和错误的Message。

正确的Message(通过 rabbitTemplate.convertAndSend(RabbitConfig.MIS_EXCHANGE, RabbitConfig.MEMBER_REWARD_ROUTING, jsonObject.toString()) 发出的Message):

Message : 
{
	"body": "eyJyZXdhcmRLZXkiOiJyZWdpc3RlciIsInRpbWUiOiIyMDIxLTA0LTA2IDExOjM3OjI0IiwidXNlcklkIjoiMSJ9",
	"messageProperties": {
		"consumerQueue": "member.reward",
		"consumerTag": "amq.ctag-yWeKbI8-E8YILm7hlR5O4Q",
		"contentEncoding": "UTF-8",
		"contentLength": 0,
		"contentType": "text/plain",
		"deliveryTag": 1,
		"finalRetryForMessageWithNoId": false,
		"headers": {},
		"lastInBatch": false,
		"priority": 0,
		"publishSequenceNumber": 0,
		"receivedDeliveryMode": "PERSISTENT",
		"receivedExchange": "mis.direct",
		"receivedRoutingKey": "member.reward",
		"redelivered": false
	}
}

Message Body: 
{
	"rewardKey": "register",
	"time": "2021-04-06 11:37:24",
	"userId": "1"
}

错误的Message(通过rabbit mq 管理后台手动发出的Message):

Message : 
{
	"body": "eyJ1c2VySWQiOiIxIiwgInJld2FyZEtleSI6Imludml0ZSIsICJ0aW1lIjoiMjAyMS0wNC0wNCAyMToxNToyMCJ9",
	"messageProperties": {
		"consumerQueue": "member.reward",
		"consumerTag": "amq.ctag-JF9n7btz0tGCzE0pk9KO7w",
		"contentLength": 0,
		"deliveryTag": 1,
		"finalRetryForMessageWithNoId": false,
		"headers": {},
		"lastInBatch": false,
		"publishSequenceNumber": 0,
		"receivedDeliveryMode": "PERSISTENT",
		"receivedExchange": "mis.direct",
		"receivedRoutingKey": "member.reward",
		"redelivered": true
	}
}

Message Body: 
{
	"userId": "1",
	"rewardKey": "invite",
	"time": "2021-04-04 21:15:20"
}

嗯,对比一下发现,确实有差别:"contentType": "text/plain"

传Object会是什么情况呢(通过 rabbitTemplate.convertAndSend(RabbitConfig.MIS_EXCHANGE, RabbitConfig.MEMBER_REWARD_ROUTING, jsonObject) 发出的Message):

Message : 
{
	"body": "rO0ABXNyAB9jb20uYWxpYmFiYS5mYXN0anNvbi5KU09OT2JqZWN0AAAAAAAAAAECAAFMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAADdAAJcmV3YXJkS2V5dAAIcmVnaXN0ZXJ0AAR0aW1ldAATMjAyMS0wNC0wNiAxMTo0NjozMXQABnVzZXJJZHQAATF4",
	"messageProperties": {
		"consumerQueue": "member.reward",
		"consumerTag": "amq.ctag-7wnGu39A5POBeF753riU8Q",
		"contentLength": 0,
		"contentType": "application/x-java-serialized-object",
		"deliveryTag": 2,
		"finalRetryForMessageWithNoId": false,
		"headers": {},
		"lastInBatch": false,
		"priority": 0,
		"publishSequenceNumber": 0,
		"receivedDeliveryMode": "PERSISTENT",
		"receivedExchange": "mis.direct",
		"receivedRoutingKey": "member.reward",
		"redelivered": false
	}
}

Message Body:
在这里插入图片描述

嗯,至此,规律已出现了。那该怎么解决呢?

解决办法1:对缝儿

让生产者发送消息的类型与消费者接收消息的类型一致。

生产者发送String类型("contentType": "text/plain")的消息:

rabbitTemplate.convertAndSend(RabbitConfig.MIS_EXCHANGE, RabbitConfig.MEMBER_REWARD_ROUTING, jsonObject.toString())

消费者接受String类型的消息:

@Component
@RabbitListener(queues = { RabbitConfig.MEMBER_REWARD_QUEUE })
public class Receiver {

    @RabbitHandler
    public void process(String msg) {
        System.out.println("Receiver : " + msg);
        JSONObject jsonObject = JSON.parseObject(msg);
        ...
    }

}

生产者发送JSONObject类型("contentType": "application/x-java-serialized-object")的消息:

rabbitTemplate.convertAndSend(RabbitConfig.MIS_EXCHANGE, RabbitConfig.MEMBER_REWARD_ROUTING, jsonObject)

消费者接受String类型的消息:

@Component
@RabbitListener(queues = { RabbitConfig.MEMBER_REWARD_QUEUE })
public class Receiver {

    @RabbitHandler
	public void process(JSONObject jsonObject) {
		System.out.println("Receiver : " + jsonObject.toJSONString());
		...
    }

}

依次类推。

解决办法2:消费者设置默认处理方法

不管生产者怎么生产消息。通过rabbitTemplate.convertAndSendamqp-clientrabbitmq 管理后台等发送均可。

消费者设置默认处理:

@Component
@RabbitListener(queues = { RabbitConfig.MEMBER_REWARD_QUEUE })
public class Receiver {

    @RabbitHandler(isDefault = true)
	public void process(Message message) {
        // message.getBody() 为消息体
        // 如果客户端发送的是String, new String(message.getBody()) 得到客户端发送的String
        // 如果客户端发送的是Object, 此时接收到的是序列化后的Object,在这里需要反序列化得到Object
        ...
    }

}

解决办法3:规避二义性

当把@RabbitListener标注在类上面时,可以在多个方法上标注@RabbitHandler。此时需要通过 isDefault 属性设置消息的默认处理方法。
当把@RabbitListener标注在方法上面时,无法设置多个消息处理方法,就不存在二义性的问题。因此完美规避本错误。
参考这里

解决办法4:生产者设置ContentType

参考这里

  1. amqp-client发送消息时,设置ContentType:
    @Test
    public void publishTest() throws IOException {
        channel.exchangeDeclare("testExchange", "direct", true);
        channel.queueBind("many", "testExchange", "many");
        String message = "this is the test";
        AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder()
                                                    .contentEncoding("UTF-8")
                                                    .contentType("text/plain")
                                                    .headers(new HashMap<String, Object>())
                                                    .priority(0);
        channel.basicPublish("testExchange", "many",builder.build(), message.getBytes());
    }
  1. RabbitMQ管理后台删除无法处理的消息,再重新开程序,就没问题了。

另外一个类似的错误:Caused by: org.springframework.amqp.AmqpException: No method found for class java.lang.String

11:41:33.719 [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#6-1] WARN  o.s.a.r.l.ConditionalRejectingErrorHandler - [log,129] - Execution of Rabbit message listener failed.
org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener threw exception
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.java:1722)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1612)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1527)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1515)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1506)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1450)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:976)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:922)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1297)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1203)
	at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.amqp.AmqpException: No method found for class java.lang.String
	at org.springframework.amqp.rabbit.listener.adapter.DelegatingInvocableHandler.getHandlerForPayload(DelegatingInvocableHandler.java:151)
	at org.springframework.amqp.rabbit.listener.adapter.DelegatingInvocableHandler.getMethodFor(DelegatingInvocableHandler.java:271)
	at org.springframework.amqp.rabbit.listener.adapter.HandlerAdapter.getMethodFor(HandlerAdapter.java:84)
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandlerAndProcessResult(MessagingMessageListenerAdapter.java:148)
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:135)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1608)
	... 10 common frames omitted
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值