看解决方法直接跳到下面看解决办法。
背景
最近在搞spring boot和mongodb整合,基础的配置都通过引用如下这个包,然后在yml中配置即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
spring:
data:
mongodb:
authentication-database: admin
host: 192.168.0.124
port: 27017
database: test
username: admin
password: 'admin123' #如果是纯数字,需要加个单引号
但是如果我想配置一些高级配置,比如过期时间,连接数等等这样的方法就不见效了。
我看到很多的帖子说是在 上述yaml的spring.data.mongodb.uri
里面写上地址,然后加?来表示参数,但是实测不生效。
然后我看到另一种,就是增加一个spring-boot-starter-mongodb-plus
的依赖,可以参看:
Spring Boot中增强对MongoDB的配置(连接池等) 我也不知道原创在哪,随便引了一个。
但是这个方法还是不可以,是因为版本的问题,后续会解释,不过我看了一个这个依赖的源码,很简单,就是一个获取yaml配置和对mongodb连接的配置类。所以我觉得为啥不能自己写一个呢。
解决办法
仅需两步:
第一步:将下面两个类添加到项目中
1.MongoOptionProperties
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "spring.data.mongodb.option")
public class MongoOptionProperties {
private Integer minConnectionPerHost = 0;
private Integer maxConnectionPerHost = 100;
private Integer threadsAllowedToBlockForConnectionMultiplier = 5;
private Integer serverSelectionTimeout = 30000;
private Integer maxWaitTime = 120000;
private Integer maxConnectionIdleTime = 0;
private Integer maxConnectionLifeTime = 0;
private Integer connectTimeout = 10000;
private Integer socketTimeout = 0;
private Boolean socketKeepAlive = false;
private Boolean sslEnabled = false;
private Boolean sslInvalidHostNameAllowed = false;
private Boolean alwaysUseMBeans = false;
private Integer heartbeatFrequency = 10000;
private Integer minHeartbeatFrequency = 500;
private Integer heartbeatConnectTimeout = 20000;
private Integer heartbeatSocketTimeout = 20000;
private Integer localThreshold = 15;
/**TODO加上get set方法*/
}
2.MongoPlusAutoConfiguration
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.mongo.MongoClientFactory;
import org.springframework.boot.autoconfigure.mongo.MongoClientSettingsBuilderCustomizer;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({MongoClient.class})
@EnableConfigurationProperties({MongoOptionProperties.class})
@ConditionalOnMissingBean(
type = {"org.springframework.data.mongodb.MongoDatabaseFactory"}
)
/**
* mongodb 连接高级配置
* */
public class MongoPlusAutoConfiguration {
public MongoPlusAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean({MongoClient.class})
public MongoClient mongo(MongoProperties properties, Environment environment, ObjectProvider<MongoClientSettingsBuilderCustomizer> builderCustomizers, MongoOptionProperties mongoOptionProperties) {
MongoClientSettings.Builder mySetting = MongoClientSettings.builder();
mySetting.applyToConnectionPoolSettings(builder -> {
builder.maxSize(mongoOptionProperties.getMaxConnectionPerHost());
builder.minSize(mongoOptionProperties.getMinConnectionPerHost());
builder.maxWaitTime(mongoOptionProperties.getMaxWaitTime(),TimeUnit.MILLISECONDS);
builder.maxConnectionIdleTime(mongoOptionProperties.getMaxConnectionIdleTime(),TimeUnit.MILLISECONDS);
builder.maxConnectionLifeTime(mongoOptionProperties.getMaxConnectionLifeTime(),TimeUnit.MILLISECONDS);
});
mySetting.applyToClusterSettings(builder -> {
builder.serverSelectionTimeout(mongoOptionProperties.getServerSelectionTimeout(), TimeUnit.MILLISECONDS);
builder.localThreshold(mongoOptionProperties.getLocalThreshold(),TimeUnit.MILLISECONDS);
});
mySetting.applyToServerSettings(builder -> {
builder.heartbeatFrequency(mongoOptionProperties.getHeartbeatFrequency(),TimeUnit.MILLISECONDS);
builder.minHeartbeatFrequency(mongoOptionProperties.getHeartbeatFrequency(),TimeUnit.MILLISECONDS);
});
mySetting.applyToSocketSettings(builder -> {
builder.connectTimeout(mongoOptionProperties.getConnectTimeout(),TimeUnit.MILLISECONDS);
});
return (MongoClient)(new MongoClientFactory(properties, environment, (List)builderCustomizers.orderedStream().collect(Collectors.toList()))).createMongoClient(mySetting.build());
}
}
springboot 的版本 2.3.2.RELEASE
第二步:在yaml中配置例子:
spring:
data:
mongodb:
authentication-database: admin
host: 192.168.0.124
port: 27017
database: test
username: admin
password: 'admin123'
option: #主要是这里
server-selection-timeout: 99
可以看到这个值变化了。
注意MongoOptionProperties 的有些参数没有相关对应的,还需要改造的可以参看原理分析。
原理和分析
之前使用的spring-boot-starter-mongodb-plus
不成功,是因为springboot版本的问题,这个都是旧方法,适用于1.x版本的。2.x好像有了一些变化。
想具体改造的话可以debug查看配置mongodb的过程,在:
spring-boot-autoconfigure-2.3.2.RELEASE.jar
\org\springframework\boot\autoconfigure\mongo\MongoAutoConfiguration
这个类就是启动mongodb的类。但是在代码调试中发现,它的传参ObjectProvider< MongoClientSettings> settings 是null,只能加载默认配置。所以在MongoPlusAutoConfiguration 改造中,增加了mysetting的配置对象,把配置文件中的配置加入进去。
MongoProperties 实际上是抄的人家1.x版本的配置,所以2.x有的好像都没了。因为已经满足了大部分需求,没有再深入考虑。