记一次Spring中HttpMessageConverter的源码分析

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

 

记一次Spring中HttpMessageConverter的源码分析_第1张图片

 

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

 

记一次Spring中HttpMessageConverter的源码分析_第2张图片

 

 

 

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

 

1.

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

 

记一次Spring中HttpMessageConverter的源码分析_第3张图片

 

2.

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

 

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

 

记一次Spring中HttpMessageConverter的源码分析_第4张图片

 

3.

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

 

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

 

 

记一次Spring中HttpMessageConverter的源码分析_第5张图片

 

 

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

 

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

 

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

 

记一次Spring中HttpMessageConverter的源码分析_第6张图片

 

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

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

 

                                                                                                

 

1.

AbstractMessageConverterMethodProcessor 类

核心代码:

记一次Spring中HttpMessageConverter的源码分析_第7张图片

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

 

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

 

2.

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

 

 

记一次Spring中HttpMessageConverter的源码分析_第8张图片

 

3.

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

 

记一次Spring中HttpMessageConverter的源码分析_第9张图片

 

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

 

4.

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

记一次Spring中HttpMessageConverter的源码分析_第10张图片

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

 

5.

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

 

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

记一次Spring中HttpMessageConverter的源码分析_第11张图片

 

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

记一次Spring中HttpMessageConverter的源码分析_第12张图片

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

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

 

附上我提交的issues链接:

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

 

本Demo源码链接:

https://github.com/iwangjie/GsonTest

 

 

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

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

 

记一次Spring中HttpMessageConverter的源码分析_第13张图片 欢迎关注

 

你可能感兴趣的:(问题记录,Spring,Gson)