Spring加载消息转换器的流程以及自定义类型转换器的优先级
目录
一、加载转换器的流程,通过下面详细的时序图可知
原图见百度云
二、自定义转换器的加载逻辑
1、总共有三种方式
a、@bean;
b、实现WebMvcConfigurer类的方法configureMessageConverters 或者 extendMessageConverters方法;
c、
如果b和c同时定义,只会生效c的方式;
下面讲讲a、b同时使用和 a、c同时使用的优先级区别
2、a 和 c同时使用
-
-
继承WebMvcConfigurationSupport类,覆盖方法configureMessageConverters
-
如下图:
结论:这种方法,只会有JavaSerializationConverter1、JavaSerializationConverter2两个转换器在处理json请求时生效,并且JavaSerializationConverter2在JavaSerializationConverter1前面。
加载流程如下:
调用栈如下:
preInstantiateSingletons:737, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:867, AbstractApplicationContext (org.springframework.context.support)
refresh:548, AbstractApplicationContext (org.springframework.context.support)
最后会调用org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
在图①中,遍历500多个bean,进行非延迟加载的bean创建,这里会先创建我们自定义的转换器JavaSerializationConverter,然后会创建requestMappingHandlerAdapter
创建requestMappingHandlerAdapter的过程:
这个对象是由org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerAdapter这个bean实例化方法创建的,因为我们自定义MyConverterConfig2继承了WebMvcConfigurationSupport对象,所以这一系列方法实际是自定义对象触发的如图:
图中①会给org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#messageConverters属性赋值四个默认转换器如下:
赋值后回到上面图②:会调用MyConverterConfig2的父类WebMvcConfigurationSupport#getMessageConverters的方法,如下:
②执行MyConverterConfig2#configureMessageConverters方法加入一个转换器;
③这时WebMvcConfigurationSupport#messageConverters属性不为空;
④不会执行,也就不会记载spring默认八个转换器;
⑤执行MyConverterConfig2#extendMessageConverters方法加入一个转换器;
方法退出后,WebMvcConfigurationSupport#messageConverters就有两个我们自定义的转换器:
①中会调用RequestMappingHandlerAdapter#getDefaultArgumentResolvers获取一系列默认参数解析器列表:
创建过程细化流程见第一个标题画的时序图,这里不详细列出,大概流程如下:
如下图:
①中匿名创建了WebMvcConfigurationSupport的子类,添加了defaultMessageConverters方法,改子类没有重写父类任何方法;
这个时候因为是匿名创建的子类,没有给父类任何属性赋值,也就意味着图中:
②是空方法;
③这时属性还是空的;
④这里会获取spirng的八个默认转换器;
⑤是空方法;
-
- spring 八个转换器和springboot 默认三个转换器组合,并赋值给HttpMessageConverters#converters(这个对象在springboot包中,也就是springboot的转换器所属对象),并没有赋值给WebMvcConfigurationSupport#messageConverters,所以WebMvcConfigurationSupport#messageConverters(这个对象在spring包中,也就是spring中生效的还是我们自定义的两个转换器)中还是上面我们自定义类MyConverterConfig2中方法添加的两个转换器;
3、a 和 b同时使用
-
-
实现WebMvcConfigurer类的方法configureMessageConverters
添加到list末尾converters.add(new JavaSerializationConverter());
-
实现WebMvcConfigurer类的方法extendMessageConverters
如下图:
-
前面流程和之前一样,只不过创建RequestMappingHandlerAdapter的对象不再是自定义的(WebMvcConfigurationSupport的子类MyConverterConfig2),而是spring自己的WebMvcConfigurationSupport对象,所以调用WebMvcConfigurationSupport#getMessageConverters
②执行WebMvcConfigurationSupport#configureMessageConverters方法,
这里会遍历三个WebMvcConfigurer,包括我们自定义的MyConverterConfig也实现了WebMvcConfigurer接口,如下:
先去遍历springboot自动配置,也就是会创建HttpMessageConverters,跟之前一样,如下图:
-
获得spring八个默认转换器,排序,xml转换器放最后;
-
-
④不会执行,也就不会再次加载spring默认八个转换器;
跟之前一样,不过是方法名改为了extendMessageConverters,继续遍历WebMvcConfigurer,包括我们自定义的MyConverterConfig,如下:
当遍历到我们自定义类的时候MyConverterConfig#extendMessageConverters,会添加自定义转换器JavaSerializationConverter2,这时有13个转换器了:
继续遍历第三个SpringDataWebConfiguration的时候,源码如下:
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { if (ClassUtils.isPresent("com.jayway.jsonpath.DocumentContext", this.context.getClassLoader()) && ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", this.context.getClassLoader())) { // 如果存在DocumentContext和ObjectMapper类型 ObjectMapper mapper = (ObjectMapper)getUniqueBean(ObjectMapper.class, this.context, ObjectMapper::new); ProjectingJackson2HttpMessageConverter converter = new ProjectingJackson2HttpMessageConverter(mapper); converter.setBeanFactory(this.context); this.forwardBeanClassLoader(converter); // ProjectingJackson2HttpMessageConverter加入到转换器第一位 converters.add(0, converter); } if (ClassUtils.isPresent("org.xmlbeam.XBProjector", this.context.getClassLoader())) { converters.add(0, this.xmlBeamHttpMessageConverter.orElseGet(() -> { return new XmlBeamHttpMessageConverter(); })); } }
从这里可以看出只要存在DocumentContext和ObjectMapper类型,就会将ProjectingJackson2HttpMessageConverter加入到转换器第一位加入到转换器列表第一位,而ProjectingJackson2HttpMessageConverter从创建的逻辑来看是支持json格式的,如下:
所以目前转换器列表第一位是ProjectingJackson2HttpMessageConverter,也就是spring默认采用的jackson的json转换器,转换器列表此时如下:
RequestMappingHandlerAdapter#messageConverters也会赋值这14个转换器
之后会执行RequestMappingHandlerAdapter#afterPropertiesSet初始化方法,进而会将14个转换器赋值给