Spring Data Elasticsearch自定义ReadingConverter无法触发的问题求助
大家好,我最近遇到了一个头疼的问题:之前正常工作的自定义@ReadingConverter突然不触发了,现在调用仓库的findByTimestampBetween方法时,转换器里的convert代码完全没执行。想请教下各位有没有遇到类似情况,或者能帮我排查下问题所在?
问题背景
我用的是Spring Boot 3.1.2 + Spring Data Elasticsearch 5.1.2,自定义了一个ReadingConverter用来在从ES读取LogEntry文档时做一些额外处理。之前代码运行正常,不知道为什么现在转换器完全不生效了。
我的相关代码
配置类
@Configuration public class ElasticsearchConfig { @Bean public MappingElasticsearchConverter mappingElasticsearchConverter() { return new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext()); } @Bean public ElasticsearchCustomConversions elasticsearchCustomConversions( MappingElasticsearchConverter mappingElasticsearchConverter, ObjectMapper objectMapper) { return new ElasticsearchCustomConversions(List.of( new LogEntryReadingConverter(mappingElasticsearchConverter, objectMapper) )); } }
自定义ReadingConverter实现
@Component @ReadingConverter public class LogEntryReadingConverter implements Converter<Document, LogEntry> { private final MappingElasticsearchConverter elasticsearchConverter; private final ObjectMapper objectMapper; public LogEntryReadingConverter(MappingElasticsearchConverter elasticsearchConverter, ObjectMapper objectMapper) { this.elasticsearchConverter = elasticsearchConverter; this.objectMapper = objectMapper; } public LogEntry convert(Document source) { // 先调用ES默认转换(尊重@Field注解) LogEntry logEntry = elasticsearchConverter.read(LogEntry.class, source); // 这里是我的自定义逻辑 // ... return logEntry; } }
实体类
@Data @JsonIgnoreProperties(ignoreUnknown = true) @Document(indexName = "logstash") public class LogEntry implements ILogModel { @Id private String id; // 其他字段省略 }
仓库接口
@Repository public interface HaProxyLogRepository extends ElasticsearchRepository<LogEntry, String> { Page<LogEntry> findByTimestampBetween(LocalDateTime from, LocalDateTime to, Pageable pageable); }
预期与实际情况
我原本以为调用findByTimestampBetween方法时,会先触发转换器的convert方法,先完成默认转换再执行我的自定义逻辑,但现在转换器完全没被调用,直接返回了默认转换后的对象。
排查方向与可能解决方案
我自己梳理了几个可能的问题点,大家可以帮我参考下:
1. 循环依赖导致Bean注册异常
我的配置类里,elasticsearchCustomConversions依赖mappingElasticsearchConverter,而如果MappingElasticsearchConverter需要使用ElasticsearchCustomConversions的话,就会形成循环依赖。Spring可能无法正确处理这种循环,导致转换器没有被正确关联到转换上下文里。
解决方案:
调整配置避免循环依赖,同时让MappingElasticsearchConverter正确关联自定义Conversions:
@Configuration public class ElasticsearchConfig { @Bean public ElasticsearchCustomConversions elasticsearchCustomConversions(ObjectMapper objectMapper) { // 不再依赖MappingElasticsearchConverter,避免循环 return new ElasticsearchCustomConversions(List.of( new LogEntryReadingConverter(objectMapper) )); } @Bean public MappingElasticsearchConverter mappingElasticsearchConverter(ElasticsearchCustomConversions customConversions) { SimpleElasticsearchMappingContext context = new SimpleElasticsearchMappingContext(); context.setSimpleTypeHolder(customConversions.getSimpleTypeHolder()); MappingElasticsearchConverter converter = new MappingElasticsearchConverter(context); converter.setConversions(customConversions); return converter; } }
同时修改转换器,去掉对MappingElasticsearchConverter的依赖(避免递归调用):
// 去掉@Component,避免重复注册 @ReadingConverter public class LogEntryReadingConverter implements Converter<Document, LogEntry> { private final ObjectMapper objectMapper; public LogEntryReadingConverter(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } public LogEntry convert(Document source) { // 用ObjectMapper解析Document到LogEntry,保留默认字段映射 LogEntry logEntry = objectMapper.convertValue(source, LogEntry.class); // 执行自定义逻辑 // ... return logEntry; } }
2. 转换器重复注册导致冲突
转换器上同时加了@Component和在配置类里手动创建实例,这会导致Spring容器里存在两个转换器实例,可能引发注册异常或者优先级问题。
解决方案:
去掉转换器上的@Component注解,只通过配置类的ElasticsearchCustomConversions注册,确保只有一个实例被加载到转换上下文里。
3. 配置方式不符合Spring Data Elasticsearch 5.x规范
在Spring Data Elasticsearch 5.x中,官方推荐通过继承ElasticsearchConfigurationSupport来配置,而不是手动创建MappingElasticsearchConverter和ElasticsearchCustomConversions,这种方式能避免很多配置细节错误。
解决方案:
改用官方推荐的配置方式:
@Configuration public class ElasticsearchConfig extends ElasticsearchConfigurationSupport { @Override protected ElasticsearchCustomConversions elasticsearchCustomConversions() { return new ElasticsearchCustomConversions(List.of( new LogEntryReadingConverter(objectMapper()) )); } @Bean public ObjectMapper objectMapper() { return new ObjectMapper(); } }
这种方式会自动处理MappingElasticsearchConverter与CustomConversions的关联,不需要手动创建,减少出错概率。
备注:内容来源于stack exchange,提问作者solujic

