Spring Boot双MongoDB实例ZonedDateTime转换器配置失败
Spring Boot 2.7.6双MongoDB实例下ZonedDateTime序列化异常解决
问题场景
- Spring Boot 2.7.6配置主从两个MongoDB实例,集合包含
ZonedDateTime类型字段 - 单库连接时,自定义
MongoCustomConversions转换器可正常处理该类型 - 双库配置后,保存数据抛出异常:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.time.ZonedDateTime.
- 尝试共用转换器配置,问题依旧
- 项目Maven指定Java 1.8,运行在OpenJDK19的Docker容器中
当前配置代码
主库配置
@Bean @Primary @Override public MongoCustomConversions customConversions() { List<Converter<?, ?>> converters = new ArrayList<>(); converters.add(new MultipleMongoConfig.DateToZonedDateTimeConverter()); converters.add(new MultipleMongoConfig.ZonedDateTimeToDateConverter()); return new MongoCustomConversions(converters); } @Bean @Primary public MongoDatabaseFactory primaryFactory() throws Exception { return new SimpleMongoClientDatabaseFactory(((connection))); } @Primary @Bean(name = "primaryMongoTemplate") public MongoTemplate primaryMongoTemplate() throws Exception { return new MongoTemplate(primaryFactory()); }
从库配置
@Bean(name = "secondaryMongoTemplate") public MongoTemplate secondaryMongoTemplate() throws Exception { return new MongoTemplate(secondaryFactory()); } @Bean @Override public MongoCustomConversions customConversions() { List<Converter<?, ?>> converters = new ArrayList<>(); converters.add(new MultipleMongoConfig.DateToZonedDateTimeConverter()); converters.add(new MultipleMongoConfig.ZonedDateTimeToDateConverter()); return new MongoCustomConversions(converters); } @Bean public MongoDatabaseFactory secondaryFactory() throws Exception { return new SimpleMongoClientDatabaseFactory(((connection))); }
YAML配置
main: allow-bean-definition-overriding: true
问题原因
- 双库配置时,直接通过
MongoTemplate(MongoDatabaseFactory)构造实例,未将自定义的MongoCustomConversions绑定到对应的MappingMongoConverter中,导致MongoTemplate使用默认转换器,无法处理ZonedDateTime类型。 - 编译JDK版本(1.8)与运行JDK版本(19)不一致,可能引发Java时间类兼容性问题,加重序列化异常。
解决方案
1. 手动绑定自定义转换器到每个MongoTemplate
修改主库和从库的配置,通过MappingMongoConverter将自定义转换器关联到对应的MongoTemplate:
主库配置修改
@Bean @Primary public MongoCustomConversions primaryCustomConversions() { List<Converter<?, ?>> converters = new ArrayList<>(); converters.add(new MultipleMongoConfig.DateToZonedDateTimeConverter()); converters.add(new MultipleMongoConfig.ZonedDateTimeToDateConverter()); return new MongoCustomConversions(converters); } @Bean @Primary public MappingMongoConverter primaryMappingMongoConverter(MongoDatabaseFactory primaryFactory, MongoCustomConversions primaryCustomConversions) throws Exception { MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(primaryFactory), new MongoMappingContext()); converter.setCustomConversions(primaryCustomConversions); converter.afterPropertiesSet(); return converter; } @Primary @Bean(name = "primaryMongoTemplate") public MongoTemplate primaryMongoTemplate(MongoDatabaseFactory primaryFactory, MappingMongoConverter primaryMappingMongoConverter) throws Exception { return new MongoTemplate(primaryFactory, primaryMappingMongoConverter); } @Bean @Primary public MongoDatabaseFactory primaryFactory() throws Exception { return new SimpleMongoClientDatabaseFactory(((connection))); }
从库配置修改
@Bean(name = "secondaryCustomConversions") public MongoCustomConversions secondaryCustomConversions() { List<Converter<?, ?>> converters = new ArrayList<>(); converters.add(new MultipleMongoConfig.DateToZonedDateTimeConverter()); converters.add(new MultipleMongoConfig.ZonedDateTimeToDateConverter()); return new MongoCustomConversions(converters); } @Bean(name = "secondaryMappingMongoConverter") public MappingMongoConverter secondaryMappingMongoConverter(MongoDatabaseFactory secondaryFactory, @Qualifier("secondaryCustomConversions") MongoCustomConversions secondaryCustomConversions) throws Exception { MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(secondaryFactory), new MongoMappingContext()); converter.setCustomConversions(secondaryCustomConversions); converter.afterPropertiesSet(); return converter; } @Bean(name = "secondaryMongoTemplate") public MongoTemplate secondaryMongoTemplate(MongoDatabaseFactory secondaryFactory, @Qualifier("secondaryMappingMongoConverter") MappingMongoConverter secondaryMappingMongoConverter) throws Exception { return new MongoTemplate(secondaryFactory, secondaryMappingMongoConverter); } @Bean public MongoDatabaseFactory secondaryFactory() throws Exception { return new SimpleMongoClientDatabaseFactory(((connection))); }
2. 统一Java版本(推荐)
将编译和运行的Java版本统一,避免兼容性问题:
- 若保留JDK8运行环境,修改Docker容器使用OpenJDK8镜像
- 若升级到JDK19,修改
pom.xml的编译版本:
<properties> <maven.compiler.source>19</maven.compiler.source> <maven.compiler.target>19</maven.compiler.target> </properties>
3. 移除Bean覆盖配置
由于已经通过指定Bean名称(如primaryCustomConversions、secondaryCustomConversions)避免冲突,可以删除YAML中的main.allow-bean-definition-overriding: true,防止意外覆盖Bean定义。
验证
启动项目后,尝试保存包含ZonedDateTime字段的文档,检查是否正常完成序列化与反序列化,无CodecConfigurationException异常抛出。
内容的提问来源于stack exchange,提问作者Armen Arzumanyan
相关产品推荐
相关产品推荐

