From 494c70b9e69a3d5e8c25649254b2d8dab425dd33 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 19 Dec 2023 02:45:22 +0800 Subject: [PATCH] fix code --- .../PoolException.java} | 24 +- .../core/pool/partition/PoolPartition.java | 18 +- .../hutool/core/text/CharSequenceUtil.java | 2 +- .../hutool/db/ds/AbstractDSFactory.java | 224 --------------- .../org/dromara/hutool/db/ds/DSFactory.java | 48 +--- .../java/org/dromara/hutool/db/ds/DSPool.java | 265 ++++++++++++++++++ .../java/org/dromara/hutool/db/ds/DSUtil.java | 50 +--- .../org/dromara/hutool/db/ds/DbConfig.java | 238 ++++++++++++++++ .../dromara/hutool/db/ds/GlobalDSFactory.java | 91 ------ .../hutool/db/ds/bee/BeeDSFactory.java | 52 ++-- .../hutool/db/ds/c3p0/C3p0DSFactory.java | 72 ++--- .../hutool/db/ds/dbcp/DbcpDSFactory.java | 62 ++-- .../hutool/db/ds/druid/DruidDSFactory.java | 59 ++-- .../hutool/db/ds/hikari/HikariDSFactory.java | 68 ++--- .../hutool/db/ds/jndi/JndiDSFactory.java | 32 +-- .../hutool/db/ds/pooled/PooledConnection.java | 3 +- .../hutool/db/ds/pooled/PooledDSFactory.java | 55 +--- .../hutool/db/ds/pooled/PooledDataSource.java | 24 +- .../hutool/db/ds/pooled/PooledDbConfig.java | 117 -------- .../dromara/hutool/db/ds/simple/DbConfig.java | 117 -------- .../hutool/db/ds/simple/SimpleDSFactory.java | 36 +-- .../hutool/db/ds/simple/SimpleDataSource.java | 1 + .../hutool/db/ds/tomcat/TomcatDSFactory.java | 59 ++-- .../hutool/db/ds/DataSourceWrapperTest.java | 1 - .../org/dromara/hutool/setting/Setting.java | 12 +- .../dromara/hutool/setting/props/Props.java | 85 +++++- .../hutool/setting/props/PropsTest.java | 13 +- 27 files changed, 796 insertions(+), 1032 deletions(-) rename hutool-core/src/main/java/org/dromara/hutool/core/{exception/NotInitedException.java => pool/PoolException.java} (65%) delete mode 100644 hutool-db/src/main/java/org/dromara/hutool/db/ds/AbstractDSFactory.java create mode 100644 hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java create mode 100644 hutool-db/src/main/java/org/dromara/hutool/db/ds/DbConfig.java delete mode 100644 hutool-db/src/main/java/org/dromara/hutool/db/ds/GlobalDSFactory.java delete mode 100644 hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledDbConfig.java delete mode 100644 hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/DbConfig.java diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/exception/NotInitedException.java b/hutool-core/src/main/java/org/dromara/hutool/core/pool/PoolException.java similarity index 65% rename from hutool-core/src/main/java/org/dromara/hutool/core/exception/NotInitedException.java rename to hutool-core/src/main/java/org/dromara/hutool/core/pool/PoolException.java index f6334b8df..a3b9ecfb3 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/exception/NotInitedException.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/pool/PoolException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 looly(loolly@aliyun.com) + * Copyright (c) 2023. looly(loolly@aliyun.com) * Hutool is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: @@ -10,22 +10,24 @@ * See the Mulan PSL v2 for more details. */ -package org.dromara.hutool.core.exception; +package org.dromara.hutool.core.pool; + +import org.dromara.hutool.core.exception.HutoolException; /** - * 未初始化异常 + * 对象池异常 * * @author Looly */ -public class NotInitedException extends HutoolException { - private static final long serialVersionUID = 8247610319171014183L; +public class PoolException extends HutoolException { + private static final long serialVersionUID = 1L; /** * 构造 * * @param e 异常 */ - public NotInitedException(final Throwable e) { + public PoolException(final Throwable e) { super(e); } @@ -34,7 +36,7 @@ public class NotInitedException extends HutoolException { * * @param message 消息 */ - public NotInitedException(final String message) { + public PoolException(final String message) { super(message); } @@ -44,7 +46,7 @@ public class NotInitedException extends HutoolException { * @param messageTemplate 消息模板 * @param params 参数 */ - public NotInitedException(final String messageTemplate, final Object... params) { + public PoolException(final String messageTemplate, final Object... params) { super(messageTemplate, params); } @@ -54,7 +56,7 @@ public class NotInitedException extends HutoolException { * @param message 消息 * @param cause 被包装的子异常 */ - public NotInitedException(final String message, final Throwable cause) { + public PoolException(final String message, final Throwable cause) { super(message, cause); } @@ -66,7 +68,7 @@ public class NotInitedException extends HutoolException { * @param enableSuppression 是否启用抑制 * @param writableStackTrace 堆栈跟踪是否应该是可写的 */ - public NotInitedException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) { + public PoolException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } @@ -77,7 +79,7 @@ public class NotInitedException extends HutoolException { * @param messageTemplate 消息模板 * @param params 参数 */ - public NotInitedException(final Throwable cause, final String messageTemplate, final Object... params) { + public PoolException(final Throwable cause, final String messageTemplate, final Object... params) { super(cause, messageTemplate, params); } } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PoolPartition.java b/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PoolPartition.java index faf91dbfd..0e9b632b4 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PoolPartition.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/pool/partition/PoolPartition.java @@ -12,11 +12,7 @@ package org.dromara.hutool.core.pool.partition; -import org.dromara.hutool.core.exception.HutoolException; -import org.dromara.hutool.core.pool.ObjectFactory; -import org.dromara.hutool.core.pool.ObjectPool; -import org.dromara.hutool.core.pool.PoolConfig; -import org.dromara.hutool.core.pool.Poolable; +import org.dromara.hutool.core.pool.*; import java.io.IOException; import java.util.concurrent.BlockingQueue; @@ -99,7 +95,7 @@ public class PoolPartition implements ObjectPool { poolable = waitingPoll(); if (null == poolable) { // 池空间达到最大值,但是无可用对象 - throw new HutoolException("Pool exhausted!"); + throw new PoolException("Pool exhausted!"); } } @@ -122,7 +118,7 @@ public class PoolPartition implements ObjectPool { try { this.queue.put(poolable); } catch (final InterruptedException e) { - throw new HutoolException(e); + throw new PoolException(e); } } else { // 对象不可用 @@ -150,7 +146,7 @@ public class PoolPartition implements ObjectPool { } total += increaseSize; } catch (final InterruptedException e) { - throw new HutoolException(e); + throw new PoolException(e); } return increaseSize; } @@ -208,9 +204,9 @@ public class PoolPartition implements ObjectPool { * 等待的时间取决于{@link PoolConfig#getMaxWait()},小于等于0时一直等待,否则等待给定毫秒数 * * @return 取出的池对象 - * @throws HutoolException 中断异常 + * @throws PoolException 中断异常 */ - private Poolable waitingPoll() throws HutoolException { + private Poolable waitingPoll() throws PoolException { final long maxWait = this.config.getMaxWait(); try { if (maxWait <= 0) { @@ -218,7 +214,7 @@ public class PoolPartition implements ObjectPool { } return this.queue.poll(maxWait, TimeUnit.MILLISECONDS); } catch (final InterruptedException e) { - throw new HutoolException(e); + throw new PoolException(e); } } } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java index f11fc28e3..03a30a5f4 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/text/CharSequenceUtil.java @@ -1325,7 +1325,7 @@ public class CharSequenceUtil extends StrValidator { * @see #appendIfMissing(CharSequence, CharSequence, CharSequence...) */ public static String addSuffixIfNot(final CharSequence str, final CharSequence suffix) { - return appendIfMissing(str, suffix, suffix); + return appendIfMissing(str, suffix); } // endregion diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/AbstractDSFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/AbstractDSFactory.java deleted file mode 100644 index 933fa16b9..000000000 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/AbstractDSFactory.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2023 looly(loolly@aliyun.com) - * Hutool is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * https://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - -package org.dromara.hutool.db.ds; - -import org.dromara.hutool.core.lang.Assert; -import org.dromara.hutool.core.map.MapUtil; -import org.dromara.hutool.core.map.SafeConcurrentHashMap; -import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.db.DbRuntimeException; -import org.dromara.hutool.db.DbUtil; -import org.dromara.hutool.db.GlobalDbConfig; -import org.dromara.hutool.db.driver.DriverUtil; -import org.dromara.hutool.setting.Setting; - -import javax.sql.DataSource; -import java.util.Collection; -import java.util.Map; - -/** - * 抽象数据源工厂
- * 此工厂抽象类用于实现数据源的缓存,当用户多次调用{@link #getDataSource(String)} 时,工厂只需创建一次即可。
- * 数据源是与配置文件中的分组相关的,每个分组的数据源相互独立,也就是每个分组的数据源是单例存在的。 - * - * @author looly - */ -public abstract class AbstractDSFactory implements DSFactory { - private static final long serialVersionUID = -6407302276272379881L; - - /** - * 数据源名 - */ - protected final String dataSourceName; - /** - * 数据库连接配置文件 - */ - private final Setting setting; - /** - * 数据源池 - */ - private final Map dsMap; - - /** - * 构造 - * - * @param dataSourceName 数据源名称 - * @param dataSourceClass 数据库连接池实现类,用于检测所提供的DataSource类是否存在,当传入的DataSource类不存在时抛出ClassNotFoundException
- * 此参数的作用是在detectDSFactory方法自动检测所用连接池时,如果实现类不存在,调用此方法会自动抛出异常,从而切换到下一种连接池的检测。 - * @param setting 数据库连接配置,如果为{@code null},则读取全局自定义或默认配置 - */ - public AbstractDSFactory(final String dataSourceName, final Class dataSourceClass, Setting setting) { - //此参数的作用是在detectDSFactory方法自动检测所用连接池时,如果实现类不存在,调用此方法会自动抛出异常,从而切换到下一种连接池的检测。 - Assert.notNull(dataSourceClass); - - this.dataSourceName = dataSourceName; - - if (null == setting) { - setting = GlobalDbConfig.createDbSetting(); - } - // 读取配置,用于SQL打印 - DbUtil.setShowSqlGlobal(setting); - this.setting = setting; - - this.dsMap = new SafeConcurrentHashMap<>(); - } - - /** - * 获取配置,用于自定义添加配置项 - * - * @return Setting - * @since 4.0.3 - */ - public Setting getSetting() { - return this.setting; - } - - @Override - public String getDataSourceName() { - return this.dataSourceName; - } - - @Override - public DataSource getDataSource(String group) { - if (group == null) { - group = StrUtil.EMPTY; - } - - // 如果已经存在已有数据源(连接池)直接返回 - return dsMap.computeIfAbsent(group, this::_createDataSource); - } - - @Override - synchronized public void closeDataSource(String group) { - if (group == null) { - group = StrUtil.EMPTY; - } - - final DSWrapper ds = dsMap.get(group); - if (ds != null) { - ds.close(); - dsMap.remove(group); - } - } - - @Override - public void close() { - if (MapUtil.isNotEmpty(dsMap)) { - final Collection values = dsMap.values(); - for (final DSWrapper ds : values) { - ds.close(); - } - dsMap.clear(); - } - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((dataSourceName == null) ? 0 : dataSourceName.hashCode()); - result = prime * result + ((setting == null) ? 0 : setting.hashCode()); - return result; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final AbstractDSFactory other = (AbstractDSFactory) obj; - if (dataSourceName == null) { - if (other.dataSourceName != null) { - return false; - } - } else if (!dataSourceName.equals(other.dataSourceName)) { - return false; - } - if (setting == null) { - return other.setting == null; - } else { - return setting.equals(other.setting); - } - } - - /** - * 创建新的{@link DataSource}
- * 子类通过实现此方法,创建一个对接连接池的数据源 - * - * @param jdbcUrl JDBC连接字符串 - * @param driver 数据库驱动类名 - * @param user 用户名 - * @param pass 密码 - * @param poolSetting 分组下的连接池配置文件 - * @return {@link DataSource} - */ - protected abstract DataSource createDataSource( - String jdbcUrl, String driver, String user, String pass, Setting poolSetting); - - /** - * 创建数据源,对于不同连接池名称的的差异做兼容,如用户配置user和username都表示用户名 - * - * @param group 分组 - * @return {@link DSWrapper} 数据源包装 - */ - private DSWrapper _createDataSource(String group) { - if (group == null) { - group = StrUtil.EMPTY; - } - - final Setting config = setting.getSetting(group); - if (MapUtil.isEmpty(config)) { - throw new DbRuntimeException("No config for group: [{}]", group); - } - - // 基本信息 - final String url = config.getAndRemove(DSKeys.KEY_ALIAS_URL); - if (StrUtil.isBlank(url)) { - throw new DbRuntimeException("No JDBC URL for group: [{}]", group); - } - - // 移除用户可能误加入的show sql配置项 - // issue#I3VW0R@Gitee - removeShowSqlParams(config); - - // 自动识别Driver - String driver = config.getAndRemove(DSKeys.KEY_ALIAS_DRIVER); - if (StrUtil.isBlank(driver)) { - driver = DriverUtil.identifyDriver(url); - } - final String user = config.getAndRemove(DSKeys.KEY_ALIAS_USER); - final String pass = config.getAndRemove(DSKeys.KEY_ALIAS_PASSWORD); - - return DSWrapper.wrap(createDataSource(url, driver, user, pass, config), driver); - } - - /** - * 移除配置文件中的Show SQL相关配置项
- * 此方法用于移除用户配置在分组下的配置项目 - * - * @param setting 配置项 - * @since 5.7.2 - */ - private static void removeShowSqlParams(final Setting setting) { - setting.remove(DSKeys.KEY_SHOW_SQL); - setting.remove(DSKeys.KEY_FORMAT_SQL); - setting.remove(DSKeys.KEY_SHOW_PARAMS); - setting.remove(DSKeys.KEY_SQL_LEVEL); - } -} diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSFactory.java index 188a5002e..f40a77025 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSFactory.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 looly(loolly@aliyun.com) + * Copyright (c) 2023. looly(loolly@aliyun.com) * Hutool is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: @@ -12,17 +12,12 @@ package org.dromara.hutool.db.ds; -import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.setting.Setting; - import javax.sql.DataSource; -import java.io.Closeable; import java.io.Serializable; /** - * 多数据源工厂方法接口,借助不同配置,同一个工厂可以连接多个相同或不同的数据库,但是连接池只能使用一种。
- * 通过实现{@link #getDataSource(String)} 方法完成数据源的获取。
- * 如果{@link DataSource} 的实现是数据库连接池库,应该在getDataSource调用时创建数据源并缓存,关系如下: + * 多数据源{@link DataSource}工厂方法接口,借助不同配置,同一个工厂可以连接多个相同或不同的数据库,但是连接池只能使用一种。
+ * 通过实现{@link #createDataSource(DbConfig)} 方法完成数据源的创建。关系如下:
*
  *                            DSFactory
  *            _____________________|____________________
@@ -33,13 +28,9 @@ import java.io.Serializable;
  *     MySQL    SQLite    SQLServer  XXXDB   XXXDB2
  * 
* - *

- * 工厂创建请使用{@link DSUtil#createFactory(Setting)} - *

- * * @author Looly */ -public interface DSFactory extends Closeable, Serializable { +public interface DSFactory extends Serializable { /** * 获取自定义的数据源名称,用于识别连接池 @@ -49,33 +40,10 @@ public interface DSFactory extends Closeable, Serializable { String getDataSourceName(); /** - * 获得默认数据源,即""分组的数据源 + * 创建数据源 * - * @return 数据源 + * @param config 数据库配置 + * @return {@link DataSource} */ - default DataSource getDataSource() { - return getDataSource(StrUtil.EMPTY); - } - - /** - * 获得分组对应数据源 - * - * @param group 分组名 - * @return 数据源 - */ - DataSource getDataSource(String group); - - /** - * 关闭默认数据源(空组) - */ - default void closeDataSource() { - closeDataSource(StrUtil.EMPTY); - } - - /** - * 关闭(归还)对应数据源 - * - * @param group 分组 - */ - void closeDataSource(String group); + DataSource createDataSource(DbConfig config); } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java new file mode 100644 index 000000000..40debc2bd --- /dev/null +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2023. looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * https://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.db.ds; + +import org.dromara.hutool.core.io.IoUtil; +import org.dromara.hutool.core.map.MapUtil; +import org.dromara.hutool.core.map.SafeConcurrentHashMap; +import org.dromara.hutool.core.spi.SpiUtil; +import org.dromara.hutool.core.text.StrUtil; +import org.dromara.hutool.db.DbRuntimeException; +import org.dromara.hutool.db.GlobalDbConfig; +import org.dromara.hutool.db.driver.DriverUtil; +import org.dromara.hutool.log.LogUtil; +import org.dromara.hutool.setting.Setting; +import org.dromara.hutool.setting.props.Props; + +import javax.sql.DataSource; +import java.io.Closeable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +/** + * 数据源池,用于支持多数据源。
+ * 在指定Setting中配置多个数据源时,通过分组(group)区分
+ * 每次获得一个数据源则缓存在pool中,确保数据源保持单例状态。 + * + * @author Looly + * @since 6.0.0 + */ +public class DSPool implements Closeable { + + private static final String CONNECTION_PREFIX = "connection."; + + private static class SingletonHolder { + private static final DSPool INSTANCE = new DSPool(); + } + + /** + * 获取单例池对象 + * + * @return 数据源池 + */ + public static DSPool getInstance() { + return SingletonHolder.INSTANCE; + } + + /** + * 数据库连接配置文件 + */ + private final Setting setting; + /** + * 数据源池 + */ + private final Map pool; + /** + * 连接工厂 + */ + private DSFactory factory; + + /** + * 构造,通过SPI方式自动获取用户引入的连接池,使用classpath:db.setting + */ + public DSPool() { + this(null); + } + + /** + * 构造,通过SPI方式自动获取用户引入的连接池 + * + * @param setting 数据库配置,支持多数据源,{@code null}表示读取classpath:db.setting + */ + public DSPool(final Setting setting) { + this(setting, null); + } + + /** + * 构造 + * + * @param setting 数据库配置,支持多数据源,{@code null}表示读取classpath:db.setting + * @param factory 数据源工厂,用于创建数据源,{@code null}表示使用SPI自动获取 + */ + public DSPool(final Setting setting, final DSFactory factory) { + this.setting = null != setting ? setting : GlobalDbConfig.createDbSetting(); + this.factory = null != factory ? factory : SpiUtil.loadFirstAvailable(DSFactory.class); + this.pool = new SafeConcurrentHashMap<>(); + } + + /** + * 获取配置,用于自定义添加配置项 + * + * @return Setting + * @since 4.0.3 + */ + public Setting getSetting() { + return this.setting; + } + + /** + * 获取数据源名称,用于识别当前使用连接池类型 + * + * @return 数据源名称 + */ + public String getDataSourceName() { + return this.factory.getDataSourceName(); + } + + /** + * 设置自定义的{@link DSFactory} + * + * @param factory {@link DSFactory} + * @return this + */ + public DSPool setFactory(final DSFactory factory) { + this.factory = factory; + LogUtil.debug("Custom use [{}] DataSource.", factory.getDataSourceName()); + return this; + } + + /** + * 获取指定分组的数据源,单例获取 + * + * @param group 分组,{@code null}表示默认分组 + * @return 数据源 + */ + public DataSource getDataSource(String group) { + if (group == null) { + group = StrUtil.EMPTY; + } + + // 如果已经存在已有数据源(连接池)直接返回 + return pool.computeIfAbsent(group, this::createDSWrapper); + } + + /** + * 关闭指定数据源 + * + * @param group 分组 + * @return this + */ + public DSPool closeDataSource(String group) { + if (group == null) { + group = StrUtil.EMPTY; + } + + // 此处线程安全,任意线程进入一旦remove完成,后续线程调用remove后都为null + final DSWrapper removed = pool.remove(group); + if (null != removed) { + IoUtil.closeQuietly(removed); + } + return this; + } + + @Override + public void close() { + final Map pool = this.pool; + if (MapUtil.isNotEmpty(pool)) { + // 此处线程安全,多线程调用可能多次调用clear,不影响 + final Collection values = pool.values(); + pool.clear(); + for (final DSWrapper ds : values) { + ds.close(); + } + } + } + + /** + * 创建数据源,对于不同连接池名称的的差异做兼容,如用户配置user和username都表示用户名 + * + * @param group 分组,{@code null}表示默认分组 + * @return {@link DSWrapper} 数据源包装 + */ + private DSWrapper createDSWrapper(String group) { + if (group == null) { + group = StrUtil.EMPTY; + } + + final Setting subSetting = setting.getSetting(group); + if (MapUtil.isEmpty(subSetting)) { + throw new DbRuntimeException("No config for group: [{}]", group); + } + + final DbConfig dbConfig = toDbConfig(subSetting); + + return DSWrapper.wrap(factory.createDataSource(dbConfig), dbConfig.getDriver()); + } + + /** + * {@link Setting}数据库配置 转 {@link DbConfig} + * + * @param setting {@link Setting}数据库配置 + * @return {@link DbConfig} + */ + private static DbConfig toDbConfig(final Setting setting) { + // 基本信息 + final String url = setting.getAndRemove(DSKeys.KEY_ALIAS_URL); + if (StrUtil.isBlank(url)) { + throw new DbRuntimeException("No JDBC URL!"); + } + + // 移除用户可能误加入的show sql配置项 + // issue#I3VW0R@Gitee + removeShowSqlParams(setting); + + // 自动识别Driver + String driver = setting.getAndRemove(DSKeys.KEY_ALIAS_DRIVER); + if (StrUtil.isBlank(driver)) { + driver = DriverUtil.identifyDriver(url); + } + + final DbConfig dbConfig = DbConfig.of() + .setUrl(url) + .setDriver(driver) + .setUser(setting.getAndRemove(DSKeys.KEY_ALIAS_USER)) + .setPass(setting.getAndRemove(DSKeys.KEY_ALIAS_PASSWORD)); + + // remarks等连接配置,since 5.3.8 + String connValue; + for (final String key : DSKeys.KEY_CONN_PROPS) { + connValue = setting.getAndRemove(key); + if (StrUtil.isNotBlank(connValue)) { + dbConfig.addConnProps(key, connValue); + } + } + + // 自定义连接属性 + final Props connProps = new Props(); + final Set keys = setting.keySet(); + for (final String key : keys) { + if (key.startsWith(CONNECTION_PREFIX)) { + connProps.set(StrUtil.subSuf(key, CONNECTION_PREFIX.length()), setting.remove(key)); + } + } + dbConfig.setConnProps(connProps); + + // 池属性 + dbConfig.setPoolProps(setting.toProps()); + + return dbConfig; + } + + /** + * 移除配置文件中的Show SQL相关配置项
+ * 此方法用于移除用户配置在分组下的配置项目 + * + * @param setting 配置项 + * @since 5.7.2 + */ + private static void removeShowSqlParams(final Setting setting) { + setting.remove(DSKeys.KEY_SHOW_SQL); + setting.remove(DSKeys.KEY_FORMAT_SQL); + setting.remove(DSKeys.KEY_SHOW_PARAMS); + setting.remove(DSKeys.KEY_SQL_LEVEL); + } +} diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSUtil.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSUtil.java index 9868a77ab..598c71f24 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSUtil.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSUtil.java @@ -12,19 +12,15 @@ package org.dromara.hutool.db.ds; -import org.dromara.hutool.core.reflect.ConstructorUtil; -import org.dromara.hutool.core.spi.ListServiceLoader; import org.dromara.hutool.db.DbRuntimeException; -import org.dromara.hutool.db.GlobalDbConfig; import org.dromara.hutool.log.LogUtil; -import org.dromara.hutool.setting.Setting; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; /** - * {@link DataSource}和{@link DSFactory}相关工具类
+ * {@link DataSource}相关工具类
* 主要提供数据源工厂的创建和数据源的获取 * * @author looly @@ -78,7 +74,7 @@ public class DSUtil { * @return 数据源 */ public static DataSource getDS(final String group) { - return GlobalDSFactory.get().getDataSource(group); + return DSPool.getInstance().getDataSource(group); } /** @@ -95,47 +91,7 @@ public class DSUtil { * @return 自定义的数据源工厂 */ public static DSFactory setGlobalDSFactory(final DSFactory dsFactory) { - return GlobalDSFactory.set(dsFactory); - } - - /** - * 创建数据源实现工厂
- * 此方法通过“试错”方式查找引入项目的连接池库,按照优先级寻找,一旦寻找到则创建对应的数据源工厂
- * 连接池优先级:Hikari > Druid > Tomcat > Dbcp > C3p0 > Hutool Pooled - * - * @param setting 数据库配置项 - * @return 日志实现类 - */ - public static DSFactory createFactory(final Setting setting) { - final DSFactory dsFactory = _createFactory(setting); - LogUtil.debug("Use [{}] DataSource As Default.", dsFactory.getDataSourceName()); + DSPool.getInstance().setFactory(dsFactory); return dsFactory; } - - /** - * 创建数据源实现工厂
- * 此方法通过“试错”方式查找引入项目的连接池库,按照优先级寻找,一旦寻找到则创建对应的数据源工厂
- * 连接池优先级:Hikari > Druid > Tomcat > BeeCP > Dbcp > C3p0 > Hutool Pooled
- * 见:META-INF/services/org.dromara.hutool.db.ds.DSFactory - * - * @param setting 数据库配置项 - * @return 日志实现类 - * @since 4.1.3 - */ - private static DSFactory _createFactory(Setting setting) { - if (null == setting) { - setting = GlobalDbConfig.createDbSetting(); - } - final ListServiceLoader loader = ListServiceLoader.of(DSFactory.class); - final int size = loader.size(); - for (int i = 0; i < size; i++) { - try { - return ConstructorUtil.newInstance(loader.getServiceClass(i), setting); - } catch (final NoClassDefFoundError | NoSuchMethodError e) { - // ignore - } - } - - throw new DbRuntimeException("No DSFactory implement available!"); - } } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DbConfig.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DbConfig.java new file mode 100644 index 000000000..5234ea2cc --- /dev/null +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DbConfig.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2023. looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * https://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.db.ds; + +import org.dromara.hutool.db.DbRuntimeException; +import org.dromara.hutool.db.driver.DriverUtil; + +import java.util.Properties; + +/** + * 数据库配置,包括: + *
    + *
  • 基本配置项,如driver、url、user、password等
  • + *
  • 连接配置,如remarks、useInformationSchema等
  • + *
  • 连接池配置,如初始容量、最大容量等,取决于连接池库具体要求
  • + *
+ * + * @author Looly + */ +public class DbConfig { + + /** + * 创建DbConfig + * + * @return DbConfig + */ + public static DbConfig of() { + return new DbConfig(); + } + + private String driver; //数据库驱动 + private String url; //jdbc url + private String user; //用户名 + private String pass; //密码 + + // 连接配置 + private Properties connProps; + // 连接池配置 + private Properties poolProps; + + /** + * 构造 + */ + public DbConfig() { + } + + /** + * 构造 + * + * @param url jdbc url + * @param user 用户名 + * @param pass 密码 + */ + public DbConfig(final String url, final String user, final String pass) { + init(url, user, pass); + } + + /** + * 初始化 + * + * @param url jdbc url + * @param user 用户名 + * @param pass 密码 + */ + public void init(final String url, final String user, final String pass) { + this.url = url; + this.user = user; + this.pass = pass; + this.driver = DriverUtil.identifyDriver(url); + try { + Class.forName(this.driver); + } catch (final ClassNotFoundException e) { + throw new DbRuntimeException(e, "Get jdbc driver from [{}] error!", url); + } + } + + /** + * 获取JDBC驱动 + * + * @return JDBC驱动 + */ + public String getDriver() { + return driver; + } + + /** + * 设置JDBC驱动 + * + * @param driver JDBC驱动 + * @return this + */ + public DbConfig setDriver(final String driver) { + this.driver = driver; + return this; + } + + /** + * 获取JDBC URL + * + * @return JDBC URL + */ + public String getUrl() { + return url; + } + + /** + * 设置JDBC URL + * + * @param url JDBC URL + * @return this + */ + public DbConfig setUrl(final String url) { + this.url = url; + return this; + } + + /** + * 获取用户名 + * + * @return 用户名 + */ + public String getUser() { + return user; + } + + /** + * 设置用户名 + * + * @param user 用户名 + * @return this + */ + public DbConfig setUser(final String user) { + this.user = user; + return this; + } + + /** + * 获取密码 + * + * @return 密码 + */ + public String getPass() { + return pass; + } + + /** + * 设置密码 + * + * @param pass 密码 + * @return this + */ + public DbConfig setPass(final String pass) { + this.pass = pass; + return this; + } + + /** + * 获取连接属性 + * + * @return 连接属性 + */ + public Properties getConnProps() { + return connProps; + } + + /** + * 设置连接属性 + * + * @param connProps 连接属性 + * @return this + */ + public DbConfig setConnProps(final Properties connProps) { + this.connProps = connProps; + + return this; + } + + /** + * 增加连接属性 + * + * @param key 属性名 + * @param value 属性值 + * @return this + */ + public DbConfig addConnProps(final String key, final String value) { + if (null == this.connProps) { + this.connProps = new Properties(); + } + this.connProps.setProperty(key, value); + return this; + } + + /** + * 获取连接池属性 + * + * @return 连接池属性 + */ + public Properties getPoolProps() { + return poolProps; + } + + /** + * 设置连接池属性 + * + * @param poolProps 连接池属性 + * @return this + */ + public DbConfig setPoolProps(final Properties poolProps) { + this.poolProps = poolProps; + + return this; + } + + /** + * 增加连接池属性 + * + * @param key 属性名 + * @param value 属性值 + * @return this + */ + public DbConfig addPoolProps(final String key, final String value) { + if (null == this.poolProps) { + this.poolProps = new Properties(); + } + this.poolProps.setProperty(key, value); + return this; + } +} diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/GlobalDSFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/GlobalDSFactory.java deleted file mode 100644 index 11d0befcc..000000000 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/GlobalDSFactory.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2023 looly(loolly@aliyun.com) - * Hutool is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * https://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - -package org.dromara.hutool.db.ds; - -import org.dromara.hutool.core.io.IoUtil; -import org.dromara.hutool.core.util.RuntimeUtil; -import org.dromara.hutool.log.LogUtil; - -/** - * 全局单例数据源工厂
- * 一般情况下,一个应用默认只使用一种数据库连接池,因此维护一个全局的数据源工厂类减少判断连接池类型造成的性能浪费 - * - * @author looly - * @since 4.0.2 - */ -public class GlobalDSFactory { - - private static volatile DSFactory factory; - private static final Object lock = new Object(); - - /* - * 设置在JVM关闭时关闭所有数据库连接 - */ - static { - // JVM关闭时关闭所有连接池 - RuntimeUtil.addShutdownHook(()->{ - if (null != factory) { - IoUtil.closeQuietly(factory); - LogUtil.debug("DataSource: [{}] closed.", factory.getDataSourceName()); - factory = null; - } - }); - } - - /** - * 获取默认的数据源工厂,读取默认数据库配置文件
- * 此处使用懒加载模式,在第一次调用此方法时才创建默认数据源工厂
- * 如果想自定义全局的数据源工厂,请在第一次调用此方法前调用{@link #set(DSFactory)} 方法自行定义 - * - * @return 当前使用的数据源工厂 - */ - public static DSFactory get() { - if (null == factory) { - synchronized (lock) { - if (null == factory) { - factory = DSUtil.createFactory(null); - } - } - } - return factory; - } - - /** - * 设置全局的数据源工厂
- * 在项目中存在多个连接池库的情况下,我们希望使用低优先级的库时使用此方法自定义之
- * 重新定义全局的数据源工厂此方法可在以下两种情况下调用: - * - *
-	 * 1. 在get方法调用前调用此方法来自定义全局的数据源工厂
-	 * 2. 替换已存在的全局数据源工厂,当已存在时会自动关闭
-	 * 
- * - * @param customDSFactory 自定义数据源工厂 - * @return 自定义的数据源工厂 - */ - public static DSFactory set(final DSFactory customDSFactory) { - synchronized (lock) { - if (null != factory) { - if (factory.equals(customDSFactory)) { - return factory;// 数据源工厂不变时返回原数据源工厂 - } - // 自定义数据源工厂前关闭之前的数据源 - IoUtil.closeQuietly(factory); - } - - LogUtil.debug("Custom use [{}] DataSource.", customDSFactory.getDataSourceName()); - factory = customDSFactory; - } - return factory; - } -} diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/bee/BeeDSFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/bee/BeeDSFactory.java index 3e0c56624..b78bf33f1 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/bee/BeeDSFactory.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/bee/BeeDSFactory.java @@ -14,55 +14,39 @@ package org.dromara.hutool.db.ds.bee; import cn.beecp.BeeDataSource; import cn.beecp.BeeDataSourceConfig; -import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.db.ds.AbstractDSFactory; -import org.dromara.hutool.db.ds.DSKeys; -import org.dromara.hutool.setting.Setting; +import org.dromara.hutool.core.map.MapUtil; +import org.dromara.hutool.db.ds.DSFactory; +import org.dromara.hutool.db.ds.DbConfig; +import org.dromara.hutool.setting.props.Props; import javax.sql.DataSource; +import java.util.Properties; /** * BeeCP数据源工厂类 * * @author Looly */ -public class BeeDSFactory extends AbstractDSFactory { +public class BeeDSFactory implements DSFactory { private static final long serialVersionUID = 1L; - /** - * 连接池名称:BeeCP - */ - public static final String DS_NAME = "BeeCP"; - - /** - * 构造,使用默认配置文件 - */ - public BeeDSFactory() { - this(null); - } - - /** - * 构造,使用自定义配置文件 - * - * @param setting 配置文件 - */ - public BeeDSFactory(final Setting setting) { - super(DS_NAME, BeeDataSource.class, setting); + @Override + public String getDataSourceName() { + return "BeeCP"; } @Override - protected DataSource createDataSource(final String jdbcUrl, final String driver, final String user, final String pass, final Setting poolSetting) { + public DataSource createDataSource(final DbConfig config) { + final BeeDataSourceConfig beeConfig = new BeeDataSourceConfig( + config.getDriver(), config.getUrl(), config.getUser(), config.getPass()); - final BeeDataSourceConfig beeConfig = new BeeDataSourceConfig(driver, jdbcUrl, user, pass); - poolSetting.toBean(beeConfig); + // 连接池和其它选项 + Props.of(config.getPoolProps()).toBean(beeConfig); - // remarks等特殊配置,since 5.3.8 - String connValue; - for (final String key : DSKeys.KEY_CONN_PROPS) { - connValue = poolSetting.getAndRemove(key); - if (StrUtil.isNotBlank(connValue)) { - beeConfig.addConnectProperty(key, connValue); - } + // 连接配置 + final Properties connProps = config.getConnProps(); + if(MapUtil.isNotEmpty(connProps)){ + connProps.forEach((key, value)->beeConfig.addConnectProperty(key.toString(), value)); } return new BeeDataSource(beeConfig); diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/c3p0/C3p0DSFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/c3p0/C3p0DSFactory.java index 77568cd4c..ae0de2bf1 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/c3p0/C3p0DSFactory.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/c3p0/C3p0DSFactory.java @@ -12,17 +12,16 @@ package org.dromara.hutool.db.ds.c3p0; -import org.dromara.hutool.core.map.MapUtil; -import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.db.DbRuntimeException; -import org.dromara.hutool.db.ds.AbstractDSFactory; -import org.dromara.hutool.db.ds.DSKeys; -import org.dromara.hutool.setting.Setting; -import org.dromara.hutool.setting.props.Props; import com.mchange.v2.c3p0.ComboPooledDataSource; +import org.dromara.hutool.core.map.MapUtil; +import org.dromara.hutool.db.DbRuntimeException; +import org.dromara.hutool.db.ds.DSFactory; +import org.dromara.hutool.db.ds.DbConfig; +import org.dromara.hutool.setting.props.Props; import javax.sql.DataSource; import java.beans.PropertyVetoException; +import java.util.Properties; /** * C3P0数据源工厂类 @@ -30,59 +29,36 @@ import java.beans.PropertyVetoException; * @author Looly * */ -public class C3p0DSFactory extends AbstractDSFactory { +public class C3p0DSFactory implements DSFactory { private static final long serialVersionUID = -6090788225842047281L; - /** - * 数据源名称:C3P0 - */ - public static final String DS_NAME = "C3P0"; - - /** - * 构造,使用默认配置 - */ - public C3p0DSFactory() { - this(null); - } - - /** - * 构造,使用自定义配置文件 - * - * @param setting 配置 - */ - public C3p0DSFactory(final Setting setting) { - super(DS_NAME, ComboPooledDataSource.class, setting); + @Override + public String getDataSourceName() { + return "C3P0"; } @Override - protected DataSource createDataSource(final String jdbcUrl, final String driver, final String user, final String pass, final Setting poolSetting) { + public DataSource createDataSource(final DbConfig config) { final ComboPooledDataSource ds = new ComboPooledDataSource(); - // remarks等特殊配置,since 5.3.8 - final Props connProps = new Props(); - String connValue; - for (final String key : DSKeys.KEY_CONN_PROPS) { - connValue = poolSetting.getAndRemove(key); - if(StrUtil.isNotBlank(connValue)){ - connProps.setProperty(key, connValue); - } + ds.setJdbcUrl(config.getUrl()); + try { + ds.setDriverClass(config.getDriver()); + } catch (final PropertyVetoException e) { + throw new DbRuntimeException(e); } + ds.setUser(config.getUser()); + ds.setPassword(config.getPass()); + + // 连接池和其它选项 + Props.of(config.getPoolProps()).toBean(ds); + + // 连接配置 + final Properties connProps = config.getConnProps(); if(MapUtil.isNotEmpty(connProps)){ ds.setProperties(connProps); } - ds.setJdbcUrl(jdbcUrl); - try { - ds.setDriverClass(driver); - } catch (final PropertyVetoException e) { - throw new DbRuntimeException(e); - } - ds.setUser(user); - ds.setPassword(pass); - - // 注入属性 - poolSetting.toBean(ds); - return ds; } } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/dbcp/DbcpDSFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/dbcp/DbcpDSFactory.java index 93f6c567f..53fcfe945 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/dbcp/DbcpDSFactory.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/dbcp/DbcpDSFactory.java @@ -12,13 +12,14 @@ package org.dromara.hutool.db.ds.dbcp; -import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.db.ds.AbstractDSFactory; -import org.dromara.hutool.db.ds.DSKeys; -import org.dromara.hutool.setting.Setting; import org.apache.commons.dbcp2.BasicDataSource; +import org.dromara.hutool.core.map.MapUtil; +import org.dromara.hutool.db.ds.DSFactory; +import org.dromara.hutool.db.ds.DbConfig; +import org.dromara.hutool.setting.props.Props; import javax.sql.DataSource; +import java.util.Properties; /** * DBCP2数据源工厂类 @@ -26,51 +27,32 @@ import javax.sql.DataSource; * @author Looly * */ -public class DbcpDSFactory extends AbstractDSFactory { - private static final long serialVersionUID = -9133501414334104548L; +public class DbcpDSFactory implements DSFactory { + private static final long serialVersionUID = 1L; - /** - * 数据源名称:commons-dbcp2 - */ - public static final String DS_NAME = "commons-dbcp2"; - - /** - * 构造,使用默认配置文件 - */ - public DbcpDSFactory() { - this(null); - } - - /** - * 构造,使用自定义配置文件 - * - * @param setting 配置 - */ - public DbcpDSFactory(final Setting setting) { - super(DS_NAME, BasicDataSource.class, setting); + @Override + public String getDataSourceName() { + return "commons-dbcp2"; } @Override - protected DataSource createDataSource(final String jdbcUrl, final String driver, final String user, final String pass, final Setting poolSetting) { + public DataSource createDataSource(final DbConfig config) { final BasicDataSource ds = new BasicDataSource(); - ds.setUrl(jdbcUrl); - ds.setDriverClassName(driver); - ds.setUsername(user); - ds.setPassword(pass); + ds.setUrl(config.getUrl()); + ds.setDriverClassName(config.getDriver()); + ds.setUsername(config.getUser()); + ds.setPassword(config.getPass()); - // remarks等特殊配置,since 5.3.8 - String connValue; - for (final String key : DSKeys.KEY_CONN_PROPS) { - connValue = poolSetting.getAndRemove(key); - if(StrUtil.isNotBlank(connValue)){ - ds.addConnectionProperty(key, connValue); - } + // 连接池和其它选项 + Props.of(config.getPoolProps()).toBean(ds); + + // 连接配置 + final Properties connProps = config.getConnProps(); + if(MapUtil.isNotEmpty(connProps)){ + connProps.forEach((key, value)->ds.addConnectionProperty(key.toString(), value.toString())); } - // 注入属性 - poolSetting.toBean(ds); - return ds; } } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/druid/DruidDSFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/druid/DruidDSFactory.java index 8b3f9a485..7e876a86e 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/druid/DruidDSFactory.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/druid/DruidDSFactory.java @@ -12,14 +12,15 @@ package org.dromara.hutool.db.ds.druid; -import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.db.ds.AbstractDSFactory; -import org.dromara.hutool.db.ds.DSKeys; -import org.dromara.hutool.setting.Setting; -import org.dromara.hutool.setting.props.Props; import com.alibaba.druid.pool.DruidDataSource; +import org.dromara.hutool.core.map.MapUtil; +import org.dromara.hutool.core.text.StrUtil; +import org.dromara.hutool.db.ds.DSFactory; +import org.dromara.hutool.db.ds.DbConfig; +import org.dromara.hutool.setting.props.Props; import javax.sql.DataSource; +import java.util.Properties; /** * Druid数据源工厂类 @@ -27,53 +28,33 @@ import javax.sql.DataSource; * @author Looly * */ -public class DruidDSFactory extends AbstractDSFactory { +public class DruidDSFactory implements DSFactory { private static final long serialVersionUID = 4680621702534433222L; - /** - * 数据源名称:Druid - */ - public static final String DS_NAME = "Druid"; - - /** - * 构造,使用默认配置文件 - */ - public DruidDSFactory() { - this(null); - } - - /** - * 构造,使用自定义配置文件 - * - * @param setting 配置 - */ - public DruidDSFactory(final Setting setting) { - super(DS_NAME, DruidDataSource.class, setting); + @Override + public String getDataSourceName() { + return "Druid"; } @Override - protected DataSource createDataSource(final String jdbcUrl, final String driver, final String user, final String pass, final Setting poolSetting) { + public DataSource createDataSource(final DbConfig config) { final DruidDataSource ds = new DruidDataSource(); // 基本信息 - ds.setUrl(jdbcUrl); - ds.setDriverClassName(driver); - ds.setUsername(user); - ds.setPassword(pass); + ds.setUrl(config.getUrl()); + ds.setDriverClassName(config.getDriver()); + ds.setUsername(config.getUser()); + ds.setPassword(config.getPass()); - // remarks等特殊配置,since 5.3.8 - // Druid中也可以通过 druid.connectProperties 属性设置 - String connValue; - for (final String key : DSKeys.KEY_CONN_PROPS) { - connValue = poolSetting.getAndRemove(key); - if(StrUtil.isNotBlank(connValue)){ - ds.addConnectionProperty(key, connValue); - } + // 连接配置 + final Properties connProps = config.getConnProps(); + if(MapUtil.isNotEmpty(connProps)){ + connProps.forEach((key, value)->ds.addConnectionProperty(key.toString(), value.toString())); } // Druid连接池配置信息,规范化属性名 final Props druidProps = new Props(); - poolSetting.forEach((key, value)-> druidProps.put(StrUtil.addPrefixIfNot(key, "druid."), value)); + config.getPoolProps().forEach((key, value)-> druidProps.set(StrUtil.addPrefixIfNot(key.toString(), "druid."), value)); ds.configFromPropeties(druidProps); //issue#I4ZKCW 某些非属性设置单独设置 diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/hikari/HikariDSFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/hikari/HikariDSFactory.java index 93999cf28..a57631e6e 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/hikari/HikariDSFactory.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/hikari/HikariDSFactory.java @@ -12,13 +12,11 @@ package org.dromara.hutool.db.ds.hikari; -import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.db.ds.AbstractDSFactory; -import org.dromara.hutool.db.ds.DSKeys; -import org.dromara.hutool.setting.Setting; -import org.dromara.hutool.setting.props.Props; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; +import org.dromara.hutool.db.ds.DSFactory; +import org.dromara.hutool.db.ds.DbConfig; +import org.dromara.hutool.setting.props.Props; import javax.sql.DataSource; @@ -28,59 +26,41 @@ import javax.sql.DataSource; * @author Looly * */ -public class HikariDSFactory extends AbstractDSFactory { +public class HikariDSFactory implements DSFactory { private static final long serialVersionUID = -8834744983614749401L; - /** - * 数据源名称:HikariCP - */ - public static final String DS_NAME = "HikariCP"; - - /** - * 构造,使用默认配置文件 - */ - public HikariDSFactory() { - this(null); - } - - /** - * 构造,使用自定义配置文件 - * - * @param setting 配置 - */ - public HikariDSFactory(final Setting setting) { - super(DS_NAME, HikariDataSource.class, setting); + @Override + public String getDataSourceName() { + return "HikariCP"; } @Override - protected DataSource createDataSource(final String jdbcUrl, final String driver, final String user, final String pass, final Setting poolSetting) { - // remarks等特殊配置,since 5.3.8 - final Props connProps = new Props(); - String connValue; - for (final String key : DSKeys.KEY_CONN_PROPS) { - connValue = poolSetting.getAndRemove(key); - if(StrUtil.isNotBlank(connValue)){ - connProps.setProperty(key, connValue); - } - } + public DataSource createDataSource(final DbConfig config) { + final Props props = new Props(); - final Props config = new Props(); - config.putAll(poolSetting); - - config.put("jdbcUrl", jdbcUrl); + // 基本信息 + props.put("jdbcUrl", config.getUrl()); + final String driver = config.getDriver(); if (null != driver) { - config.put("driverClassName", driver); + props.put("driverClassName", driver); } + final String user = config.getUser(); if (null != user) { - config.put("username", user); + props.put("username", user); } + final String pass = config.getPass(); if (null != pass) { - config.put("password", pass); + props.put("password", pass); } - final HikariConfig hikariConfig = new HikariConfig(config); - hikariConfig.setDataSourceProperties(connProps); + // 连接池信息 + props.putAll(config.getPoolProps()); + + final HikariConfig hikariConfig = new HikariConfig(props); + // 连接信息 + hikariConfig.setDataSourceProperties(config.getConnProps()); return new HikariDataSource(hikariConfig); } + } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/jndi/JndiDSFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/jndi/JndiDSFactory.java index 85bcaf951..b25adad5f 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/jndi/JndiDSFactory.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/jndi/JndiDSFactory.java @@ -14,9 +14,9 @@ package org.dromara.hutool.db.ds.jndi; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.db.DbRuntimeException; -import org.dromara.hutool.db.ds.AbstractDSFactory; +import org.dromara.hutool.db.ds.DSFactory; import org.dromara.hutool.db.ds.DSUtil; -import org.dromara.hutool.setting.Setting; +import org.dromara.hutool.db.ds.DbConfig; import javax.sql.DataSource; @@ -31,33 +31,17 @@ import javax.sql.DataSource; * @author Looly * */ -public class JndiDSFactory extends AbstractDSFactory { +public class JndiDSFactory implements DSFactory { private static final long serialVersionUID = 1573625812927370432L; - /** - * 数据源名称:JNDI DataSource - */ - public static final String DS_NAME = "JNDI DataSource"; - - /** - * 构造,使用默认配置文件 - */ - public JndiDSFactory() { - this(null); - } - - /** - * 构造,使用自定义配置文件 - * - * @param setting 配置 - */ - public JndiDSFactory(final Setting setting) { - super(DS_NAME, null, setting); + @Override + public String getDataSourceName() { + return "JNDI DataSource"; } @Override - protected DataSource createDataSource(final String jdbcUrl, final String driver, final String user, final String pass, final Setting poolSetting) { - final String jndiName = poolSetting.getStr("jndi"); + public DataSource createDataSource(final DbConfig config) { + final String jndiName = config.getPoolProps().getProperty("jndi"); if (StrUtil.isEmpty(jndiName)) { throw new DbRuntimeException("No setting name [jndi] for this group."); } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledConnection.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledConnection.java index 06c54d09f..ecb1d7afc 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledConnection.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledConnection.java @@ -15,6 +15,7 @@ package org.dromara.hutool.db.ds.pooled; import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.pool.Poolable; import org.dromara.hutool.db.DbRuntimeException; +import org.dromara.hutool.db.ds.DbConfig; import org.dromara.hutool.setting.props.Props; import java.sql.Connection; @@ -40,7 +41,7 @@ public class PooledConnection extends ConnectionWrapper implements Poolable connPool; /** @@ -38,12 +45,16 @@ public class PooledDataSource extends AbstractDataSource { * * @param config 数据库池配置 */ - public PooledDataSource(final PooledDbConfig config) { + public PooledDataSource(final DbConfig config) { + + final Props poolProps = Props.of(config.getPoolProps()); + this.maxWait = poolProps.getInt(KEY_MAX_WAIT, 6000); + final PartitionPoolConfig poolConfig = (PartitionPoolConfig) PartitionPoolConfig.of() .setPartitionSize(1) - .setMaxWait(config.getMaxWait()) - .setMinSize(config.getInitialSize()) - .setMaxSize(config.getMaxActive()); + .setMaxWait(this.maxWait) + .setMinSize(poolProps.getInt(KEY_INITIAL_SIZE, 0)) + .setMaxSize(poolProps.getInt(KEY_MAX_ACTIVE, 8)); this.connPool = new PartitionObjectPool<>(poolConfig, createConnFactory(config)); } @@ -78,7 +89,7 @@ public class PooledDataSource extends AbstractDataSource { * @param config 数据库配置 * @return {@link ObjectFactory} */ - private ObjectFactory createConnFactory(final PooledDbConfig config) { + private ObjectFactory createConnFactory(final DbConfig config) { return new ObjectFactory() { @Override public Connection create() { @@ -88,7 +99,8 @@ public class PooledDataSource extends AbstractDataSource { @Override public boolean validate(final Connection connection) { try { - return null != connection && connection.isValid((int) config.getMaxWait()); + return null != connection + && connection.isValid(maxWait); } catch (final SQLException e) { throw new DbRuntimeException(e); } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledDbConfig.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledDbConfig.java deleted file mode 100644 index 5fc280d24..000000000 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/pooled/PooledDbConfig.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2023 looly(loolly@aliyun.com) - * Hutool is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * https://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - -package org.dromara.hutool.db.ds.pooled; - -import org.dromara.hutool.db.ds.simple.DbConfig; - -/** - * 数据库配置 - * - * @author Looly - */ -public class PooledDbConfig extends DbConfig { - - private int initialSize; //初始连接数 - private int minIdle; //最小闲置连接数 - private int maxActive; //最大活跃连接数 - private long maxWait; //连接的超时等待 - - /** - * 构造 - */ - public PooledDbConfig() { - } - - /** - * 构造 - * - * @param url jdbc url - * @param user 用户名 - * @param pass 密码 - */ - public PooledDbConfig(final String url, final String user, final String pass) { - super(url, user, pass); - } - - /** - * 获取初始大小 - * - * @return 初始大小 - */ - public int getInitialSize() { - return initialSize; - } - - /** - * 设置初始大小 - * - * @param initialSize 初始大小 - */ - public void setInitialSize(final int initialSize) { - this.initialSize = initialSize; - } - - /** - * 获取最小闲置连接数 - * - * @return 最小闲置连接数 - */ - public int getMinIdle() { - return minIdle; - } - - /** - * 设置最小闲置连接数 - * - * @param minIdle 最小闲置连接数 - */ - public void setMinIdle(final int minIdle) { - this.minIdle = minIdle; - } - - /** - * 获取最大活跃连接数 - * - * @return 最大活跃连接数 - */ - public int getMaxActive() { - return maxActive; - } - - /** - * 设置最大活跃连接数 - * - * @param maxActive 最大活跃连接数 - */ - public void setMaxActive(final int maxActive) { - this.maxActive = maxActive; - } - - /** - * 获取连接的超时等待 - * - * @return 连接的超时等待 - */ - public long getMaxWait() { - return maxWait; - } - - /** - * 设置连接的超时等待 - * - * @param maxWait 连接的超时等待 - */ - public void setMaxWait(final long maxWait) { - this.maxWait = maxWait; - } -} diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/DbConfig.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/DbConfig.java deleted file mode 100644 index 3927dae30..000000000 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/DbConfig.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2023 looly(loolly@aliyun.com) - * Hutool is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * https://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - */ - -package org.dromara.hutool.db.ds.simple; - -import org.dromara.hutool.db.DbRuntimeException; -import org.dromara.hutool.db.driver.DriverUtil; - -import java.util.Properties; - -/** - * 数据库配置 - * - * @author Looly - */ -public class DbConfig { - - private String driver; //数据库驱动 - private String url; //jdbc url - private String user; //用户名 - private String pass; //密码 - - // 连接配置 - private Properties connProps; - - /** - * 构造 - */ - public DbConfig() { - } - - /** - * 构造 - * - * @param url jdbc url - * @param user 用户名 - * @param pass 密码 - */ - public DbConfig(final String url, final String user, final String pass) { - init(url, user, pass); - } - - /** - * 初始化 - * - * @param url jdbc url - * @param user 用户名 - * @param pass 密码 - */ - public void init(final String url, final String user, final String pass) { - this.url = url; - this.user = user; - this.pass = pass; - this.driver = DriverUtil.identifyDriver(url); - try { - Class.forName(this.driver); - } catch (final ClassNotFoundException e) { - throw new DbRuntimeException(e, "Get jdbc driver from [{}] error!", url); - } - } - - public String getDriver() { - return driver; - } - - public void setDriver(final String driver) { - this.driver = driver; - } - - public String getUrl() { - return url; - } - - public void setUrl(final String url) { - this.url = url; - } - - public String getUser() { - return user; - } - - public void setUser(final String user) { - this.user = user; - } - - public String getPass() { - return pass; - } - - public void setPass(final String pass) { - this.pass = pass; - } - - public Properties getConnProps() { - return connProps; - } - - public void setConnProps(final Properties connProps) { - this.connProps = connProps; - } - - public void addConnProps(final String key, final String value){ - if(null == this.connProps){ - this.connProps = new Properties(); - } - this.connProps.setProperty(key, value); - } -} diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/SimpleDSFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/SimpleDSFactory.java index 868238500..0fc89ccd4 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/SimpleDSFactory.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/SimpleDSFactory.java @@ -12,8 +12,8 @@ package org.dromara.hutool.db.ds.simple; -import org.dromara.hutool.db.ds.AbstractDSFactory; -import org.dromara.hutool.setting.Setting; +import org.dromara.hutool.db.ds.DSFactory; +import org.dromara.hutool.db.ds.DbConfig; import javax.sql.DataSource; @@ -23,36 +23,16 @@ import javax.sql.DataSource; * @author Looly * */ -public class SimpleDSFactory extends AbstractDSFactory { +public class SimpleDSFactory implements DSFactory { private static final long serialVersionUID = 4738029988261034743L; - /** - * 数据源名称:Hutool-Simple-DataSource - */ - public static final String DS_NAME = "Hutool-Simple-DataSource"; - - /** - * 构造,使用默认配置文件 - */ - public SimpleDSFactory() { - this(null); - } - - /** - * 构造,使用自定义配置文件 - * - * @param setting 配置 - */ - public SimpleDSFactory(final Setting setting) { - super(DS_NAME, SimpleDataSource.class, setting); + @Override + public String getDataSourceName() { + return "Hutool-Simple-DataSource"; } @Override - protected DataSource createDataSource(final String jdbcUrl, final String driver, final String user, final String pass, final Setting poolSetting) { - final DbConfig dbConfig = new DbConfig(jdbcUrl, user, pass); - dbConfig.setDriver(driver); - dbConfig.setConnProps(poolSetting.getProps(Setting.DEFAULT_GROUP)); - - return new SimpleDataSource(dbConfig); + public DataSource createDataSource(final DbConfig config) { + return new SimpleDataSource(config); } } diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/SimpleDataSource.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/SimpleDataSource.java index 012fd887b..fb8b7075c 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/SimpleDataSource.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/simple/SimpleDataSource.java @@ -13,6 +13,7 @@ package org.dromara.hutool.db.ds.simple; import org.dromara.hutool.core.map.MapUtil; +import org.dromara.hutool.db.ds.DbConfig; import org.dromara.hutool.setting.props.Props; import java.sql.Connection; diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/tomcat/TomcatDSFactory.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/tomcat/TomcatDSFactory.java index dc71126d2..93063af6b 100644 --- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/tomcat/TomcatDSFactory.java +++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/tomcat/TomcatDSFactory.java @@ -12,65 +12,40 @@ package org.dromara.hutool.db.ds.tomcat; -import org.dromara.hutool.core.text.StrUtil; -import org.dromara.hutool.db.ds.AbstractDSFactory; -import org.dromara.hutool.db.ds.DSKeys; -import org.dromara.hutool.setting.Setting; -import org.dromara.hutool.setting.props.Props; import org.apache.tomcat.jdbc.pool.DataSource; import org.apache.tomcat.jdbc.pool.PoolProperties; +import org.dromara.hutool.db.ds.DSFactory; +import org.dromara.hutool.db.ds.DbConfig; +import org.dromara.hutool.setting.props.Props; /** * Tomcat-Jdbc-Pool数据源工厂类 * * @author Looly - * */ -public class TomcatDSFactory extends AbstractDSFactory { +public class TomcatDSFactory implements DSFactory { private static final long serialVersionUID = 4925514193275150156L; - /** - * 数据源名称:Tomcat-Jdbc-Pool - */ - public static final String DS_NAME = "Tomcat-Jdbc-Pool"; - - /** - * 构造 - */ - public TomcatDSFactory() { - this(null); - } - - /** - * 构造,自定义配置 - * - * @param setting Setting数据库配置 - */ - public TomcatDSFactory(final Setting setting) { - super(DS_NAME, DataSource.class, setting); + @Override + public String getDataSourceName() { + return "Tomcat-Jdbc-Pool"; } @Override - protected javax.sql.DataSource createDataSource(final String jdbcUrl, final String driver, final String user, final String pass, final Setting poolSetting) { + public javax.sql.DataSource createDataSource(final DbConfig config) { final PoolProperties poolProps = new PoolProperties(); - poolProps.setUrl(jdbcUrl); - poolProps.setDriverClassName(driver); - poolProps.setUsername(user); - poolProps.setPassword(pass); - // remarks等特殊配置,since 5.3.8 - final Props connProps = new Props(); - String connValue; - for (final String key : DSKeys.KEY_CONN_PROPS) { - connValue = poolSetting.getAndRemove(key); - if(StrUtil.isNotBlank(connValue)){ - connProps.setProperty(key, connValue); - } - } - poolProps.setDbProperties(connProps); + // 基本配置 + poolProps.setUrl(config.getUrl()); + poolProps.setDriverClassName(config.getDriver()); + poolProps.setUsername(config.getUser()); + poolProps.setPassword(config.getPass()); + + // 连接配置 + poolProps.setDbProperties(config.getConnProps()); // 连接池相关参数 - poolSetting.toBean(poolProps); + Props.of(config.getPoolProps()).toBean(poolProps); return new DataSource(poolProps); } diff --git a/hutool-db/src/test/java/org/dromara/hutool/db/ds/DataSourceWrapperTest.java b/hutool-db/src/test/java/org/dromara/hutool/db/ds/DataSourceWrapperTest.java index edd2c0c9e..91f0cfa7a 100644 --- a/hutool-db/src/test/java/org/dromara/hutool/db/ds/DataSourceWrapperTest.java +++ b/hutool-db/src/test/java/org/dromara/hutool/db/ds/DataSourceWrapperTest.java @@ -12,7 +12,6 @@ package org.dromara.hutool.db.ds; -import org.dromara.hutool.db.ds.simple.DbConfig; import org.dromara.hutool.db.ds.simple.SimpleDataSource; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/hutool-setting/src/main/java/org/dromara/hutool/setting/Setting.java b/hutool-setting/src/main/java/org/dromara/hutool/setting/Setting.java index 52aec34e7..efbd0f149 100644 --- a/hutool-setting/src/main/java/org/dromara/hutool/setting/Setting.java +++ b/hutool-setting/src/main/java/org/dromara/hutool/setting/Setting.java @@ -383,20 +383,20 @@ public class Setting extends AbsSetting implements Map { } /** - * 转换为Properties对象,原分组变为前缀 + * 转换为{@link Props}对象,原分组变为前缀 * - * @return Properties对象 + * @return {@link Props}对象 */ - public Properties toProperties() { - final Properties properties = new Properties(); + public Props toProps() { + final Props props = new Props(); String group; for (final Entry> groupEntry : this.groupedMap.entrySet()) { group = groupEntry.getKey(); for (final Entry entry : groupEntry.getValue().entrySet()) { - properties.setProperty(StrUtil.isEmpty(group) ? entry.getKey() : group + CharUtil.DOT + entry.getKey(), entry.getValue()); + props.setProperty(StrUtil.isEmpty(group) ? entry.getKey() : group + CharUtil.DOT + entry.getKey(), entry.getValue()); } } - return properties; + return props; } /** diff --git a/hutool-setting/src/main/java/org/dromara/hutool/setting/props/Props.java b/hutool-setting/src/main/java/org/dromara/hutool/setting/props/Props.java index 97b0709de..7f43f105c 100644 --- a/hutool-setting/src/main/java/org/dromara/hutool/setting/props/Props.java +++ b/hutool-setting/src/main/java/org/dromara/hutool/setting/props/Props.java @@ -13,20 +13,19 @@ package org.dromara.hutool.setting.props; import org.dromara.hutool.core.bean.BeanUtil; -import org.dromara.hutool.core.io.file.FileUtil; -import org.dromara.hutool.core.io.IORuntimeException; -import org.dromara.hutool.core.io.IoUtil; -import org.dromara.hutool.core.io.resource.Resource; -import org.dromara.hutool.core.io.resource.ResourceUtil; -import org.dromara.hutool.core.io.resource.UrlResource; -import org.dromara.hutool.core.io.watch.SimpleWatcher; -import org.dromara.hutool.core.io.watch.WatchMonitor; -import org.dromara.hutool.core.io.watch.WatchUtil; -import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.func.LambdaInfo; import org.dromara.hutool.core.func.LambdaUtil; import org.dromara.hutool.core.func.SerFunction; import org.dromara.hutool.core.func.SerSupplier; +import org.dromara.hutool.core.io.IORuntimeException; +import org.dromara.hutool.core.io.IoUtil; +import org.dromara.hutool.core.io.file.FileUtil; +import org.dromara.hutool.core.io.resource.Resource; +import org.dromara.hutool.core.io.resource.ResourceUtil; +import org.dromara.hutool.core.io.watch.SimpleWatcher; +import org.dromara.hutool.core.io.watch.WatchMonitor; +import org.dromara.hutool.core.io.watch.WatchUtil; +import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.getter.TypeGetter; import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.reflect.ConstructorUtil; @@ -102,6 +101,16 @@ public final class Props extends Properties implements TypeGetter return new Props(resource, charset); } + /** + * {@link Properties}转为Props + * + * @param properties {@link Properties} + * @return Props + */ + public static Props of(final Properties properties) { + return new Props(properties); + } + // ----------------------------------------------------------------------- 构造方法 start /** @@ -272,6 +281,37 @@ public final class Props extends Properties implements TypeGetter return (String) value; } + /** + * 获取一个新的子属性,子属性键值对拥有公共前缀,以.分隔。 + *
+	 *     a.b
+	 *     a.c
+	 *     b.a
+	 * 
+ * 则调用getSubProps("a");得到 + *
+	 *     a.b
+	 *     a.c
+	 * 
+ * + * @param prefix 前缀,可以不以.结尾 + * @return 子属性 + */ + public Props getSubProps(final String prefix) { + final Props subProps = new Props(); + final String finalPrefix = StrUtil.addSuffixIfNot(prefix, StrUtil.DOT); + final int prefixLength = finalPrefix.length(); + + forEach((key, value) -> { + final String keyStr = key.toString(); + if (StrUtil.startWith(keyStr, finalPrefix)) { + subProps.set(StrUtil.subSuf(keyStr, prefixLength), value); + } + }); + + return subProps; + } + /** * 转换为标准的{@link Properties}对象 * @@ -325,7 +365,28 @@ public final class Props extends Properties implements TypeGetter */ public T toBean(final Class beanClass, final String prefix) { final T bean = ConstructorUtil.newInstanceIfPossible(beanClass); - return fillBean(bean, prefix); + return toBean(bean, prefix); + } + + /** + * 将配置文件转换为Bean,支持嵌套Bean
+ * 支持的表达式: + * + *
+	 * persion
+	 * persion.name
+	 * persons[3]
+	 * person.friends[5].name
+	 * ['person']['friends'][5]['name']
+	 * 
+ * + * @param Bean类型 + * @param bean Bean对象 + * @return Bean对象 + * @since 4.6.3 + */ + public T toBean(final T bean) { + return toBean(bean, null); } /** @@ -346,7 +407,7 @@ public final class Props extends Properties implements TypeGetter * @return Bean对象 * @since 4.6.3 */ - public T fillBean(final T bean, String prefix) { + public T toBean(final T bean, String prefix) { prefix = StrUtil.emptyIfNull(StrUtil.addSuffixIfNot(prefix, StrUtil.DOT)); String key; diff --git a/hutool-setting/src/test/java/org/dromara/hutool/setting/props/PropsTest.java b/hutool-setting/src/test/java/org/dromara/hutool/setting/props/PropsTest.java index e562eab85..d5f490ca7 100644 --- a/hutool-setting/src/test/java/org/dromara/hutool/setting/props/PropsTest.java +++ b/hutool-setting/src/test/java/org/dromara/hutool/setting/props/PropsTest.java @@ -88,7 +88,7 @@ public class PropsTest { Assertions.assertEquals(DateUtil.parse("2020-01-01"), systemConfig.getCreateTime()); Assertions.assertEquals(true, systemConfig.getIsInit()); Assertions.assertEquals("1", systemConfig.getStairPlan()); - Assertions.assertEquals(new Integer(2), systemConfig.getStageNum()); + Assertions.assertEquals(Integer.valueOf(2), systemConfig.getStageNum()); Assertions.assertEquals("3", systemConfig.getVersion()); } @@ -124,5 +124,16 @@ public class PropsTest { private Date nextStageTime;//当前阶段结束日期/下一阶段开始日期 } + @Test + void getSubTest() { + final Props props = new Props(); + props.set("a.b", "1"); + props.set("a.c", "2"); + props.set("b.a", "3"); + final Props subProps = props.getSubProps("a"); + Assertions.assertEquals(2, subProps.size()); + Assertions.assertEquals("1", subProps.getStr("b")); + Assertions.assertEquals("2", subProps.getStr("c")); + } }