首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164…
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca…
一 . 前言
这一篇只关注一个小点 , 学习一下 SpringMVC 是如何进行数据转换.
二. 数据承接
2.1 数据转换常见用法
1 | java复制代码@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") |
以 fasterxml 为例 , 它属于外包 , 但是 SpringMVC 对其进行了集成 , 那么该功能是如何进行处理的呢 ?
2.2 数据转换的源码梳理
JSON 的转换流程主要为 HttpMessageConverter 模块 , 先来看一下之前的流程图
可以看到 , 会先通过 HandlerMethodArgumentResolverComposite 对属性进行解析 , 通过 HandlerMethodReturnValueHandlerComposite 对返回进行解析 , 他们都会通过 AbstractMessageConverterMethodArgumentResolver 进行统一的处理.
2.2.1 MessageConverter 的加载和初始化
1 | java复制代码// 注意 , 该类在 Spring AutoConfigure 中 , 并不是 MVC 专属 |
2.2.2 转化的入口
MessageConvert 转换的核心入口为 AbstractMessageConverterMethodArgumentResolver , 来看一下处理逻辑 (之前已经看过相关的代码 , 这里只截取一部分 -> juejin.cn/post/696584…)
1 | JAVA复制代码// C- AbstractMessageConverterMethodArgumentResolver # readWithMessageConverters |
Converter 有很多种 , 此处以 AbstractJackson2HttpMessageConverter 为例 , 其向下的处理流程为 :
- Step 1 : AbstractJackson2HttpMessageConverter # read : 进入 Converter 解析操作
- Step 2 : AbstractJackson2HttpMessageConverter # readJavaType : 获取 Java 类型
- Step 3 : CollectionDeserializer # deserialize : 进入转码解析
- Step 4 : BeanDeserializer # deserializeFromObject : 循环处理 Object Param
- Step 5 : deserializeAndSet : 解析并且设置数据
Step 4 : 循环处理 Object Param
最主要的操作就是从 deserializeFromObject 开始 ,此处将value 解析为 Bean
1 | java复制代码public Object deserializeFromObject(JsonParser p, DeserializationContext ctxt) throws IOException |
Step 5 : 数据转换和设置
1 | java复制代码public void deserializeAndSet(JsonParser p, DeserializationContext ctxt,Object instance) throws IOException{ |
Step 6 : 具体类进行序列化
此处以 DateDeserializers 为例 , 对应得序列化类还有好多 , 有兴趣得可以进去看看
1 | java复制代码// C- DateDeserializers |
这里再来回顾下 , DateFormat 是什么时候注入的 ?
在属性进入得时候 , 会进行 createContextual 操作 ,为对象创建一个容器上下文进行处理 (容器的处理很有意思 , 有机会也要看看 , 理解这种思想)
- CollectionDeserializer # createContextual : 创建容器
- DeserializationContext # findContextualValueDeserializer : 查找当前 value 对应的序列化类
1 | java复制代码public static JsonDeserializer<?> find(Class<?> rawType, String clsName) |
容器就像一个小车库, 当准备买车后 , 为他准备各种工具 , 用于自己的保养和维护 , 来解决各种问题 ,为其进行改装 ,不过这种思想 , 在单调的系统中其实很难实现
三 .数据导出
那么数据导出时是如何进行转换处理的呢 ?
write 数据同样通过 for 循环 messageConverters 来进行处理 , 其调用流程如下 :
- RequestMappingHandlerAdapter # handleInternal : 此时在其中进行 invokeAndHandle 方法进行处理
- RequestMappingHandlerAdapter # invokeHandlerMethod :
- ServletInvocableHandlerMethod # invokeAndHandle : 准备 Return Value
- HandlerMethodReturnValueHandlerComposite # handleReturnValue :
- RequestResponseBodyMethodProcessor # handleReturnValue :
- AbstractMessageConverterMethodProcessor # writeWithMessageConverters : 处理 converter 列表
在 writeWithMessageConverters 中核心流程如下 ,我们重点关注一下 :
1 | java复制代码for (HttpMessageConverter<?> converter : this.messageConverters) { |
可以看到 , 使用的 converter 还是那些 , 处理的逻辑也大致相同 , 其主流程中分为2大部分 :
- Step 1 : 前置处理 , 调用 RequestResponseBodyAdviceChain 链式处理
- Step 2 : 调用具体的 converter 进行 write 操作
Advice 主要分为 RequestBodyAdvice 和 ResponseBodyAdvice 两种
总结
有点偏题了 , 不算 MVC 的核心内容 , 主要是日常使用中出现了未生效的问题, 排查了一下原因 . 顺便出了一篇文档 , 以备以后使用.
Jackson 的底层看的很过瘾 , 很多地方想深入但是精力有限 , 它展现了序列化的核心流程 , 有机会一定要深入的看看
参考文档
developer.aliyun.com/article/769…
本文转载自: 掘金