Spring 消息转换器和注解控制器
1、什么是消息转换器?
@RequestBody 和 @ResponseBody 两个注解,分别完成请求报文到对象和对象到响应报文的转换。
底层这种灵活的消息转换机制,就是 Spring3.x 中新引入的 HttpMessageConverter,即消息转换器机制。
而负责这种机制的主要接口HttpMessageConverter及其各种子类(StringHttpMessageConverter等),就是消息转换器。
2、消息转换器结构:HttpMessageConverter
消息转换器的结构如下图
- HttpInputMessage 这个接口是 SpringMVC 内部对一次 Http 请求报文的抽象
- HttpOutputMessage 这个接口是 SpringMVC 内部对一次 Http 响应报文的抽象
- HttpMessageConverter 这个接口对消息转换器最高层次的接口抽象
- 其read()方法接收 HttpInputMessage 作为入参,负责读取请求报文
- canRead()方法负责判断请求报文是否可以由该消息转换器处理
- 其 write()方法接收 HttpOutputMessage 作为入参,负责将数据写入响应报文
- canWrite()方法负责判断响应报文是否可以由该消息转换器处理
接口说明见图:
请求处理流程见图:
3、Spring 调用逻辑
3.1 HandlerMethodArgumentResolver 接口 和 HandlerMethodReturnValueHandler 接口
这两个接口只是声明,定义一些方法。具体的实现才是最终处理。
- HandlerMethodArgumentResolver 是将请求报文绑定到处理方法形参的策略接口
- HandlerMethodReturnValueHandler 是对处理方法返回值进行处理的策略接口。
3.2 RequestResponseBodyMethodProcessor 类
- 该类同时实现了HandlerMethodArgumentResolver 接口 和 HandlerMethodReturnValueHandler 接口。所以充当了方法参数解析和返回值处理两种角色 。
3.2.1 对 HandlerMethodArgumentResolver 接口的实现 ( resolveArgument()方法)
- 实现可以见源码,这里只说明观看逻辑。
- 依次进入:resolveArgument()方法→readWithMessageConverters()方法→super.readWithMessageConverters()方法
- 然后可以看到先调用HttpMessageConverter的canRead()方法,校验通过后调用read()方法。
3.2.2 对 HandlerMethodReturnValueHandler 接口的实现 ( handleReturnValue()方法)
- 实现可以见源码,这里只说明观看逻辑。
- 依次进入:handleReturnValue()方法→writeWithMessageConverters()方法[参数不同]→writeWithMessageConverters()方法[参数不同]
- 然后可以看到先调用HttpMessageConverter的canWrite()方法,校验通过后调用write()方法。
4、HttpMessageConverter子类及其在SpringMVC中的使用
以我们代码中的一个配置作为说明,并具体理解这个加载过程:
<mvc:annotation-driven>
<mvc:message-converters>
<ref bean="fastJsonHttpMessageConverter"/>
<ref bean="sourceHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="sourceHttpMessageConverter"
class="org.springframework.http.converter.xml.SourceHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/xml;charset=UTF-8</value>
<value>text/xml;charset=UTF-8</value>
</list>
</property>
</bean>
<bean id="fastJsonHttpMessageConverter"
class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
4.1 注解的解析(注解控制器)及加载HttpMessageConverter
主要参考文章: SpringMVC关于json、xml自动转换的原理研究-附带源码分析 - format丶 - 博客园
对于注解的解析:<mvc:annotation-driven/>
。该解析由类org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
的parse()
方法处理。
- 源码路径:AnnotationDrivenBeanDefinitionParser类→parse()方法→getMessageConverters()方法。
- 源码中可知,如果没有配置
<mvc:message-converters>
属性,则加载默认的HttpMessageConverter。- 默认的有4个基础的,和5个需要条件再加载的。(这部分不做说明,不属于本文内容)
- 如果配置了,则只加载配置的HttpMessageConverter
- 源码中可知,如果没有配置
如同上述配置,则只会加载两个sourceHttpMessageConverter
和fastJsonHttpMessageConverter
。
4.2 HttpMessageConverter的supportedMediaTypes属性作用
我们配置了多个HttpMessageConverter,而每个HttpMessageConverter可以处理哪些类型的请求则由supportedMediaTypes属性定义(不止该属性,但也是一部分)
这部分的具体使用在:
- 读部分参考【3.2.1】,找到canRead方法的调用地方之后,我们看canRead方法的实现。
- 以FastJsonHttpMessageConverter为例,它的canRead方法实现实际调用的时父类(AbstractHttpMessageConverter)的canRead方法实现
- 父类的实现如下,可以看到有对
supportedMediaType
的过滤
- 父类的实现如下,可以看到有对
- 以FastJsonHttpMessageConverter为例,它的canRead方法实现实际调用的时父类(AbstractHttpMessageConverter)的canRead方法实现
至此,我们可以确定,XML的配置中的supportedMediaTypes会音响该消息转换器可以处理的请求。以上述配置为例,sourceHttpMessageConverter负责处理XML数据格式的请求;fastJsonHttpMessageConverter处理json格式的请求。
canWrite方法也会用到supportedMediaTypes,可以自行梳理。至此,消息转换器的配置以及生效过程就比较清晰了。
5、参考:
- SpringMVC 源码剖析(五)- 消息转换器 HttpMessageConverter - 相见欢的个人空间 - OSCHINA
注:本篇博客就是该文章的翻版,所以原文很重要。- SpringMVC关于json、xml自动转换的原理研究-附带源码分析 - format丶 - 博客园
注:对配置的生效过程说明很详细,可以参考。- Spring MVC 解读—— - Don't worry, Loser. - OSCHINA
注:对于Spring XML配置的解析说明很清楚。重点: 标签解析都是由BeanDefinitionParser接口的子类来完成的。还有对于AnnotationDrivenBeanDefinitionParser 的详细解析。- springMVC的消息转换器(Message Converter) - 简书
注:对于自定义消息转换器说明很棒,源码说明也不错。- SpringMVC HttpMessageConverter 匹配规则 - - SegmentFault 思否
注:匹配规则,很深奥看不懂的感觉,后续再看。
Spring 消息转换器和注解控制器的更多相关文章
- ActiveMQ之spring集成消息转换器MessageConverter
MessageConverter的作用主要有两方面,一方面它可以把我们的非标准化Message对象转换成我们的目标Message对象,这主要是用在发送消息的时候:另一方面它又可以把我们的Message ...
- 【spring-boot神器】第一篇:拦截器,过滤器,监听器,控制器,消息转换器,AOP执行顺序
整理一下这几天学习的资料和代码 第一部分.上代码 1.spring各种器的实现,idea搭建spring-boot的教程在这里http://www.jianshu.com/p/9082a533fa3c ...
- SpringMVC源码剖析5:消息转换器HttpMessageConverter与@ResponseBody注解
转自 SpringMVC关于json.xml自动转换的原理研究[附带源码分析] 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Spring源码 ...
- HandlerMethodArgumentResolver(三):基于消息转换器的参数处理器【享学Spring MVC】
每篇一句 一个事实是:对于大多数技术,了解只需要一天,简单搞起来只需要一周.入门可能只需要一个月 前言 通过 前面两篇文章 的介绍,相信你对HandlerMethodArgumentResolver了 ...
- Spring Boot项目中如何定制HTTP消息转换器
在构建RESTful数据服务过程中,我们定义了controller.repositories,并用一些注解修饰它们,但是到现在为止我们还没执行过对象的转换--将java实体对象转换成HTTP的数据输出 ...
- 【Spring学习笔记-MVC-1.3】消息转换器HttpMessageConverter
作者:ssslinppp 参考链接: SpringMVC源码剖析(五)-消息转换器HttpMessageConverter: http://my.oschina.net/lichhao/b ...
- Spring消息之STOMP
一.STOMP 简介 直接使用WebSocket(或SockJS)就很类似于使用TCP套接字来编写Web应用.因为没有高层级的线路协议(wire protocol),因此就需要我们定义应用之间所发送消 ...
- HttpMessageConverter(消息转换器 )和@responsebody使用(转)
@responsebody表示该方法的返回结果直接写入HTTP response body中 一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@resp ...
- Spring RESTful + Redis全注解实现恶意登录保护机制
好久没更博了... 最近看了个真正全注解实现的 SpringMVC 博客,感觉很不错,终于可以彻底丢弃 web.xml 了.其实这玩意也是老东西了,丢弃 web.xml,是基于 5.6年前发布的 Se ...
随机推荐
- P4425 【[HNOI/AHOI2018]转盘】
颂魔眼中的一眼题我大湖南竟无一人\(AC\) 首先我们考虑一个性质:我们肯定存在一种最优解,满足从某个点出发,一直往前走,不停下来. 证明:我们假设存在一种最优解,是在\(t_i\)的时候到达\(a\ ...
- 2019暑期金华集训 Day6 计算几何
自闭集训 Day6 计算几何 内积 内积不等式: \[ (A,B)^2\le (A,A)(B,B) \] 其中\((A,B)\)表示\(A\cdot B\). (好像是废话?) 叉积 \[ A\tim ...
- 记一次清理缓存的小事情(chrome) chrome下清理缓存不生效的问题
记一次清理缓存的小事情(chrome) chrome下清理缓存不生效的问题 前端开发中会经常涉及清理缓存的事情. 在一次开发后, 需要清理缓存,一个哥们怎么清理都不生效, 于是向我求救. 在我看了下后 ...
- 设置windows service方式启动GitBlit
1.在Gitblit目录下,找到installService.cmd文件. 2.用记事本或者notepad++打开 2.1修改 ARCH 32位系统:SET ARCH=x86 64位系统:SET AR ...
- spark学习记录-1
mapreduce的限制 适合“一趟”计算操作 很难组合和嵌套操作符号 无法表示迭代操作 ======== 由于复制.序列化和磁盘IO导致mapreduce慢 复杂的应用.流计算.内部查询都因为map ...
- laravel删除文件
laravel删除文件 一.总结 一句话总结: 1.注意disk:disk决定路径 2.删单个文件的时候就用删单个文件的方式,别用删多个文件的方式(也就是参数别数组) public function ...
- JSON HiJacking攻击
JSON劫持类似于CSRF攻击,为了了解这种攻击方式,我们先看一下Web开发中一种常用的跨域获取数据的方式:JSONP. 先说一下JSON吧,JSON是一种数据格式,主要由字典(键值对)和列表两种存在 ...
- CUDA编程之快速入门【转】
https://www.cnblogs.com/skyfsm/p/9673960.html CUDA(Compute Unified Device Architecture)的中文全称为计算统一设备架 ...
- 我大概知道他在说什么了,是对内存单元的竞争访问吧。Python有GIL,在执行伪码时是原子的。但是伪码之间不保证原子性。 UDP丢包,你是不是做了盲发?没有拥塞控制的情况下,确实会出现丢包严重的情况。你先看看发送速率,还有是否带有拥塞控制。
我大概知道他在说什么了,是对内存单元的竞争访问吧.Python有GIL,在执行伪码时是原子的.但是伪码之间不保证原子性. UDP丢包,你是不是做了盲发?没有拥塞控制的情况下,确实会出现丢包严重的情 ...
- javaweb--Rest访问(RestTemplate)
Rest访问(RestTemplate)在实际的项目中,往往需要发送一个Get/Post请求到其他的系统(Rest API),比如向人员管理部门请求,然后解析返回信息获取该用户的基本信息等.JDK传统 ...