为什么 Spring Data MongoDB 不为更新…(…) 方法公开事件?

Why does Spring Data MongoDB not expose events for update…(…) methods?

mongoOperations 的更新似乎没有触发 AbstractMongoEventListener 中的事件。

这 post 表明至少在 2014 年 11 月是这样

目前有什么方法可以监听如下更新事件吗?如果是这样的话,这似乎是一个很大的疏漏。

MongoTemplate.updateMulti()

谢谢!

这不是疏忽。事件是围绕域对象或至少文档的生命周期设计的,这意味着它们通常包含您感兴趣的域对象的实例。

另一方面,更新完全在数据库中处理。因此 MongoTemplate 中没有处理任何文档甚至领域对象。考虑这基本上与 JPA @EntityListeners 仅针对首先加载到持久性上下文中的实体触发的方式相同,但在执行查询时不会触发,因为查询的执行是在数据库中发生的。

我知道现在回答这个问题为时已晚,我在 MongoTemplate.findAndModify 方法中遇到了同样的情况,我需要事件的原因是为了审计目的。这是我所做的。

1.EventPublisher(这是 ofc MongoTemplate 的方法)

public class CustomMongoTemplate extends MongoTemplate {

    private ApplicationEventPublisher applicationEventPublisher;


    @Autowired
    public void setApplicationEventPublisher(ApplicationEventPublisher
                                                         applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

   //Default Constructor here

    @Override
    public <T> T findAndModify(Query query, Update update, Class<T> entityClass) {
        T result = super.findAndModify(query, update, entityClass);

        //Publishing Custom Event on findAndModify
        if(result!=null && result instanceof Parent)//All of my Domain class extends Parent
            this.applicationEventPublisher.publishEvent(new AfterFindAndModify
                    (this,((Parent)result).getId(),
                            result.getClass().toString())
            );

        return result;
    } }

2.Application 事件

public class AfterFindAndModify extends ApplicationEvent {

    private DocumentAuditLog documentAuditLog;

    public AfterFindAndModify(Object source, String documentId,
                            String documentObject) {
        super(source);
        this.documentAuditLog = new DocumentAuditLog(documentId,
                documentObject,new Date(),"UPDATE");
    }

    public DocumentAuditLog getDocumentAuditLog() {
        return documentAuditLog;
    }
}

3.Application 听众

public class FindandUpdateMongoEventListner implements ApplicationListener<AfterFindAndModify> {

    @Autowired
    MongoOperations mongoOperations;

    @Override
    public void onApplicationEvent(AfterFindAndModify event) {
        mongoOperations.save(event.getDocumentAuditLog());
    }
}

然后

@Configuration
@EnableMongoRepositories(basePackages = "my.pkg")
@ComponentScan(basePackages = {"my.pkg"})
public class MongoConfig extends AbstractMongoConfiguration {

    //.....

    @Bean
    public FindandUpdateMongoEventListner findandUpdateMongoEventListner(){
        return new FindandUpdateMongoEventListner();
    }   

}

您可以监听数据库更改,甚至是完全在您的程序之外的更改(MongoDB 4.2 和更新版本)。

(代码使用 kotlin 语言。java 相同)

@Autowired private lateinit var op: MongoTemplate

@PostConstruct
fun listenOnExternalChanges() {
    Thread {
        op.getCollection("Item").watch().onEach {
            if(it.updateDescription.updatedFields.containsKey("name")) {
                println("name changed on a document: ${it.updateDescription.updatedFields["name"]}")
            }
        }
    }.start()
}

此代码仅在启用复制时有效。即使只有一个节点也可以启用它:

将以下副本集详细信息添加到 mongodb.conf(/etc/mongodb.conf 或 /usr/local/etc/mongod.conf 或 C:\Program Files\MongoDB\Server.0\bin\mongod。 cfg) 文件

replication:
  replSetName: "local"

重新启动 mongo 服务,然后打开 mongo 控制台和 运行 这个命令:

rs.initiate()