共计 7990 个字符,预计需要花费 20 分钟才能阅读完成。
导读 | 这篇文章主要介绍了 SpringBoot 整合 mongoDB 并自定义连接池 , 整合 mongoDB 的目的就是想用它给我们提供的 mongoTemplate,它可以很容易的操作 mongoDB 数据库,对整合过程及实例代码感兴趣的朋友跟随小编一起看看吧 |
得力于 SpringBoot 的特性,整合 mongoDB 是很容易的,我们整合 mongoDB 的目的就是想用它给我们提供的 mongoTemplate,它可以很容易的操作 mongoDB 数据库。
为了自定义连接池,我们在配置类中主要与 MongoClientOptions、MongoCredential、MongoClient、MongoDbFactory 打交道。最终的目的就是配置好一个 MongoDbFactory 的 bean 交由 Spring 管理。
org.springframework.boot
spring-boot-starter-data-mongodb
配置文件
mongodb:
database: bfa_mongo
username: "xxx"
password: "xxxxx"
address: "host:port"
authenticationDatabase: [设置你的认证数据库,如果有的话]
# 连接池配置
clientName: ${spring.application.name} # 客户端的标识,用于定位请求来源等
connectionTimeoutMs: 10000 # TCP 连接超时,毫秒
readTimeoutMs: 15000 # TCP 读取超时,毫秒
poolMaxWaitTimeMs: 3000 #当连接池无可用连接时客户端阻塞等待的时长,单位毫秒
connectionMaxIdleTimeMs: 60000 #TCP 连接闲置时间,单位毫秒
connectionMaxLifeTimeMs: 120000 #TCP 连接最多可以使用多久,单位毫秒
heartbeatFrequencyMs: 20000 #心跳检测发送频率,单位毫秒
minHeartbeatFrequencyMs: 8000 #最小的心跳检测发送频率,单位毫秒
heartbeatConnectionTimeoutMs: 10000 #心跳检测 TCP 连接超时,单位毫秒
heartbeatReadTimeoutMs: 15000 #心跳检测 TCP 连接读取超时,单位毫秒
connectionsPerHost: 20 # 每个 host 的 TCP 连接数
minConnectionsPerHost: 5 #每个 host 的最小 TCP 连接数
#计算允许多少个线程阻塞等待可用 TCP 连接时的乘数,算法:threadsAllowedToBlockForConnectionMultiplier*connectionsPerHost,当前配置允许 10*20 个线程阻塞
threadsAllowedToBlockForConnectionMultiplier: 10
注意: 其中的 address 参数可以配置为一个数组(代表集群模式)
address:
- "host:port"
- "host2:port2"
配置类中使用了 lombok,如果你没有用 lombok 依赖和 IDE 插件,你要重写 getter、Setter 方法:
代码稍长,可以复制在 IDEA 中查看:
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@Configuration
@EnableConfigurationProperties(MongoConfig.MongoClientOptionProperties.class)
public class MongoConfig {
/**
* monogo 转换器
* @return
*/
@Bean
public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory,
MongoMappingContext context, BeanFactory beanFactory, MongoCustomConversions conversions) {DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
// remove _class field
// mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
mappingConverter.setCustomConversions(conversions);
return mappingConverter;
}
/**
* 自定义 mongo 连接池
* @param properties
* @return
*/
@Bean
public MongoDbFactory mongoDbFactory(MongoClientOptionProperties properties) {
// 创建客户端参数
MongoClientOptions options = mongoClientOptions(properties);
// 创建客户端和 Factory
List serverAddresses = new ArrayList();
for (String address : properties.getAddress()) {String[] hostAndPort = address.split(":");
String host = hostAndPort[0];
Integer port = Integer.parseInt(hostAndPort[1]);
ServerAddress serverAddress = new ServerAddress(host, port);
serverAddresses.add(serverAddress);
}
// 创建认证客户端
MongoCredential mongoCredential = MongoCredential.createScramSha1Credential(properties.getUsername(),
properties.getAuthenticationDatabase() != null ? properties.getAuthenticationDatabase() : properties.getDatabase(),
properties.getPassword().toCharArray());
MongoClient mongoClient = new MongoClient(serverAddresses.get(0), mongoCredential, options);
// 集群模式
if (serverAddresses.size() > 1) {mongoClient = new MongoClient(serverAddresses, new ArrayList(Arrays.asList(mongoCredential)));
}
/** ps: 创建非认证客户端 */
//MongoClient mongoClient = new MongoClient(serverAddresses, mongoClientOptions);
return new SimpleMongoDbFactory(mongoClient, properties.getDatabase());
}
/**
* mongo 客户端参数配置
* @return
*/
public MongoClientOptions mongoClientOptions(MongoClientOptionProperties properties) {return MongoClientOptions.builder()
.connectTimeout(properties.getConnectionTimeoutMs())
.socketTimeout(properties.getReadTimeoutMs()).applicationName(properties.getClientName())
.heartbeatConnectTimeout(properties.getHeartbeatConnectionTimeoutMs())
.heartbeatSocketTimeout(properties.getHeartbeatReadTimeoutMs())
.heartbeatFrequency(properties.getHeartbeatFrequencyMs())
.minHeartbeatFrequency(properties.getMinHeartbeatFrequencyMs())
.maxConnectionIdleTime(properties.getConnectionMaxIdleTimeMs())
.maxConnectionLifeTime(properties.getConnectionMaxLifeTimeMs())
.maxWaitTime(properties.getPoolMaxWaitTimeMs())
.connectionsPerHost(properties.getConnectionsPerHost())
.threadsAllowedToBlockForConnectionMultiplier(properties.getThreadsAllowedToBlockForConnectionMultiplier())
.minConnectionsPerHost(properties.getMinConnectionsPerHost()).build();}
@Getter
@Setter
@Validated
@ConfigurationProperties(prefix = "mongodb")
public static class MongoClientOptionProperties {
/** 基础连接参数 */
private String database;
private String username;
private String password;
@NotNull
private List address;
private String authenticationDatabase;
/** 客户端连接池参数 */
@NotNull
@Size(min = 1)
private String clientName;
/** socket 连接超时时间 */
@Min(value = 1)
private int connectionTimeoutMs;
/** socket 读取超时时间 */
@Min(value = 1)
private int readTimeoutMs;
/** 连接池获取链接等待时间 */
@Min(value = 1)
private int poolMaxWaitTimeMs;
/** 连接闲置时间 */
@Min(value = 1)
private int connectionMaxIdleTimeMs;
/** 连接最多可以使用多久 */
@Min(value = 1)
private int connectionMaxLifeTimeMs;
/** 心跳检测发送频率 */
@Min(value = 2000)
private int heartbeatFrequencyMs;
/** 最小的心跳检测发送频率 */
@Min(value = 300)
private int minHeartbeatFrequencyMs;
/** 计算允许多少个线程阻塞等待时的乘数,算法:threadsAllowedToBlockForConnectionMultiplier*connectionsPerHost */
@Min(value = 1)
private int threadsAllowedToBlockForConnectionMultiplier;
/** 心跳检测连接超时时间 */
@Min(value = 200)
private int heartbeatConnectionTimeoutMs;
/** 心跳检测读取超时时间 */
@Min(value = 200)
private int heartbeatReadTimeoutMs;
/** 每个 host 最大连接数 */
@Min(value = 1)
private int connectionsPerHost;
/** 每个 host 的最小连接数 */
@Min(value = 1)
private int minConnectionsPerHost;
}
}
MappingMongoConverter 可以自定义 mongo 转换器,主要自定义存取 mongo 数据时的一些操作,例如 mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null)) 方法会将 mongo 数据中的_class 字段去掉。
最后通过 new SimpleMongoDbFactory(mongoClient, properties.getDatabase()) 方法配置了一个 MongoDbFactory 交由 Spring 管理,Springboot 会拿这个 MongoDbFactory 工厂 bean 来 new 一个 MongoTemplate,在 MongoDbFactoryDependentConfiguration 类下可以看到 SpringBoot 帮你做得事:
/**
* Configuration for Mongo-related beans that depend on a {@link MongoDbFactory}.
*
* @author Andy Wilkinson
*/
@Configuration
@ConditionalOnBean(MongoDbFactory.class)
class MongoDbFactoryDependentConfiguration {
private final MongoProperties properties;
MongoDbFactoryDependentConfiguration(MongoProperties properties) {this.properties = properties;}
//SpringBoot 创建 MongoTemplate 实例
@Bean
@ConditionalOnMissingBean
public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter converter) {return new MongoTemplate(mongoDbFactory, converter);
@ConditionalOnMissingBean(MongoConverter.class)
public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory, MongoMappingContext context,
MongoCustomConversions conversions) {DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
mappingConverter.setCustomConversions(conversions);
return mappingConverter;
//...
}
SpringBoot 利用我们配置好的 MongoDbFactory 在配置类中生成一个 MongoTemplate,之后我们就可以在项目代码中直接 @Autowired 了。因为用于生成 MongoTemplate 的 MongoDbFactory 是我们自己在 MongoConfig 配置类中生成的,所以我们自定义的连接池参数也就生效了。
到此这篇关于 SpringBoot 整合 mongoDB 并自定义连接池的文章就介绍到这了。