You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot升级后ResolvableType序列化循环引用异常求助

Spring Boot 3.2.1升级后Spring Integration+Kafka序列化循环引用异常

背景

项目基于Spring Integration和Spring Kafka,将Spring Boot从3.1.7升级到3.2.1后,消息发送时出现Jackson序列化循环引用异常。

核心代码

@Bean
IntegrationFlow sendToKafkaFlow() {
    return IntegrationFlow.from("sendToKafkaFlow.input")
            .transform(Transformers.toJson()) // 1. 生成json__resolvableType头
           // 其他处理器/头增强器 
//        .headerFilter(JsonHeaders.RESOLVABLE_TYPE) // 2. 注释掉的头过滤代码
            .handle(Kafka.outboundChannelAdapter(kafkaTemplate) //3. Kafka出站适配器
                   .topic("someTopic")
            )
            .get();
}

异常详情

每次走这个流程发消息都会抛错:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: org.springframework.core.ResolvableType["componentType"]-org.springframework.core.ResolvableType["componentType"])

完整堆栈:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: org.springframework.core.ResolvableType["componentType"]->org.springframework.core.ResolvableType["componentType"])
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
    at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1308)
(3) at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._handleSelfReference(BeanPropertyWriter.java:948)
(2) at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:726)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
(1) at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:732)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318)
    at com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsBytes(ObjectMapper.java:3987)

问题根因

步骤1的Transformers.toJson()会自动添加json__resolvableType头,步骤3的Kafka出站适配器用DefaultKafkaHeaderMapper映射这个头时,触发循环引用:当ResolvableType的componentType为null时,会被替换成EmptyInstance,而这个EmptyInstance的componentType又指向自身,Jackson序列化时就会报错。

已试过的无效操作

  • 手动加步骤2的头过滤可以解决,但项目里有大量类似流程,改起来成本太高;
  • 在application.yml里配置Jackson关闭自引用失败开关,完全没效果:
spring:   
  jackson:
    serialization:
      fail-on-self-references: false

可行解决方案

1. 全局配置Jackson处理ResolvableType序列化

给Jackson加个自定义序列化器,专门处理ResolvableType,避免循环引用:

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new SimpleModule()
                .addSerializer(ResolvableType.class, new JsonSerializer<ResolvableType>() {
                    @Override
                    public void serialize(ResolvableType value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                        if (value == null || ResolvableType.NONE.equals(value)) {
                            gen.writeNull();
                            return;
                        }
                        // 只序列化类型名称,跳过会引发循环的字段
                        gen.writeString(value.getType().getTypeName());
                    }
                }));
        return mapper;
    }
}

2. 全局配置KafkaHeaderMapper过滤该头

不用修改每个IntegrationFlow,直接全局配置DefaultKafkaHeaderMapper,自动忽略json__resolvableType:

@Bean
public KafkaHeaderMapper kafkaHeaderMapper() {
    DefaultKafkaHeaderMapper mapper = new DefaultKafkaHeaderMapper();
    // 感叹号表示排除该头
    mapper.setOutboundHeaderPatterns(Collections.singletonList("!" + JsonHeaders.RESOLVABLE_TYPE));
    return mapper;
}

3. 关闭Transformers.toJson()生成ResolvableType头

在使用Transformers.toJson()时,直接配置不生成这个头:

.transform(Transformers.toJson()
        .resolvableType(false))

如果多处用到,可以封装成一个统一的Transformer bean,避免重复配置。

4. 升级依赖版本

检查Spring Integration或Spring Kafka的后续版本,看是否官方已经修复了ResolvableType的循环引用问题,升级到最新稳定版可能直接解决。

内容的提问来源于stack exchange,提问作者Jonathan H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 02:54:52