Spring Boot多MongoDB连接持久化与超时关闭方案咨询
问题场景与需求
我有一个基于Spring Boot的应用,用的是Spring Data的MongoDB驱动。现在想在运行时创建多个MongoDB连接,查询之后把连接保留X分钟,要是这段时间没活动就自动关闭。
现有实现代码:
private MongoCredential buildCredential(SourceResource source) { MongoCredentials sourceCredentials = objectMapper.convertValue(source.getCredentials(), MongoCredentials.class); return MongoCredential.createCredential(sourceCredentials.getUsername(), sourceCredentials.getAuthDatabase(), sourceCredentials.getPassword().toCharArray()); } private MongoClient buildClient(SourceResource source) { MongoCredentials sourceCredentials = objectMapper.convertValue(source.getCredentials(), MongoCredentials.class); return MongoClients.create( MongoClientSettings.builder() .applyToClusterSettings(builder -> builder.hosts(Collections.singletonList(new ServerAddress(sourceCredentials.getHost(), sourceCredentials.getPort()))) ) .credential(buildCredential(source)) .build() ); } private MongoDatabaseFactory buildFactory(SourceResource source) { MongoCredentials sourceCredentials = objectMapper.convertValue(source.getCredentials(), MongoCredentials.class); return new SimpleMongoClientDatabaseFactory(buildClient(source), sourceCredentials.getDatabase()); } public MongoTemplate connect(SourceResource source) { return new MongoTemplate(buildFactory(source)); }
我有三个疑问:
- 把这些连接持久化给应用其他模块用,最佳方案是什么?
- 能不能把这些对象序列化后存到Redis缓存里?
- 怎么实现X分钟后自动清除/关闭这些连接?
解决方案
一、连接持久化的最佳方案
别直接序列化MongoTemplate或者MongoClient存Redis,这类带网络连接的对象根本没法正常序列化(就算硬序列化,反序列化出来的连接也用不了),而且手动管连接生命周期容易出问题。推荐用本地缓存+连接池复用的方式:
- 用本地缓存(比如Guava Cache、Caffeine)存
MongoTemplate实例,拿SourceResource的唯一标识(比如host+port+database组合)当key。 - 每次需要连接时先从缓存里取,没有就调用你的
connect()方法创建新实例存进去。 - 这种方式在应用进程内复用连接,不用跨进程序列化,性能也更好。
二、Redis存储连接对象的可行性
不行,绝对不能直接把MongoTemplate或MongoClient序列化存Redis:
- 这些对象底层包含Socket连接、线程池这类资源,序列化后没法完整还原出可用的连接。
- 就算强行序列化存进去,取出来反序列化后的对象也是无效状态,不仅没法执行MongoDB操作,还可能导致资源泄漏。
三、自动关闭闲置连接的实现
结合本地缓存的过期机制和MongoClient本身的配置来搞:
- 缓存层面设置过期时间:在本地缓存(比如Caffeine)里配置X分钟的访问后过期,只要
MongoTemplate实例X分钟没被用,缓存就自动删掉它。 - 加缓存移除监听器:给缓存加个移除监听器,实例被移除时手动关闭对应的
MongoClient:// Caffeine缓存配置示例 Cache<String, MongoTemplate> mongoTemplateCache = Caffeine.newBuilder() .expireAfterAccess(X, TimeUnit.MINUTES) .removalListener((key, value, cause) -> { if (value != null) { // 获取并关闭MongoClient MongoDatabaseFactory factory = value.getMongoDatabaseFactory(); if (factory instanceof SimpleMongoClientDatabaseFactory) { MongoClient client = ((SimpleMongoClientDatabaseFactory) factory).getMongoClient(); client.close(); } } }) .build(); - MongoClient连接池配置:构建
MongoClientSettings时,配置连接池的闲置超时,就算缓存没及时清理,MongoDB驱动也会自动回收闲置连接:MongoClientSettings.builder() // 其他原有配置... .applyToConnectionPoolSettings(poolBuilder -> { poolBuilder.maxIdleTime(X, TimeUnit.MINUTES); // 连接池内的连接闲置X分钟后自动关闭 }) .build();
内容的提问来源于stack exchange,提问作者ethan
相关产品推荐
相关产品推荐

