web项目:servlet和spring的消息转换器&&消息转换器源码分析(两个扩展点)&&前后端交互消息转换链路&&自
2020-12-01 14:38:11 0 举报
web项目:servlet和spring的消息转换器&&消息转换器源码分析(两个扩展点)&&前后端交互消息转换链路&&自定义消息转换器
作者其他创作
大纲/内容
方法入参解析器
判断是否支持
springIOC启动org.springframework.context.support.AbstractApplicationContext#refresh
HttpInputMessage #getBody
所有的HttpMessageConverter的supports方法
ServletInputStream 读取原始请求报文
InputStream
configureMessageConverters(this.messageConverters);
finishBeanFactoryInitialization(beanFactory);
继承WebMvcConfigurationSupport重写configureMessageConverters,可以添加自定义HttpMessageConverters与RequestMappingHandlerAdapter和ExceptionHandlerExceptionResolver将转换器添加到列表中会关闭默认的转换器否则默认为注册。用于添加默认的消息转换器
自定义消息转换器
是否支持当前请求报文格式
configurer.mediaTypes(getDefaultMediaTypes());
添加默认的转换器
boolean supportsReturnType(MethodParameter returnType);
对应的HttpMessageConverter的readInternal方法
extends
AbstractMessageConverterMethodArgumentResolver
this.configurers.configureMessageConverters(converters);
传给接口
转换请求报文
返回前端
addDefaultHttpMessageConverters(this.messageConverters);
\"application/json\"\"application/xml\"
AbstractMessageConverterMethodProcessor
RequestResponseBodyMethodProcessor
@Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { for (WebMvcConfigurer delegate : this.delegates) { delegate.configureMessageConverters(converters); } }
判断是否能写
tomcat生命周期基础类启动
ServletRequest#getInputStream()
将返参转换成目标格式
registerListeners();
adapter.setMessageConverters(getMessageConverters());
getSupportedMediaTypes()
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer
第一次启动时,消息转换器是没有的,因此要调用添加默认消息转换器方法
canRead
result = {ArrayList@11425} size = 8 0 = {ByteArrayHttpMessageConverter@11430} 1 = {StringHttpMessageConverter@11427} 2 = {ResourceHttpMessageConverter@11431} 3 = {ResourceRegionHttpMessageConverter@11432} 4 = {SourceHttpMessageConverter@11435} 5 = {AllEncompassingFormHttpMessageConverter@11436} 6 = {Jaxb2RootElementHttpMessageConverter@11437} 7 = {MappingJackson2HttpMessageConverter@11438}
HttpMessageConverter消息转换器
自定义MyWebMvcConfigurer实现WebMvcConfigurer
完成这个上下文的bean工厂的初始化,初始化所有剩余的单例bean。
implements
循环调用所有的HttpMessageConverter,将每一个的HttpMessageConverter添加的消息转换器添加到this.messageConverters
自定义一个HttpMessageConverterextends AbstractHttpMessageConverter
方法消息转换处理器AbstractMessageConverterMethodProcessor#writeWithMessageConverters
例如
HandlerMethodArgumentResolver
针对各种类型,到项目中找是否有引入相应的依赖类,只有引入了才能解析和返回此类型的数据。springboot默认是json,就是因为内部引入了json的支持
org.springframework.boot.web.embedded.tomcat.TomcatStarter#onStartup
read和write来进行入参和返参的数据格式转换
响应返回处理器
Spring
设置消息转换器
canRead和canWrite方法来判断是否支持该类型的数据
这里存在一些问题,通过这三步添加的消息转换器是不会排重的。
ServletResponse #getOutputStream()
返参
返回
ServletOutputStream 输出 Http 的响应报文内容
启动先初始化org.springframework.boot.web.embedded.tomcat.TomcatWebServer#initialize
在Spring MVC 的设计中,一次请求报文和一次响应报文,分别被抽象为一个请求消息HttpInputMessage 和一个响应消息 HttpOutputMessage 。处理请求时,由合适的消息转换器将请求报文绑定为方法中的形参对象,在这里,同一个对象就有可能出现多种不同的消息形式,比如 json 和 xml 。同样,当响应请求时,方法的返回值也同样可能被返回为不同的消息形式,比如 json 和 xml 。
对应的HttpMessageConverter的writeInternal方法
再给ContentNegotiationManager设置属性mediaTypes
前端请求消息转换链路
WebMvcConfigurationSupport#getDefaultMediaTypes
指定消息转换器:UserHttpMessageConverter
这里存在一些问题,不同的HttpMessageConverter添加相同的消息转换器到this.messageConverters是不会排重的。
模仿源码中的StringHttpMessageConverter写一个自己的user类的消息转换器
extendMessageConverters(this.messageConverters);
入参
boolean supportsParameter(MethodParameter parameter);
请求报文的juser转properties类型。响应报文是properties转user返回
onRefresh();
WebMvcConfigurationSupport#getMessageConverters
org.apache.catalina.util.LifecycleBase#start
Spring 3.x 消息转换器HttpMessageConverter
public class UserHttpMessageConverter extends AbstractHttpMessageConverter<User> { public UserHttpMessageConverter() { //设置自定义类型 application/properties+user super(MediaType.valueOf(\"application/properties+user\")); setDefaultCharset(Charset.forName(\"UTF-8\
先添加基础的消息转换器:比如String,byte等消息转换器
将请求报文绑定到处理方法形参的策略接口
底层的消息转换机制
@Configurationpublic class MyWebMvcConfigurer implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(new UserHttpMessageConverter()); }// @Override 这三种方法都可以添加我们自定义的消息转换器// public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {// converters.add(new UserHttpMessageConverter());// }// @Bean // public HttpMessageConverter UserHttpMessageConverter() {// return new UserHttpMessageConverter();// }}
tomcat启动
@PostMapping(value = \"/json/to/properties\
再以此判断是否引入其他数据类型的消息转换器依赖
WebMvcConfigurationSupport
实例化所有剩余的(非延迟-init)单例。beanFactory.preInstantiateSingletons();
HandlerMethodReturnValueHandler
WebMvcConfigurationSupport类中配置的各种格式
请求
结论:添加自定义的消息转换器有三种方式:1、直接在配置类中通过@Bean添加。2、利用扩展点一,重写WebMvcConfigurationSupport的configureMessageConverters方法添加。3、利用扩展点二,重写WebMvcConfigurationSupport的extendMessageConverters方法添加。
第一个扩展点:添加自定义的消息转换器
对处理方法返回值进行处理的策略接口
read
Servlet
在 Spring MVC 中,可以使用 @RequestBody 和 @ResponseBody 两个注解,分别完成请求报文到对象和对象到响应报文的转换
HttpOutputMessage#getBody
controller层接口上也可以通过produce和consumer来指定返回的报文格式和请求接收的格式
不同的 HttpMessageConverter 实现类来处理各种消息形式
@Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { for (WebMvcConfigurer delegate : this.delegates) { delegate.extendMessageConverters(converters); } }
源码分析
write
第二个扩展点:添加额外的消息转换器
将入参转换成指定格式
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { for (WebMvcConfigurer delegate : this.delegates) { delegate.configureMessageConverters(converters); } }
当实例化:请求映射处理程序适配器RequestMappingHandlerAdapter
adapter.setContentNegotiationManager(mvcContentNegotiationManager());
canWrite
DelegatingWebMvcConfiguration#configureMessageConverters
方法参数解析器AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters
设置mvc内容协商管理器
0 条评论
回复 删除
下一页