阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

教你SpringBoot 整合mongoDB并自定义连接池

26次阅读
没有评论

共计 7990 个字符,预计需要花费 20 分钟才能阅读完成。

导读 这篇文章主要介绍了 SpringBoot 整合 mongoDB 并自定义连接池 , 整合 mongoDB 的目的就是想用它给我们提供的 mongoTemplate,它可以很容易的操作 mongoDB 数据库,对整合过程及实例代码感兴趣的朋友跟随小编一起看看吧

得力于 SpringBoot 的特性,整合 mongoDB 是很容易的,我们整合 mongoDB 的目的就是想用它给我们提供的 mongoTemplate,它可以很容易的操作 mongoDB 数据库。

为了自定义连接池,我们在配置类中主要与 MongoClientOptions、MongoCredential、MongoClient、MongoDbFactory 打交道。最终的目的就是配置好一个 MongoDbFactory 的 bean 交由 Spring 管理。

Maven 依赖

    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"
MongoConfig 配置类

配置类中使用了 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 并自定义连接池的文章就介绍到这了。

阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

代金券:在阿里云专用满减优惠券

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-07-25发表,共计7990字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中