前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >记一次Spring中HttpMessageConverter的源码分析

记一次Spring中HttpMessageConverter的源码分析

作者头像
代码宇宙
发布2023-02-23 10:05:13
5880
发布2023-02-23 10:05:13
举报
文章被收录于专栏:代码宇宙代码宇宙

阅读本文大概需要 3 分钟。

最近在使用Spring时遇到一个关于JSON解析的问题,@Response的接口如果返回值为一个Interfacce那么结果将变为空对象,也就是{},记录一下,防止再次踩坑。

前两天,业务部门反映,官网有新闻数据接口返回数据为空,导致官网无法访问。于是我着手开始查找原因。

1.

当然是首先怀疑是不是代码出错导致JSON返回了空对象,于是我直接debug了一下controller的代码,直接call到返回值那一行,发现返回值到响应时还是正常的,可以确定代码是没有问题的,排除。

2.

排除了业务代码问题后,我的注意力放在了项目中的几个拦截器上,会不会是拦截器导致的数据被刷掉了?

进行逐一排查,但是奇怪的是拦截器并没有做什么修改接口响应的操作,仅仅是记录日志和一些无关紧要的操作

3.

到这一步,问题的原因已经超出了搜索引擎和个人经验能解决的范畴了,于是我开始翻代码提交记录,试图找出影响接口响应值的修改。

由于ResponseBody注解和JSON解析框架有着密切的关系,所以着重排查有关JSON的依赖引用,经过我的排查,发现jackson依赖在最近的提交中被删除。

问题的原因浮出水面,Jackson的引用被删除,导致Spring默认的HttpMessageConverter由Jackson变为了默认的Gson。

Gson解析的 ”BUG“ (姑且称为BUG,后面会解析)导致对象解析失败,所以响应变为了{}

问题原因找到后,添加上Jackson依赖,测试,响应正常

虽然问题解决,但是我还是想要尝试去探究问题的原因

因为知道了是由于HttpMessageConverter的JSON解析器导致,所以我直接跟踪代码定位到解析器执行部分。

1.

AbstractMessageConverterMethodProcessor 类

核心代码:

这里循环了所有的HttpMessageConverter也就是消息处理器,每个HttpMessageConverter都会有一个canWrite方法,来确认是否执行。

当所有条件都满足时,会进入 HttpMessageConverter的write方法,也就是我用红框圈起来的代码。

2.

继续跟踪会进入AbstractGenericHttpMessageConverter类的write方法,这个类是消息处理器的基类,我们能看到这个方法处理了StreamingHttpOutputMessage类型,随之调用了子类的writeInternal方法。

3.

继续跟踪代码进入具体的Gson解析器实现类GsonHttpMessageConverter的writeInternal方法,代码如下

OK,到这一步,已经完全定位到了导致响应为{}的原因所在,再来看 继续分析

4.

这里调用了Gson的toJson方法,并且传入了源对象,对象Type类型,以及一个输出流,这里需要注意的是传入的Type类型是返回值的类型也就是一个接口,这样做有什么后果呢?继续进入toJson方法

首先,这个方法的核心是根据传入的type类型构建了一个Adapter对象

5.

就是它!胜利在眼前,我们进入~

这个方法看起来有点复杂,没关系,大家只关注我圈起来的核心部分,也就是真正的构造部分,这一句会创建一个TypeAdapter对象,现在查看其代码

这里很简单,就是获取一下全部的字段然后创建一个Adapter对象,但是来再看getBoundFields方法

我们看到这里会判断type如果是一个接口便不会往下执行了,也就是说这个Adapter的字段列表将是空,空对象生成出来的Json是{}也就是必然结果了~

分析完毕,一开始我以为是Gson的BUG,后来慢慢分析发现这是Spring中GsonHttpMessageConverter 实现类的 BUG....

附上我提交的issues链接:

https://github.com/spring-projects/spring-framework/issues/24234

本Demo源码链接:

https://github.com/iwangjie/GsonTest

如果你喜欢这篇文章,再看,转发+关注。

生活很美好,明天见(。・ω・。)ノ♡

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 代码宇宙 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档