最近項目要求對mongodb的數據變更操作記錄操作日誌,首先想到的是基於spring的AOP對變更的接口進行攔截處理,由於調用接口的點很多不是很方便的去梳理,考慮使用mongodb的CDC機制,實時監控數據的變更。
首先是springboot集成mongodb,mongdb需要是3.6以上的版本才能支持changestream
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
</dependencies>
首先配置mongo監聽器,用於接收數據庫的變更信息
import com.mongodb.client.model.changestream.ChangeStreamDocument; import lombok.extern.slf4j.Slf4j; import org.bson.Document; import org.springframework.data.mongodb.core.messaging.Message; import org.springframework.data.mongodb.core.messaging.MessageListener; import org.springframework.stereotype.Component; @Component @Slf4j public class DocumnetMessageListener implements MessageListener<ChangeStreamDocument<Document>, Document> { @Override public void onMessage(Message<ChangeStreamDocument<Document>, Document> message) { log.info("Received Message in collection: {},message raw: {}, message body:{}", message.getProperties().getCollectionName(), message.getRaw(), message.getBody()); } }
配置 mongo監聽器的容器MessageListenerContainer,spring啓動時會自動啓動監聽的任務用於接收changestream
import com.mongodb.client.model.changestream.FullDocument; import org.bson.Document; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.messaging.ChangeStreamRequest; import org.springframework.data.mongodb.core.messaging.DefaultMessageListenerContainer; import org.springframework.data.mongodb.core.messaging.MessageListenerContainer; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import static org.springframework.data.mongodb.core.aggregation.Aggregation.match; import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation; import static org.springframework.data.mongodb.core.query.Criteria.where; @Configuration public class MongoConfig { @Bean MessageListenerContainer messageListenerContainer(MongoTemplate template, DocumnetMessageListener documnetMessageListener) { Executor executor = Executors.newSingleThreadExecutor(); MessageListenerContainer messageListenerContainer = new DefaultMessageListenerContainer(template, executor) { @Override public boolean isAutoStartup() { return true; } }; ChangeStreamRequest<Document> request = ChangeStreamRequest.builder(documnetMessageListener) .collection("topic") //需要監聽的集合名,不指定默認監聽數據庫的 .filter(newAggregation(match(where("operationType").in("insert", "update", "replace")))) //過濾需要監聽的操作類型,可以根據需求指定過濾條件 .fullDocumentLookup(FullDocument.UPDATE_LOOKUP) //不設置時,文檔更新時,只會發送變更字段的信息,設置UPDATE_LOOKUP會返回文檔的全部信息 .build(); messageListenerContainer.register(request, Document.class); return messageListenerContainer; } }
返回的數據格式類似這樣子
{
"_id": {
"_data": {
"$binary": "glzquiIAAAACRmRfaWQAZFzquiK0lDNo+K0DpwBaEARUMrm0ruVACoftuxjt1RtCBA==",
"$type": "00"
}
},
"operationType": "insert",
"fullDocument": {
"_id": {
"$oid": "5ceaba22b4943368f8ad03a7"
},
"y": 1
},
"ns": {
"db": "test",
"coll": "bar"
},
"documentKey": {
"_id": {
"$oid": "5ceaba22b4943368f8ad03a7"
}
}
}