cn.hutool.db.nosql.mongo.MongoDS Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hutool-all Show documentation
Show all versions of hutool-all Show documentation
Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
package cn.hutool.db.nosql.mongo;
import cn.hutool.core.exceptions.NotInitedException;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.DbRuntimeException;
import cn.hutool.log.Log;
import cn.hutool.setting.Setting;
import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.connection.ConnectionPoolSettings;
import com.mongodb.connection.SocketSettings;
import org.bson.Document;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* MongoDB4工具类
*
* @author VampireAchao
*/
public class MongoDS implements Closeable {
private final static Log log = Log.get();
/**
* 默认配置文件
*/
public final static String MONGO_CONFIG_PATH = "config/mongo.setting";
// MongoDB配置文件
private Setting setting;
// MongoDB实例连接列表
private String[] groups;
// MongoDB单点连接信息
private ServerAddress serverAddress;
// MongoDB客户端对象
private MongoClient mongo;
// --------------------------------------------------------------------------- Constructor start
/**
* 构造MongoDB数据源
* 调用者必须持有MongoDS实例,否则会被垃圾回收导致写入失败!
*
* @param host 主机(域名或者IP)
* @param port 端口
*/
public MongoDS(String host, int port) {
this.serverAddress = createServerAddress(host, port);
initSingle();
}
/**
* 构造MongoDB数据源
* 调用者必须持有MongoDS实例,否则会被垃圾回收导致写入失败!
*
* @param mongoSetting MongoDB的配置文件,如果是null则读取默认配置文件或者使用MongoDB默认客户端配置
* @param host 主机(域名或者IP)
* @param port 端口
*/
public MongoDS(Setting mongoSetting, String host, int port) {
this.setting = mongoSetting;
this.serverAddress = createServerAddress(host, port);
initSingle();
}
/**
* 构造MongoDB数据源
* 当提供多个数据源时,这些数据源将为一个副本集或者多个mongos
* 调用者必须持有MongoDS实例,否则会被垃圾回收导致写入失败! 官方文档: http://docs.mongodb.org/manual/administration/replica-sets/
*
* @param groups 分组列表,当为null或空时使用无分组配置,一个分组使用单一模式,否则使用副本集模式
*/
public MongoDS(String... groups) {
this.groups = groups;
init();
}
/**
* 构造MongoDB数据源
* 当提供多个数据源时,这些数据源将为一个副本集或者mongos
* 调用者必须持有MongoDS实例,否则会被垃圾回收导致写入失败!
* 官方文档: http://docs.mongodb.org/manual/administration/replica-sets/
*
* @param mongoSetting MongoDB的配置文件,必须有
* @param groups 分组列表,当为null或空时使用无分组配置,一个分组使用单一模式,否则使用副本集模式
*/
public MongoDS(Setting mongoSetting, String... groups) {
if (mongoSetting == null) {
throw new DbRuntimeException("Mongo setting is null!");
}
this.setting = mongoSetting;
this.groups = groups;
init();
}
// --------------------------------------------------------------------------- Constructor end
/**
* 初始化,当给定分组数大于一个时使用
*/
public void init() {
if (groups != null && groups.length > 1) {
initCloud();
} else {
initSingle();
}
}
/**
* 初始化
* 设定文件中的host和端口有三种形式:
*
*
* host = host:port
*
*
*
* host = host
* port = port
*
*
*
* host = host
*
*/
synchronized public void initSingle() {
if (setting == null) {
try {
setting = new Setting(MONGO_CONFIG_PATH, true);
} catch (Exception e) {
// 在single模式下,可以没有配置文件。
}
}
String group = StrUtil.EMPTY;
if (null == this.serverAddress) {
//存在唯一分组
if (groups != null && groups.length == 1) {
group = groups[0];
}
serverAddress = createServerAddress(group);
}
final MongoCredential credentail = createCredentail(group);
try {
MongoClientSettings.Builder clusterSettingsBuilder = MongoClientSettings.builder()
.applyToClusterSettings(b -> b.hosts(Collections.singletonList(serverAddress)));
buildMongoClientSettings(clusterSettingsBuilder, group);
if (null != credentail) {
clusterSettingsBuilder.credential(credentail);
}
mongo = MongoClients.create(clusterSettingsBuilder.build());
} catch (Exception e) {
throw new DbRuntimeException(StrUtil.format("Init MongoDB pool with connection to [{}] error!", serverAddress), e);
}
log.info("Init MongoDB pool with connection to [{}]", serverAddress);
}
/**
* 初始化集群
* 集群的其它客户端设定参数使用全局设定
* 集群中每一个实例成员用一个group表示,例如:
*
*
* user = test1
* pass = 123456
* database = test
* [db0]
* host = 192.168.1.1:27117
* [db1]
* host = 192.168.1.1:27118
* [db2]
* host = 192.168.1.1:27119
*
*/
synchronized public void initCloud() {
if (groups == null || groups.length == 0) {
throw new DbRuntimeException("Please give replication set groups!");
}
if (setting == null) {
// 若未指定配置文件,则使用默认配置文件
setting = new Setting(MONGO_CONFIG_PATH, true);
}
final List addrList = new ArrayList<>();
for (String group : groups) {
addrList.add(createServerAddress(group));
}
final MongoCredential credentail = createCredentail(StrUtil.EMPTY);
try {
MongoClientSettings.Builder clusterSettingsBuilder = MongoClientSettings.builder()
.applyToClusterSettings(b -> b.hosts(addrList));
buildMongoClientSettings(clusterSettingsBuilder, StrUtil.EMPTY);
if (null != credentail) {
clusterSettingsBuilder.credential(credentail);
}
mongo = MongoClients.create(clusterSettingsBuilder.build());
} catch (Exception e) {
log.error(e, "Init MongoDB connection error!");
return;
}
log.info("Init MongoDB cloud Set pool with connection to {}", addrList);
}
/**
* 设定MongoDB配置文件
*
* @param setting 配置文件
*/
public void setSetting(Setting setting) {
this.setting = setting;
}
/**
* @return 获得MongoDB客户端对象
*/
public MongoClient getMongo() {
return mongo;
}
/**
* 获得DB
*
* @param dbName DB
* @return DB
*/
public MongoDatabase getDb(String dbName) {
return mongo.getDatabase(dbName);
}
/**
* 获得MongoDB中指定集合对象
*
* @param dbName 库名
* @param collectionName 集合名
* @return DBCollection
*/
public MongoCollection getCollection(String dbName, String collectionName) {
return getDb(dbName).getCollection(collectionName);
}
@Override
public void close() {
mongo.close();
}
// --------------------------------------------------------------------------- Private method start
/**
* 创建ServerAddress对象,会读取配置文件中的相关信息
*
* @param group 分组,如果为{@code null}或者""默认为无分组
* @return ServerAddress
*/
private ServerAddress createServerAddress(String group) {
final Setting setting = checkSetting();
if (group == null) {
group = StrUtil.EMPTY;
}
final String tmpHost = setting.getByGroup("host", group);
if (StrUtil.isBlank(tmpHost)) {
throw new NotInitedException("Host name is empy of group: {}", group);
}
final int defaultPort = setting.getInt("port", group, 27017);
return new ServerAddress(NetUtil.buildInetSocketAddress(tmpHost, defaultPort));
}
/**
* 创建ServerAddress对象
*
* @param host 主机域名或者IP(如果为空默认127.0.0.1)
* @param port 端口(如果为空默认为)
* @return ServerAddress
*/
private ServerAddress createServerAddress(String host, int port) {
return new ServerAddress(host, port);
}
/**
* 创建{@link MongoCredential},用于服务端验证
* 此方法会首先读取指定分组下的属性,用户没有定义则读取空分组下的属性
*
* @param group 分组
* @return {@link MongoCredential},如果用户未指定用户名密码返回null
* @since 4.1.20
*/
private MongoCredential createCredentail(String group) {
final Setting setting = this.setting;
if (null == setting) {
return null;
}
final String user = setting.getStr("user", group, setting.getStr("user"));
final String pass = setting.getStr("pass", group, setting.getStr("pass"));
final String database = setting.getStr("database", group, setting.getStr("database"));
return createCredentail(user, database, pass);
}
/**
* 创建{@link MongoCredential},用于服务端验证
*
* @param userName 用户名
* @param database 数据库名
* @param password 密码
* @return {@link MongoCredential}
* @since 4.1.20
*/
private MongoCredential createCredentail(String userName, String database, String password) {
if (StrUtil.hasEmpty(userName, database, database)) {
return null;
}
return MongoCredential.createCredential(userName, database, password.toCharArray());
}
/**
* 构件MongoDB连接选项
*
* @param group 分组,当分组对应的选项不存在时会读取根选项,如果也不存在使用默认值
* @return Builder
*/
private MongoClientSettings.Builder buildMongoClientSettings(MongoClientSettings.Builder builder, String group) {
if (setting == null) {
return builder;
}
if (StrUtil.isEmpty(group)) {
group = StrUtil.EMPTY;
} else {
group = group + StrUtil.DOT;
}
// 每个主机答应的连接数(每个主机的连接池大小),当连接池被用光时,会被阻塞住
Integer connectionsPerHost = setting.getInt(group + "connectionsPerHost");
if (StrUtil.isBlank(group) == false && connectionsPerHost == null) {
connectionsPerHost = setting.getInt("connectionsPerHost");
}
ConnectionPoolSettings.Builder connectionPoolSettingsBuilder = ConnectionPoolSettings.builder();
if (connectionsPerHost != null) {
connectionPoolSettingsBuilder.maxSize(connectionsPerHost);
log.debug("MongoDB connectionsPerHost: {}", connectionsPerHost);
}
// 被阻塞线程从连接池获取连接的最长等待时间(ms) --int
Integer connectTimeout = setting.getInt(group + "connectTimeout");
if (StrUtil.isBlank(group) == false && connectTimeout == null) {
setting.getInt("connectTimeout");
}
if (connectTimeout != null) {
connectionPoolSettingsBuilder.maxWaitTime(connectTimeout, TimeUnit.MILLISECONDS);
log.debug("MongoDB connectTimeout: {}", connectTimeout);
}
builder.applyToConnectionPoolSettings(b -> b.applySettings(connectionPoolSettingsBuilder.build()));
// 套接字超时时间;该值会被传递给Socket.setSoTimeout(int)。默以为0(无穷) --int
Integer socketTimeout = setting.getInt(group + "socketTimeout");
if (StrUtil.isBlank(group) == false && socketTimeout == null) {
setting.getInt("socketTimeout");
}
if (socketTimeout != null) {
SocketSettings socketSettings = SocketSettings.builder().connectTimeout(socketTimeout, TimeUnit.MILLISECONDS).build();
builder.applyToSocketSettings(b -> b.applySettings(socketSettings));
log.debug("MongoDB socketTimeout: {}", socketTimeout);
}
return builder;
}
/**
* 检查Setting配置文件
*
* @return Setting配置文件
*/
private Setting checkSetting() {
if (null == this.setting) {
throw new DbRuntimeException("Please indicate setting file or create default [{}]", MONGO_CONFIG_PATH);
}
return this.setting;
}
// --------------------------------------------------------------------------- Private method end
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy