踩坑记录

近日在用spring boot架构一个微服务框架,服务发现与治理、发布REST接口各种轻松惬意。但是服务当设计MQ入口时,就发现遇到无数地雷,现在整理成下文,供各路大侠围观与嘲笑。

版本

当前使用的spring-boot-starter-amqp版本为2016.5发布的1.3.5.RELEASE

也许若干年后,你们版本都不会有这些问题了。:(

RabbitMQ

当需要用到MQ的时候,我的第一反映就是使用RabbitMQ,猫了一眼spring boot的官方说明,上面说spring boot为rabbit准备了spring-boot-starter-amqp,并且为RabbitTemplate和RabbitMQ提供了自动配置选项。暗自窃喜~~

瞅瞅[官方文档]http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-rabbitmq和例子,SO EASY,再看一眼GITHUB上的官方例了,也有例子。

心情愉悦的照着例子,开干~~。

踩坑

十五分钟后的代码类似这样:

@Service
@RabbitListener(queues = "merchant")
public class MQReceiver {
protected Logger logger = Logger.getLogger(MQReceiver.class
.getName()); @RabbitHandler
public void process(@Payload UpdateMerchant request) {
UpdateMerchantResponse response = new UpdateMerchantResponse();
logger.info(request.getMerchantId() + "->" + response.getReturnCode());
}
}

消费信息后,应该记录一条日志。

结果得到只有org.springframework.amqp.AmqpException: No method found for class [B 这个异常,并且还无限循环抛出这个异常。。。

记得刚才官方文档好像说了异常什么的,转身去猫一眼,果然有:

If retries are not enabled and the listener throws an exception, by default the delivery will be retried indefinitely. You can modify this behavior in two ways; set the defaultRequeueRejected

 property to false

 and zero re-deliveries will be attempted; or, throw an AmqpRejectAndDontRequeueException

 to signal the message should be rejected. This is the mechanism used when retries are enabled and the maximum delivery attempts are reached.

知道了为啥会无限重试了,下面来看看为啥会抛出这个异常,google搜一下,貌似还有一个倒霉鬼遇到了这个问题

进去看完问题和大神的解答,豁然开朗。

There are two conversions in the @RabbitListener pipeline.

The first converts from a Spring AMQP Message to a spring-messaging Message.

There is currently no way to change the first converter from SimpleMessageConverter which handles String, Serializable and passes everything else as byte[].

The second converter converts the message payload to the method parameter type (if necessary).

With method-level @RabbitListeners there is a tight binding between the handler and the method.

With class-level @RabbitListener s, the message payload from the first conversion is used to select which method to invoke. Only then, is the argument conversion attempted.

This mechanism works fine with Java Serializable objects since the payload has already been converted before the method is selected.

However, with JSON, the first conversion returns a byte[] and hence we find no matching @RabbitHandler.

We need a mechanism such that the first converter is settable so that the payload is converted early enough in the pipeline to select the appropriate handler method.

A ContentTypeDelegatingMessageConverter is probably most appropriate.

And, as stated in AMQP-574, we need to clearly document the conversion needs for a @RabbitListener, especially when using JSON or a custom conversion.

得嘞,官方示例果然是坑,试试大神的解决方案,手动新增下转换。

  @Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMessageConverter(new Jackson2JsonMessageConverter());
return template;
} @Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(new Jackson2JsonMessageConverter());
return factory;
}

然后在生产和消费信息的地方使用他们:

@RabbitListener(queues = "merchant", containerFactory="rabbitListenerContainerFactory")
public void process(@Payload UpdateMerchant request) {
UpdateMerchantResponse response = new UpdateMerchantResponse();
logger.info(request.getMerchantId() + "->" + response.getReturnCode());
}

再来一次,果然可以了

c.l.s.m.service.MQReceiver : 00000001->null

总结

看起来很简单,可是掉坑里面之后怎么也得折腾个几个小时才能爬出来,此文献给掉进同一个坑的童鞋,希望你能满意。

spring-boot-starter-amqp踩坑记的更多相关文章

  1. 记一次 Spring 事务配置踩坑记

    记一次 Spring 事务配置踩坑记 问题描述:(SpringBoot + MyBatisPlus) 业务逻辑伪代码如下.理论上,插入数据 t1 后,xxService.getXxx() 方法的查询条 ...

  2. Spring @Transactional踩坑记

    @Transactional踩坑记 总述 ​ Spring在1.2引入@Transactional注解, 该注解的引入使得我们可以简单地通过在方法或者类上添加@Transactional注解,实现事务 ...

  3. 从零一起学Spring Boot之LayIM项目长成记(五)websocket

    前言 距离上一篇已经比较久的时间了,项目也是开了个头.并且,由于网上的关于Spring Boot的websocket讲解也比较多.于是我采用了另外的一个通讯框架 t-io 来实现LayIM中的通讯功能 ...

  4. 从零一起学Spring Boot之LayIM项目长成记(三) 数据库的简单设计和JPA的简单使用。

    前言 今天是第三篇了,上一篇简单模拟了数据,实现了LayIM页面的数据加载.那么今天呢就要用数据库的数据了.闲言少叙,书归正传,让我们开始吧. 数据库 之前有好多小伙伴问我数据库是怎么设计的.我个人用 ...

  5. EOS踩坑记 2

    [EOS踩坑记 2] 1.--contracts-console 在开发模式下,需要将 nodeos 添加此选项. 2.Debug Method The main method used to deb ...

  6. SpringBoot 之Spring Boot Starter依赖包及作用

    Spring Boot 之Spring Boot Starter依赖包及作用 spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. spri ...

  7. Spring Boot Starter列表

    转自:http://blog.sina.com.cn/s/blog_798f713f0102wiy5.html Spring Boot Starter 基本的一共有43种,具体如下: 1)spring ...

  8. 从零开始开发一个Spring Boot Starter

    一.Spring Boot Starter简介 Starter是Spring Boot中的一个非常重要的概念,Starter相当于模块,它能将模块所需的依赖整合起来并对模块内的Bean根据环境( 条件 ...

  9. Spring Boot Starter 开发指南

    Spring Boot Starter是什么? 依赖管理是任何复杂项目的关键部分.以手动的方式来实现依赖管理不太现实,你得花更多时间,同时你在项目的其他重要方面能付出的时间就会变得越少. Spring ...

  10. Spark踩坑记——Spark Streaming+Kafka

    [TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...

随机推荐

  1. #9.5课堂JS总结#循环语句、函数

    一.循环语句 1.for循环 下面是 for 循环的语法: for (语句 1; 语句 2; 语句 3) { 被执行的代码块 } 语句 1 在循环(代码块)开始前执行 语句 2 定义运行循环(代码块) ...

  2. FusionCharts的使用方法(超详细)

    今天统计价格变化规律的时候找到的一个很好的文档,很详细 一.简介 Ø FusionCharts 是InfoSoft Global 公司的一个产品,InfoSoft Global 公司是专业的Flash ...

  3. mysql NOW,CURRENT_TIMESTAMP,SYSDATE 之间的区别

    这些函数都可以返回当前的系统时间,但它们之间有什么区别呢??大家先看一下以下这个例子. select NOW(), CURRENT_TIMESTAMP(),SYSDATE(); 从上面的例子可以看出返 ...

  4. iOS --NSAttributedString

    字符属性可以应用于 attributed string 的文本中. 文/iOS_成才录(简书作者) 原文链接:http://www.jianshu.com/p/03a741246737 著作权归作者所 ...

  5. Windows平台下利用APM来做负载均衡方案 - 负载均衡(下)

    概述 我们在上一篇Windows平台分布式架构实践 - 负载均衡中讨论了Windows平台下通过NLB(Network Load Balancer) 来实现网站的负载均衡,并且通过压力测试演示了它的效 ...

  6. 运行时报错:java.net.BindException: Address already in use: JVM_Bind <null>:8080 (或8009或8005)

    修改Tomcat端口号步骤:1.找到Tomcat目录下的conf文件夹2.进入conf文件夹里面找到server.xml文件3.打开server.xml文件(打开方式选择记事本)4.在server.x ...

  7. 搭建自己的PHP框架心得(一)

    h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h ...

  8. YARN与MRv1的对比

    YARN与MRv1的对比 转载请注明出处:http://www.cnblogs.com/BYRans/ Hadoop 1.0存在的问题 由于Hadoop 1.0的良好特性,Hadoop 1.0被应用到 ...

  9. java实现基于activeMQ的消息推送

    一. 准备工作 1. 点击此下载相关的第三方jar包,并在工程中引用 二. spring配置文件:application.xml <?xml version="1.0" en ...

  10. linux shell 比较文件夹内容 diff

    diff -ruNa test1 test2 > test12.diff   -r   比较子目录中的文件 -u  以合并的方式显示文件的不同 -N 比较目录时,若文件A仅出现在某个目录中,预设 ...