oracle自定义函数返回多个值_源码分析springboot自定义jackson序列化,默认null值个性化处理返回值...

最近项目要实现一种需求,对于后端返回给前端的json格式的一种规范,不允许缺少字段和字段值都为null,所以琢磨了一下如何进行将springboot的Jackson序列化自定义一下,先看看如何实现,再去看源码第一步:写配置类
@Configurationpublic class WebConfiguration  extends WebMvcConfigurationSupport {@Override    protected void extendMessageConverters(List> converters) {        converters.stream().filter(c -> c instanceof MappingJackson2HttpMessageConverter)                .map(c ->(MappingJackson2HttpMessageConverter)c)                .forEach(c->{                    ObjectMapper mapper = c.getObjectMapper();                    // 为mapper注册一个带有SerializerModifier的Factory,此modifier主要做的事情为:当序列化类型为array,list、set时,当值为空时,序列化成[]                    mapper.setSerializerFactory(mapper.getSerializerFactory().withSerializerModifier(new MyBeanSerializerModifier()));                    c.setObjectMapper(mapper);                });    }}
第二步:编写值为null时的自定义序列化
/** * @title: MyBeanSerializerModifier * @Author junyu * 旧巷里有一个穿着白衬衫笑起来如太阳般温暖我的少年。 * 记忆里有一个穿着连衣裙哭起来如孩子般讨人喜的女孩。 * 他说,哪年树弯了腰,人见了老,桃花落了白发梢,他讲的笑话她还会笑,那便是好。 * 她说,哪年国改了号,坟长了草,地府过了奈何桥,她回头看时他还在瞧,就不算糟。 * @Date: 2020/9/12 16:44 * @Version 1.0 */public class MyBeanSerializerModifier extends BeanSerializerModifier {    private MyNullStringJsonSerializer myNullStringJsonSerializer;    private MyNullArrayJsonSerializer MyNullArrayJsonSerializer;    private MyNullObjectJsonSerializer MyNullObjectJsonSerializer;    private MyNullJsonSerializer myNullJsonSerializer;    public MyBeanSerializerModifier(){        myNullStringJsonSerializer = new MyNullStringJsonSerializer();        MyNullArrayJsonSerializer = new MyNullArrayJsonSerializer();        MyNullObjectJsonSerializer =  new MyNullObjectJsonSerializer();        myNullJsonSerializer = new MyNullJsonSerializer();    }    @Override    public ListchangeProperties(SerializationConfig config, BeanDescription beanDesc,                                                     List beanProperties) {        // 循环所有的beanPropertyWriter        beanProperties.forEach(writer ->{            // 判断字段的类型            if (isArrayType(writer)) {                //给writer注册一个自己的nullSerializer                writer.assignNullSerializer(MyNullArrayJsonSerializer);            } else if (isObjectType(writer)) {                writer.assignNullSerializer(MyNullObjectJsonSerializer);            } else if (isStringType(writer)) {                writer.assignNullSerializer(myNullStringJsonSerializer);            } else if (isPrimitiveType(writer)) {                writer.assignNullSerializer(myNullJsonSerializer);            }        });        return beanProperties;    }    // 判断是否是boolean类型    private boolean isPrimitiveType(BeanPropertyWriter writer) {        Class> clazz = writer.getType().getRawClass();        return clazz.isPrimitive();    }    // 判断是否是string类型    private boolean isStringType(BeanPropertyWriter writer) {        Class> clazz = writer.getType().getRawClass();        return clazz.equals(String.class);    }    // 判断是否是对象类型    private boolean isObjectType(BeanPropertyWriter writer) {        Class> clazz = writer.getType().getRawClass();        return !clazz.isPrimitive() && !clazz.equals(String.class)                && clazz.isAssignableFrom(Object.class);    }    // 判断是否是集合类型    protected boolean isArrayType(BeanPropertyWriter writer) {        Class> clazz = writer.getType().getRawClass();        return clazz.isArray() || clazz.equals(List.class) || clazz.equals(Set.class);    }    class MyNullJsonSerializer extends JsonSerializer<Object>{        @Override        public void serialize(Object value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {            if (value == null) {                jgen.writeNull();            }        }    }    class MyNullStringJsonSerializer extends JsonSerializer<Object>{        @Override        public void serialize(Object value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {            if (value == null) {                jgen.writeString(StringUtils.EMPTY);            }        }    }    class MyNullArrayJsonSerializer extends JsonSerializer<Object>{        @Override        public void serialize(Object value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {            if (value == null) {                jgen.writeStartArray();                jgen.writeEndArray();            }        }    }    class MyNullObjectJsonSerializer extends JsonSerializer<Object>{        @Override        public void serialize(Object value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {            if (value == null) {                jgen.writeStartObject();                jgen.writeEndObject();            }        }    }}
这样基本配置就完事了,现在可以试试效果了,自己定义一个bean用来返回,定义一个简单的controller去接受访问就行了,博主就不进行写这两个类了。返回结果如下 92b17005915b6099678fb16e2b98d577.png

这是我的项目需求需要实现的,大家可以根据的自己的需求去改写MyBeanSerializerModifier这个类。还有另一种实现方式:不继承

@Configurationpublic class WebConfiguration {@Bean    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();        ObjectMapper mapper = mappingJackson2HttpMessageConverter.getObjectMapper();        mapper.setSerializerFactory(mapper.getSerializerFactory().withSerializerModifier(new MyBeanSerializerModifier()));        mappingJackson2HttpMessageConverter.setObjectMapper(mapper);        return mappingJackson2HttpMessageConverter;    }}

这种方法也是可以设置成功的,主要是不是继承了WebMvcConfigurationSupport类,毕竟这个类有很多可以自定义的方法,用起来顺手而已。

  第一个问题:为什么继承WebMvcConfigurationSupport后,要重写extendMessageConverters方法;

  第二个问题:为什么继承WebMvcConfigurationSupport后,再去生成@Bean的MappingJackson2HttpMessageConverter,却不生效;

  第三个问题:为什么不继承WebMvcConfigurationSupport时,生成@Bean的MappingJackson2HttpMessageConverter是生效的;

  这几个问题,都需要我们进入源码观察,废活不多说,我们来进入源码的世界。解决问题之前必须搞清楚在哪里进行了序列化。

  第一步:我们要弄清楚在哪里进行的Jackson序列化,看这里https://www.processon.com/embed/5f5c6464f346fb7afd55448b,从返回请求开始的序列化基本流程就在这里了,虽然图有点low,但是清楚的记录的每一步,我们主要看一下下面的源码

/*    /**********************************************************    /* Field serialization methods    /**********************************************************     */    //序列化每一个字段    protected void serializeFields(Object bean, JsonGenerator gen, SerializerProvider provider)            throws IOException{        final BeanPropertyWriter[] props;        if (_filteredProps != null && provider.getActiveView() != null) {            props = _filteredProps;        } else {            props = _props;        }        int i = 0;        try {            for (final int len = props.length; i < len; ++i) {                BeanPropertyWriter prop = props[i];                if (prop != null) { // can have nulls in filtered list                    //关键就在这一步进行的序列化,而为什么BeanPropertyWriter是数组,我们一会解释                    prop.serializeAsField(bean, gen, provider);                }            }            if (_anyGetterWriter != null) {                _anyGetterWriter.getAndSerialize(bean, gen, provider);            }        } catch (Exception e) {            String name = (i == props.length) ? "[anySetter]" : props[i].getName();            wrapAndThrow(provider, e, bean, name);        } catch (StackOverflowError e) {            // 04-Sep-2009, tatu: Dealing with this is tricky, since we don't have many            //   stack frames to spare... just one or two; can't make many calls.            // 10-Dec-2015, tatu: and due to above, avoid "from" method, call ctor directly:            //JsonMappingException mapE = JsonMappingException.from(gen, "Infinite recursion (StackOverflowError)", e);            JsonMappingException mapE = new JsonMappingException(gen, "Infinite recursion (StackOverflowError)", e);            String name = (i == props.length) ? "[anySetter]" : props[i].getName();            mapE.prependPath(new JsonMappingException.Reference(bean, name));            throw mapE;        }    }

既然已经找到了在哪里要进行序列化,那我们看看是如何实现的:

/**     * Method called to access property that this bean stands for, from within     * given bean, and to serialize it as a JSON Object field using appropriate     * serializer.     */    @Override    public void serializeAsField(Object bean, JsonGenerator gen,                                 SerializerProvider prov) throws Exception {        // inlined 'get()'        final Object value = (_accessorMethod == null) ? _field.get(bean)                : _accessorMethod.invoke(bean, (Object[]) null);        // Null handling is bit different, check that first        if (value == null) {            //看到这里大家应该就知道null值是如何进行序列化 的了,如果不配置的话,默认是返回null            //因为_nullSerializer是有默认值的,大家看一看这个类的初始化            //那我们要是改一下_nullSerializer的这个默认类,让每一个字段调用我们自己的_nullSerializer不就可以了吗,            //yes、我们就这么干            if (_nullSerializer != null) {                gen.writeFieldName(_name);                _nullSerializer.serialize(null, gen, prov);            }            return;        }        // then find serializer to use        JsonSerializer ser = _serializer;        if (ser == null) {            Class> cls = value.getClass();            PropertySerializerMap m = _dynamicSerializers;            ser = m.serializerFor(cls);            if (ser == null) {                ser = _findAndAddDynamic(m, cls, prov);            }        }        // and then see if we must suppress certain values (default, empty)        if (_suppressableValue != null) {            if (MARKER_FOR_EMPTY == _suppressableValue) {                if (ser.isEmpty(prov, value)) {                    return;                }            } else if (_suppressableValue.equals(value)) {                return;            }        }        // For non-nulls: simple check for direct cycles        if (value == bean) {            // three choices: exception; handled by call; or pass-through            if (_handleSelfReference(bean, gen, prov, ser)) {                return;            }        }        gen.writeFieldName(_name);        if (_typeSerializer == null) {            ser.serialize(value, gen, prov);        } else {            ser.serializeWithType(value, gen, prov, _typeSerializer);        }    }
那我们来解决第一个问题:为什么继承WebMvcConfigurationSupport后,要重写extendMessageConverters方法?

  不知道大家记得不记得我们请求过来的时候,如果我们配置类集成了WebMvcConfigurationSupport类,dispatchservlet处理handle请求的ha,其实就是RequestMappingHandlerAdapter类,这个类是在WebMvcConfigurationSupport配置的,看源码:

@Bean    public RequestMappingHandlerAdapter requestMappingHandlerAdapter(            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,            @Qualifier("mvcConversionService") FormattingConversionService conversionService,            @Qualifier("mvcValidator") Validator validator) {        RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();        adapter.setContentNegotiationManager(contentNegotiationManager);        adapter.setMessageConverters(getMessageConverters());        adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));        adapter.setCustomArgumentResolvers(getArgumentResolvers());        adapter.setCustomReturnValueHandlers(getReturnValueHandlers());        if (jackson2Present) {            adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));            adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));        }        AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();        configureAsyncSupport(configurer);        if (configurer.getTaskExecutor() != null) {            adapter.setTaskExecutor(configurer.getTaskExecutor());        }        if (configurer.getTimeout() != null) {            adapter.setAsyncRequestTimeout(configurer.getTimeout());        }        adapter.setCallableInterceptors(configurer.getCallableInterceptors());        adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());        return adapter;    }
adapter.setMessageConverters(getMessageConverters());当大家看到这个方法的时候,应该就会想到我们的默认jackson转换器:MappingJackson2HttpMessageConverter,我们看看这个getMessageConverters()有什么幺蛾子:
protected final List> getMessageConverters() {        if (this.messageConverters == null) {            this.messageConverters = new ArrayList<>();            configureMessageConverters(this.messageConverters);            if (this.messageConverters.isEmpty()) {                addDefaultHttpMessageConverters(this.messageConverters);            }            extendMessageConverters(this.messageConverters);        }        return this.messageConverters;    }
protected final void addDefaultHttpMessageConverters(List> messageConverters) {            //这些都不用管,跟我们的需求没啥作用,我们只看关键的部分,在下面            messageConverters.add(new ByteArrayHttpMessageConverter());            messageConverters.add(new StringHttpMessageConverter());            messageConverters.add(new ResourceHttpMessageConverter());            messageConverters.add(new ResourceRegionHttpMessageConverter());            try {                messageConverters.add(new SourceHttpMessageConverter<>());            }            catch (Throwable ex) {                // Ignore when no TransformerFactory implementation is available...            }            messageConverters.add(new AllEncompassingFormHttpMessageConverter());            if (romePresent) {                messageConverters.add(new AtomFeedHttpMessageConverter());                messageConverters.add(new RssChannelHttpMessageConverter());            }            if (jackson2XmlPresent) {                Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();                if (this.applicationContext != null) {                    builder.applicationContext(this.applicationContext);                }                messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));            }            else if (jaxb2Present) {                messageConverters.add(new Jaxb2RootElementHttpMessageConverter());            }            if (jackson2Present) {                Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();                if (this.applicationContext != null) {                    builder.applicationContext(this.applicationContext);                }                //解析我们返回值的转换器就是在这里生成的                messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));            }            else if (gsonPresent) {                messageConverters.add(new GsonHttpMessageConverter());            }            else if (jsonbPresent) {                messageConverters.add(new JsonbHttpMessageConverter());            }            if (jackson2SmilePresent) {                Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();                if (this.applicationContext != null) {                    builder.applicationContext(this.applicationContext);                }                messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));            }            if (jackson2CborPresent) {                Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor();                if (this.applicationContext != null) {                    builder.applicationContext(this.applicationContext);                }                messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));            }        }

我们的MappingJackson2HttpMessageConverter类就是这里初始化的,初始化的时候默认的_nullSerializer也会被初始化,大家肯定说这已经初始化完了,该咋办,大家应该看到了extendMessageConverters(this.messageConverters);这个方法就是用来重写实现的了,这回知道我们继承WebMvcConfigurationSupport后,为什么要重写extendMessageConverters,我们的配置类遍历已经获取到的convert,然后对我们想要的转换器进行修改添加,那修改完了,是在哪里起作用的呢,我们再来看一看源码:

在序列化之前有一些方法是可以进行修改操作的,在调用writeWithMessageConverters方法的时候:

protected void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,                                                      ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)                throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {            .......            MediaType selectedMediaType = null;            MediaType contentType = outputMessage.getHeaders().getContentType();            boolean isContentTypePreset = contentType != null && contentType.isConcrete();            if (isContentTypePreset) {                if (logger.isDebugEnabled()) {                    logger.debug("Found 'Content-Type:" + contentType + "' in response");                }                selectedMediaType = contentType;            }            else {                HttpServletRequest request = inputMessage.getServletRequest();                List acceptableTypes = getAcceptableMediaTypes(request);                //这里进行自定义操作修改MappingJackson2HttpMessageConverter                List producibleTypes = getProducibleMediaTypes(request, valueType, targetType);                .......            if (selectedMediaType != null) {                selectedMediaType = selectedMediaType.removeQualityValue();                //这这里进行选择我们的MappingJackson2HttpMessageConverter去自定义序列化                for (HttpMessageConverter> converter : this.messageConverters) {                    GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?                            (GenericHttpMessageConverter>) converter : null);                    if (genericConverter != null ?                            ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :                            converter.canWrite(valueType, selectedMediaType)) {                        body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,                                (Class extends HttpMessageConverter>>) converter.getClass(),                                inputMessage, outputMessage);                        if (body != null) {                            Object theBody = body;                            LogFormatUtils.traceDebug(logger, traceOn ->                                    "Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");                            addContentDispositionHeader(inputMessage, outputMessage);                            if (genericConverter != null) {                                genericConverter.write(body, targetType, selectedMediaType, outputMessage);                            }                            else {                                ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);                            }                        }                        else {                            if (logger.isDebugEnabled()) {                                logger.debug("Nothing to write: null body");                            }                        }                        return;                    }                }            }            if (body != null) {                Set producibleMediaTypes =                        (Set) inputMessage.getServletRequest()                                .getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);                if (isContentTypePreset || !CollectionUtils.isEmpty(producibleMediaTypes)) {                    throw new HttpMessageNotWritableException(                            "No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'");                }                throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);            }        }
我们一直追踪getProducibleMediaTypes后,最终发现会调用BeanSerializerFactory的constructBeanOrAddOnSerializer,就是这里进行修改操作的。
protected JsonSerializer<Object> constructBeanOrAddOnSerializer(SerializerProvider prov,            JavaType type, BeanDescription beanDesc, boolean staticTyping)        throws JsonMappingException    {        // 13-Oct-2010, tatu: quick sanity check: never try to create bean serializer for plain Object        // 05-Jul-2012, tatu: ... but we should be able to just return "unknown type" serializer, right?        if (beanDesc.getBeanClass() == Object.class) {            return prov.getUnknownTypeSerializer(Object.class);//            throw new IllegalArgumentException("Cannot create bean serializer for Object.class");        }        final SerializationConfig config = prov.getConfig();        BeanSerializerBuilder builder = constructBeanSerializerBuilder(beanDesc);        builder.setConfig(config);        // First: any detectable (auto-detect, annotations) properties to serialize?        List props = findBeanProperties(prov, beanDesc, builder);        if (props == null) {            props = new ArrayList();        } else {            props = removeOverlappingTypeIds(prov, beanDesc, builder, props);        }        // [databind#638]: Allow injection of "virtual" properties:        prov.getAnnotationIntrospector().findAndAddVirtualProperties(config, beanDesc.getClassInfo(), props);        // [JACKSON-440] Need to allow modification bean properties to serialize:        if (_factoryConfig.hasSerializerModifiers()) {            for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {                props = mod.changeProperties(config, beanDesc, props);            }        }.......//此处省略}
大家看一下props = mod.changeProperties(config, beanDesc, props);我们在配置类里面可是为我们的MappingJackson2HttpMessageConverter配置了 withSerializerModifier方法,并且设置了我们的MyBeanSerializerModifier并且继承BeanSerializerModifier重写了 changeProperties,所以会调用我们的changeProperties方法,进行修改null值的序列化类,我们也返回了一个list类型的BeanPropertyWriter,所以知道为什么那个BeanPropertyWriter在解析时,会是个数组类型的了吧,因为不同字段解析是不一样的。剩下的解释一下为什么单独配置并设置实例化@bean的MappingJackson2HttpMessageConverter也是好使的呢,大家可以看一下JacksonHttpMessageConvertersConfiguration类的源码,里面明确写了@ConditionalOnMissingBean注解,如果我们自己进行配置了,这个注入后就是一个备胎,以我们的为准,这个不多说  我们再来解析一下第二个问题:为什么继承WebMvcConfigurationSupport后,再去生成@Bean的MappingJackson2HttpMessageConverter,却不生效,这需要跟第三个问题一起解决:为什么不继承WebMvcConfigurationSupport时,生成@Bean的MappingJackson2HttpMessageConverter是生效的。  我们知道当我们继承WebMvcConfigurationSupport后,有一个配置会自动失效,就是自动注入的一个mvc配置,可以看看@SpringBootApplication注解里面有个@EnableAutoConfiguration注解,会引入一个AutoConfigurationImportSelector类。这个类就会扫描org.springframework.boot:spring-boot-autoconfigure下的spring.factories文件,这里面有一个我们默认的mvn配置也是继承了WebMvcConfigurationSupport,叫WebMvcAutoConfiguration,我们来看一下源码:
@Configuration(proxyBeanMethods = false)@ConditionalOnWebApplication(type = Type.SERVLET)@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })//注意此处有一个ConditionalOnMissingBean注解,所以如果我们自己继承后,就相当于已经存在WebMvcConfigurationSupport类,//就会走我们自己的配置类,此配置会失效@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,        ValidationAutoConfiguration.class })public class WebMvcAutoConfiguration {    .....    @Configuration(proxyBeanMethods = false)    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {        private final ResourceProperties resourceProperties;        private final WebMvcProperties mvcProperties;        private final ListableBeanFactory beanFactory;        private final WebMvcRegistrations mvcRegistrations;        private ResourceLoader resourceLoader;        public EnableWebMvcConfiguration(ResourceProperties resourceProperties,                ObjectProvider mvcPropertiesProvider,                ObjectProvider mvcRegistrationsProvider, ListableBeanFactory beanFactory) {            this.resourceProperties = resourceProperties;            this.mvcProperties = mvcPropertiesProvider.getIfAvailable();            this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();            this.beanFactory = beanFactory;        }        //如果我们不继承的话,处理请求的RequestMappingHandlerAdapter就会在这里生成        //会调用DelegatingWebMvcConfiguration里面的 requestMappingHandlerAdapter方法,        @Bean        @Override        public RequestMappingHandlerAdapter requestMappingHandlerAdapter(                @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,                @Qualifier("mvcConversionService") FormattingConversionService conversionService,                @Qualifier("mvcValidator") Validator validator) {            RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager,                    conversionService, validator);            adapter.setIgnoreDefaultModelOnRedirect(                    this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());            return adapter;        }.....}
不知道大家是否还记得getMessageConverters()方法里面添加默认messageConverters的时候之前,会调用一个configureMessageConverters(this.messageConverters);方法,我们的DelegatingWebMvcConfiguration 就已经重写了这个方法,所以我们如果不继承WebMvcConfigurationSupport,将会把我们的@bean形式存在的MappingJackson2HttpMessageConverter将会被扫描到
@Override    protected void configureMessageConverters(List> converters) {        this.configurers.configureMessageConverters(converters);    }//会添加我们的convert@Override    public void configureMessageConverters(List> converters) {        for (WebMvcConfigurer delegate : this.delegates) {            delegate.configureMessageConverters(converters);        }    }

现在我们配置的自定义jackson序列化已经生效了,但是,你仔细看我的流程图会发现,其实调用序列化的时候走的是RequestResponseBodyMethodProcessor的handleReturnValue方法

@Override    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {        mavContainer.setRequestHandled(true);        ServletServerHttpRequest inputMessage = createInputMessage(webRequest);        ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);        // Try even with null return value. ResponseBodyAdvice could get involved.        //这里进入序列化流程        writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);    }
最后在序列化的时候也是从这个类或则父类里面的一个属性:messageConverters
public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver {    private static final Set SUPPORTED_METHODS =            EnumSet.of(HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH);    private static final Object NO_VALUE = new Object();    protected final Log logger = LogFactory.getLog(getClass());    //这个属性取值的    protected final List>> messageConverters;    protected final List allSupportedMediaTypes;    private final RequestResponseBodyAdviceChain advice;...}
于是,小伙伴们就疑惑了,这我们自定义的在RequestMappingHandlerAdapter里面呢,跟这个类也没关系啊,属性是咋设置进来的呢?我们再看看RequestMappingHandlerAdapter的源码,你会发现,RequestMappingHandlerAdapter这个类实现了InitializingBean类,也就说明,创建RequestMappingHandlerAdapter的时候会调用afterPropertiesSet方法,至于为啥,看源码吧:(不是主要流程)
 //在createBean的时候会调用这个方法,看看是否实现了InitializingBean  protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)              throws Throwable {            boolean isInitializingBean = (bean instanceof InitializingBean);          if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {              if (logger.isTraceEnabled()) {                  logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");              }             if (System.getSecurityManager() != null) {                 try {                     AccessController.doPrivileged((PrivilegedExceptionAction) () -> {                         ((InitializingBean) bean).afterPropertiesSet();                         return null;                     }, getAccessControlContext());                 }                 catch (PrivilegedActionException pae) {                     throw pae.getException();                 }             }             else {                 //在这里进行调用的,                 ((InitializingBean) bean).afterPropertiesSet();             }         }          if (mbd != null && bean.getClass() != NullBean.class) {             String initMethodName = mbd.getInitMethodName();             if (StringUtils.hasLength(initMethodName) &&                     !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&                     !mbd.isExternallyManagedInitMethod(initMethodName)) {                 invokeCustomInitMethod(beanName, bean, mbd);             }         }     }
那我们看看RequestMappingHandlerAdapter的afterPropertiesSet方法都干了些啥吧。
@Override    public void afterPropertiesSet() {        // Do this first, it may add ResponseBody advice beans        initControllerAdviceCache();        if (this.argumentResolvers == null) {            List resolvers = getDefaultArgumentResolvers();            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);        }        if (this.initBinderArgumentResolvers == null) {            List resolvers = getDefaultInitBinderArgumentResolvers();            this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);        }        if (this.returnValueHandlers == null) {            //是在这里生成的类            List handlers = getDefaultReturnValueHandlers();            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);        }    }
private ListgetDefaultReturnValueHandlers() {        List handlers = new ArrayList<>();        // Single-purpose return value types        handlers.add(new ModelAndViewMethodReturnValueHandler());        handlers.add(new ModelMethodProcessor());        handlers.add(new ViewMethodReturnValueHandler());        handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),                this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));        handlers.add(new StreamingResponseBodyReturnValueHandler());        handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),                this.contentNegotiationManager, this.requestResponseBodyAdvice));        handlers.add(new HttpHeadersReturnValueHandler());        handlers.add(new CallableMethodReturnValueHandler());        handlers.add(new DeferredResultMethodReturnValueHandler());        handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));        // Annotation-based return value types        handlers.add(new ModelAttributeMethodProcessor(false));        //看到这个类了吗?生成的时候将RequestMappingHandlerAdapter里面的转换器设置进去了        handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),                this.contentNegotiationManager, this.requestResponseBodyAdvice));        // Multi-purpose return value types        handlers.add(new ViewNameMethodReturnValueHandler());        handlers.add(new MapMethodProcessor());        // Custom return value types        if (getCustomReturnValueHandlers() != null) {            handlers.addAll(getCustomReturnValueHandlers());        }        // Catch-all        if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {            handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));        }        else {            handlers.add(new ModelAttributeMethodProcessor(true));        }        return handlers;    }
讲到这里,不知道大家理解了多少,这些都是博主遇到需求后,自己问自己的问题,自己通过源码回答问题的,也希望大家能理解源码。还有一篇源码文章在路上:为什么我们的项目里出现两个配置类继承WebMvcConfigurationSupport时,只有一个会生效。我在网上找了半天都是说结果的,没有人分析源码到底是为啥,博主准备讲解一下,到希望可以帮 大家 !
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值