Spring Boot 2.2.x升级后Mongo审计字段createdAt为空问题排查
问题根源
Spring Boot 2.2.x 对应的 Spring Data MongoDB 2.2 版本,将MongoAuditingEventListener的优先级调整为最高优先级(Ordered.HIGHEST_PRECEDENCE),导致它的onBeforeConvert事件处理会先于你自定义的GenerateUUIDListener执行。
在旧版本(2.1.x)中,事件顺序相反:自定义监听器先设置ID,再触发审计逻辑——这其实存在逻辑矛盾(设置ID后isNew()返回false,理论上审计不应填充@CreatedDate),但旧版本的审计逻辑对Persistable实体的处理更宽松,仍会基于首次插入的状态填充字段。而2.2.x版本严格遵循Persistable.isNew()的语义,同时事件顺序反转直接导致了审计字段为空的问题。
修复方案
推荐第一种方案,逻辑更清晰且符合MongoDB事件模型的设计:
方案1:将ID生成逻辑移至onBeforeSave事件
MongoDB的事件执行顺序为:onBeforeConvert → onBeforeSave → 持久化。把ID生成从onBeforeConvert移到onBeforeSave,可以确保审计逻辑先完成createdAt的填充,再设置ID:
public class GenerateUUIDListener extends AbstractMongoEventListener<IdentifiableEntity> { @Override public void onBeforeSave(BeforeSaveEvent<IdentifiableEntity> event) { IdentifiableEntity entity = event.getSource(); if (entity.isNew()) { entity.setId(UUID.randomUUID()); } } }
执行流程变为:
onBeforeConvert:审计监听器触发,此时ID为null,isNew()返回true,成功填充createdAtonBeforeSave:自定义监听器触发,生成并设置UUID作为ID- 实体持久化,同时包含
id和createdAt字段
方案2:调整自定义监听器优先级(备选)
如果你希望保留onBeforeConvert事件,可以调整监听器优先级,让它在审计监听器之后执行,同时修改isNew()逻辑确保审计能识别新实体:
- 给自定义监听器设置优先级(比审计监听器低一级):
@Configuration @EnableMongoAuditing public class MongoConfiguration { @Bean @Order(Ordered.HIGHEST_PRECEDENCE + 1) public GenerateUUIDListener generateUUIDListener() { return new GenerateUUIDListener(); } }
- 修改
isNew()逻辑,并给createdAt添加getter:
public abstract class InsertableEntity extends IdentifiableEntity { @CreatedDate @JsonIgnore private Instant createdAt; public Instant getCreatedAt() { return createdAt; } } public abstract class IdentifiableEntity implements Persistable<UUID> { @Id private UUID id; @JsonIgnore public boolean isNew() { // ID为空 或 createdAt为空,均判定为新实体 return getId() == null || (this instanceof InsertableEntity && ((InsertableEntity) this).getCreatedAt() == null); } }
验证
修改后重新运行测试,createdAt字段会被正确自动填充,UUID ID也能正常生成。
内容的提问来源于stack exchange,提问作者Matthias Baumgart
相关产品推荐
相关产品推荐

