为什么 Spring Data MongoDB 不为更新…(…) 方法公开事件?
Why does Spring Data MongoDB not expose events for update…(…) methods?
mongoOperations 的更新似乎没有触发 AbstractMongoEventListener 中的事件。
目前有什么方法可以监听如下更新事件吗?如果是这样的话,这似乎是一个很大的疏漏。
MongoTemplate.updateMulti()
谢谢!
这不是疏忽。事件是围绕域对象或至少文档的生命周期设计的,这意味着它们通常包含您感兴趣的域对象的实例。
另一方面,更新完全在数据库中处理。因此 MongoTemplate
中没有处理任何文档甚至领域对象。考虑这基本上与 JPA @EntityListener
s 仅针对首先加载到持久性上下文中的实体触发的方式相同,但在执行查询时不会触发,因为查询的执行是在数据库中发生的。
我知道现在回答这个问题为时已晚,我在 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()
mongoOperations 的更新似乎没有触发 AbstractMongoEventListener 中的事件。
目前有什么方法可以监听如下更新事件吗?如果是这样的话,这似乎是一个很大的疏漏。
MongoTemplate.updateMulti()
谢谢!
这不是疏忽。事件是围绕域对象或至少文档的生命周期设计的,这意味着它们通常包含您感兴趣的域对象的实例。
另一方面,更新完全在数据库中处理。因此 MongoTemplate
中没有处理任何文档甚至领域对象。考虑这基本上与 JPA @EntityListener
s 仅针对首先加载到持久性上下文中的实体触发的方式相同,但在执行查询时不会触发,因为查询的执行是在数据库中发生的。
我知道现在回答这个问题为时已晚,我在 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()