欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-15 11:23:42
...

前言

  • 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:
Caused by: org.springframework.amqp.AmqpException: No method found for class [B

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

解决办法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
相关标签: spring-boot error