Spring Boot通过 spring-boot-starter-data-mongodb 自动配置连接MongoDB,spring.data.mongodb 对外暴露的配置项非常少,网上有很多文章说 Spring Boot没有提供连接池配置的功能,需要自行重写 MongoDbFactory,实际这样的确冤枉且小看了 spring-boot-starter-data-mongodb 的内部封装,连接MongoDb的组件当中内置了连接池的方法,只是我们用的姿势不对,并不需要什么重写搞得这么复杂。抱着尊重原创的想法,从其源码入手看看它是如何使用,官方文档也有一些配置,简单的说,MongoDb的连接方式,不是分开的一项一项的配置,学问都在它的uri里,也就是 spring.data.mongodb.uri, 在最后面放着一个option参数,隐秘而深奥,这里就是所有配置的奥妙所在。这个是官方文档,感兴趣的朋友可以看一下
我们从org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration 自动配置类看起,可以轻易的找到 org.springframework.boot.autoconfigure.mongo.MongoClientFactorySupport<T>, 从这里,又可以找到,com.mongodb.MongoClientSettings, 顺着这里又可以找到,com.mongodb.connection.ConnectionPoolSettings, 那么和连接池相关的设置就在这里了,进入到这个类,很明显就会看到一堆属性
@Immutable
public class ConnectionPoolSettings {
private final List<ConnectionPoolListener> connectionPoolListeners;
private final int maxSize;
private final int minSize;
private final int maxWaitQueueSize;
private final long maxWaitTimeMS;
private final long maxConnectionLifeTimeMS;
private final long maxConnectionIdleTimeMS;
private final long maintenanceInitialDelayMS;
private final long maintenanceFrequencyMS;
所以我们主要考虑这些地方如何才能产生对应的值即可,从com.mongodb.MongoClientSettings.Builder.applyConnectionString(ConnectionString) 这个方法中我们就可以看到 connectionPoolSettingsBuilder.applyConnectionString(connectionString);
public Builder applyConnectionString(final ConnectionString connectionString) {
if (connectionString.getApplicationName() != null) {
applicationName = connectionString.getApplicationName();
}
clusterSettingsBuilder.applyConnectionString(connectionString);
if (!connectionString.getCompressorList().isEmpty()) {
compressorList = connectionString.getCompressorList();
}
/// !!!这里是设置连接池的重点
connectionPoolSettingsBuilder.applyConnectionString(connectionString);
if (connectionString.getCredential() != null) {
credential = connectionString.getCredential();
}
if (connectionString.getReadConcern() != null) {
readConcern = connectionString.getReadConcern();
}
if (connectionString.getReadPreference() != null) {
readPreference = connectionString.getReadPreference();
}
if (connectionString.getRetryWritesValue() != null) {
retryWrites = connectionString.getRetryWritesValue();
}
if (connectionString.getUuidRepresentation() != null) {
uuidRepresentation = connectionString.getUuidRepresentation();
}
serverSettingsBuilder.applyConnectionString(connectionString);
socketSettingsBuilder.applyConnectionString(connectionString);
sslSettingsBuilder.applyConnectionString(connectionString);
if (connectionString.getWriteConcern() != null) {
writeConcern = connectionString.getWriteConcern();
}
return this;
}
也就是这句话,实现了连接池的设置,那么他是如何设置的呢,只要进去看一看便知,首先他入参的是connectionString, 通过方法如果往调用方的方向反过来一找,便可知道,他就是 spring.data.mongodb.uri 对应的值,那么重点就是我们再重点进去看看里面的方法,其中 com.mongodb.ConnectionString 这个类就是解析连接字符串的重点。在它的带参构造方法中
com.mongodb.ConnectionString.ConnectionString(String)
除了解析字符串以外,Map<String, List<String>> connectionStringOptionsMap = parseOptions(connectionStringQueryParamenters);
// !!!这句是重点
Map<String, List<String>> connectionStringOptionsMap = parseOptions(connectionStringQueryParamenters);
Map<String, List<String>> txtRecordsOptionsMap = parseOptions(txtRecordsQueryParameters);
这个方法中用于对 uri中的option进行解析,uri的结构在最尾部会有一个options选项,也就是对参数选项进行解析。通过一系列的解析实现参数设置,真佩服写代码的人不辞辛苦的这种解析精神,换来的是幸福的各种配置,包括连接池,
static {
GENERAL_OPTIONS_KEYS.add("minpoolsize");
GENERAL_OPTIONS_KEYS.add("maxpoolsize");
GENERAL_OPTIONS_KEYS.add("waitqueuetimeoutms");
GENERAL_OPTIONS_KEYS.add("connecttimeoutms");
GENERAL_OPTIONS_KEYS.add("maxidletimems");
GENERAL_OPTIONS_KEYS.add("maxlifetimems");
GENERAL_OPTIONS_KEYS.add("sockettimeoutms");
这里的配置项就是对应的 option里的值,总结来说就是这样的一个对应关系
minConnectionPoolSize; 最小连接池大小 —- minPoolSize
maxConnectionPoolSize; 最大连接池大小 —- maxPoolSize
maxWaitTime; 最大等待时间 —- waitQueueTimeoutMS
maxConnectionIdleTime; 最大空闲时间 —- maxIdleTimeMS
maxConnectionLifeTime; 连接池最大生命周期 —- maxLifeTimeMS
connectTimeout; 连接超时 —- connectTimeoutMS
socketTimeout; 读取超时 —- socketTimeoutMS
如果我们想配置mongoDB的选项,只需要在uri中增加配置内容,否则就会按默认的走
例如我们可以这样配置,实现我们的连接池设置
spring.data.mongodb.uri=mongodb://username:password@192.168.1.1:27017,192.168.1.2:27017,192.168.1.3:27017/?readPreference=secondaryPreferred&maxIdleTimeMS=60000&waitQueueTimeoutMS=2000&minPoolSize=0&maxPoolSize=100&maxLifeTimeMS=0&connectTimeoutMS=2000&socketTimeoutMS=2000
所以以上就是为Spring Boot当中使用mongoDB的组件正名,它并不是没有,也不需要自己实现,应了那句话,生活中不缺少美,缺少的是发现