sequence
The spring-boot-2.0.0-M1 version changes the default database connection pool from Tomcat JDBC Pool to HIkari. Here we will focus on the default hikari configuration
spring-configuration-metadata.json
Spring – the boot – autoconfigure – 2.0.0. M7. Jar! /META-INF/spring-configuration-metadata.json
{
"sourceType": "org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari"."name": "spring.datasource.hikari"."sourceMethod": "dataSource(org.springframework.boot.autoconfigure.jdbc.DataSourceProperties)"."type": "com.zaxxer.hikari.HikariDataSource"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.allow-pool-suspension"."type": "java.lang.Boolean"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.auto-commit"."type": "java.lang.Boolean"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.catalog"."type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.connection-init-sql"."type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.connection-test-query"."type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.connection-timeout"."type": "java.lang.Long"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.data-source-class-name"."type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.data-source-j-n-d-i"."type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.data-source-properties"."type": "java.util.Properties"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.driver-class-name"."type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.health-check-properties"."type": "java.util.Properties"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.health-check-registry"."type": "java.lang.Object"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.idle-timeout"."type": "java.lang.Long"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."deprecated": true."name": "spring.datasource.hikari.initialization-fail-fast", //initializationFailTimeout > 0
"type": "java.lang.Boolean"."deprecation": {}}, {"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.initialization-fail-timeout"."type": "java.lang.Long"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.isolate-internal-queries"."type": "java.lang.Boolean"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.jdbc-url"."type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."deprecated": true."name": "spring.datasource.hikari.jdbc4-connection-test", / / scrap"type": "java.lang.Boolean"."deprecation": {}}, {"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.leak-detection-threshold"."type": "java.lang.Long"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.login-timeout"// In HikariDataSource and PoolBase"type": "java.lang.Integer"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.max-lifetime"."type": "java.lang.Long"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.maximum-pool-size"."type": "java.lang.Integer"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.metric-registry"."type": "java.lang.Object"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.metrics-tracker-factory"."type": "com.zaxxer.hikari.metrics.MetricsTrackerFactory"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.minimum-idle"."type": "java.lang.Integer"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.password"."type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.pool-name"."type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.read-only"."type": "java.lang.Boolean"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.register-mbeans"."type": "java.lang.Boolean"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.scheduled-executor"."type": "java.util.concurrent.ScheduledExecutorService"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."deprecated": true."name": "spring.datasource.hikari.scheduled-executor-service"."type": "java.util.concurrent.ScheduledThreadPoolExecutor"."deprecation": {}}, {"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.schema"."type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.transaction-isolation", //transactionIsolationName
"type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.username"."type": "java.lang.String"
},
{
"sourceType": "com.zaxxer.hikari.HikariDataSource"."name": "spring.datasource.hikari.validation-timeout"."type": "java.lang.Long"
},
Copy the code
HikariConfig
HikariCP 2.7.6 – sources jar! /com/zaxxer/hikari/HikariConfig.java
@SuppressWarnings({"SameParameterValue"."unused"})
public class HikariConfig implements HikariConfigMXBean
{
private static final Logger LOGGER = LoggerFactory.getLogger(HikariConfig.class);
private static final char[] ID_CHARACTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); private static final long CONNECTION_TIMEOUT = SECONDS.toMillis(30); private static final long VALIDATION_TIMEOUT = SECONDS.toMillis(5); private static final long IDLE_TIMEOUT = MINUTES.toMillis(10); private static final long MAX_LIFETIME = MINUTES.toMillis(30); private static final int DEFAULT_POOL_SIZE = 10; / /... /** * Default constructor */ publicHikariConfig()
{
dataSourceProperties = new Properties();
healthCheckProperties = new Properties();
minIdle = -1;
maxPoolSize = -1;
maxLifetime = MAX_LIFETIME;
connectionTimeout = CONNECTION_TIMEOUT;
validationTimeout = VALIDATION_TIMEOUT;
idleTimeout = IDLE_TIMEOUT;
initializationFailTimeout = 1;
isAutoCommit = true;
String systemProp = System.getProperty("hikaricp.configurationFile");
if(systemProp ! = null) { loadProperties(systemProp); } } @Override public voidsetConnectionTimeout(long connectionTimeoutMs)
{
if (sealed) throw new IllegalStateException("The configuration of the pool is sealed once started. Use HikariConfigMXBean for runtime changes.");
if (connectionTimeoutMs == 0) {
this.connectionTimeout = Integer.MAX_VALUE;
}
else if (connectionTimeoutMs < 250) {
throw new IllegalArgumentException("connectionTimeout cannot be less than 250ms");
}
else {
this.connectionTimeout = connectionTimeoutMs;
}
}
@Override
public void setIdleTimeout(long idleTimeoutMs)
{
if (sealed) throw new IllegalStateException("The configuration of the pool is sealed once started. Use HikariConfigMXBean for runtime changes.");
if (idleTimeoutMs < 0) {
throw new IllegalArgumentException("idleTimeout cannot be negative");
}
this.idleTimeout = idleTimeoutMs;
}
@Override
public void setMaximumPoolSize(int maxPoolSize)
{
if (sealed) throw new IllegalStateException("The configuration of the pool is sealed once started. Use HikariConfigMXBean for runtime changes.");
if (maxPoolSize < 1) {
throw new IllegalArgumentException("maxPoolSize cannot be less than 1");
}
this.maxPoolSize = maxPoolSize;
}
@Override
public void setMinimumIdle(int minIdle)
{
if (sealed) throw new IllegalStateException("The configuration of the pool is sealed once started. Use HikariConfigMXBean for runtime changes.");
if (minIdle < 0) {
throw new IllegalArgumentException("minimumIdle cannot be negative");
}
this.minIdle = minIdle;
}
@Override
public void setValidationTimeout(long validationTimeoutMs)
{
if (sealed) throw new IllegalStateException("The configuration of the pool is sealed once started. Use HikariConfigMXBean for runtime changes.");
if (validationTimeoutMs < 250) {
throw new IllegalArgumentException("validationTimeout cannot be less than 250ms");
}
this.validationTimeout = validationTimeoutMs;
}
public void validate()
{
if (poolName == null) {
poolName = generatePoolName();
}
else if (isRegisterMbeans && poolName.contains(":")) {
throw new IllegalArgumentException("poolName cannot contain ':' when used with JMX");
}
// treat empty property as null
catalog = getNullIfEmpty(catalog);
connectionInitSql = getNullIfEmpty(connectionInitSql);
connectionTestQuery = getNullIfEmpty(connectionTestQuery);
transactionIsolationName = getNullIfEmpty(transactionIsolationName);
dataSourceClassName = getNullIfEmpty(dataSourceClassName);
dataSourceJndiName = getNullIfEmpty(dataSourceJndiName);
driverClassName = getNullIfEmpty(driverClassName);
jdbcUrl = getNullIfEmpty(jdbcUrl);
// Check Data Source Options
if(dataSource ! = null) {if(dataSourceClassName ! = null) { LOGGER.warn("{} - using dataSource and ignoring dataSourceClassName.", poolName); }}else if(dataSourceClassName ! = null) {if(driverClassName ! = null) { LOGGER.error("{} - cannot use driverClassName and dataSourceClassName together.", poolName);
// NOTE: This exception text is referenced by a Spring Boot FailureAnalyzer, it should not be
// changed without first notifying the Spring Boot developers.
throw new IllegalStateException("cannot use driverClassName and dataSourceClassName together.");
}
else if(jdbcUrl ! = null) { LOGGER.warn("{} - using dataSourceClassName and ignoring jdbcUrl.", poolName); }}else if(jdbcUrl ! = null || dataSourceJndiName ! = null) { // ok }else if(driverClassName ! = null) { LOGGER.error("{} - jdbcUrl is required with driverClassName.", poolName);
throw new IllegalArgumentException("jdbcUrl is required with driverClassName.");
}
else {
LOGGER.error("{} - dataSource or dataSourceClassName or jdbcUrl is required.", poolName);
throw new IllegalArgumentException("dataSource or dataSourceClassName or jdbcUrl is required.");
}
validateNumerics();
if (LOGGER.isDebugEnabled() || unitTest) {
logConfiguration();
}
}
private void validateNumerics()
{
if(maxLifetime ! = 0 && maxLifetime < SECONDS.toMillis(30)) { LOGGER.warn("{} - maxLifetime is less than 30000ms, setting to default {}ms.", poolName, MAX_LIFETIME);
maxLifetime = MAX_LIFETIME;
}
if (idleTimeout + SECONDS.toMillis(1) > maxLifetime && maxLifetime > 0) {
LOGGER.warn("{} - idleTimeout is close to or more than maxLifetime, disabling it.", poolName);
idleTimeout = 0;
}
if(idleTimeout ! = 0 && idleTimeout < SECONDS.toMillis(10)) { LOGGER.warn("{} - idleTimeout is less than 10000ms, setting to default {}ms.", poolName, IDLE_TIMEOUT);
idleTimeout = IDLE_TIMEOUT;
}
if(leakDetectionThreshold > 0 && ! unitTest) {if (leakDetectionThreshold < SECONDS.toMillis(2) || (leakDetectionThreshold > maxLifetime && maxLifetime > 0)) {
LOGGER.warn("{} - leakDetectionThreshold is less than 2000ms or more than maxLifetime, disabling it.", poolName); leakDetectionThreshold = 0; }}if (connectionTimeout < 250) {
LOGGER.warn("{} - connectionTimeout is less than 250ms, setting to {}ms.", poolName, CONNECTION_TIMEOUT);
connectionTimeout = CONNECTION_TIMEOUT;
}
if (validationTimeout < 250) {
LOGGER.warn("{} - validationTimeout is less than 250ms, setting to {}ms.", poolName, VALIDATION_TIMEOUT);
validationTimeout = VALIDATION_TIMEOUT;
}
if (maxPoolSize < 1) {
maxPoolSize = (minIdle <= 0) ? DEFAULT_POOL_SIZE : minIdle;
}
if(minIdle < 0 || minIdle > maxPoolSize) { minIdle = maxPoolSize; }}}Copy the code
You can see that parameter validation is added to the set method and that the validate method is called in the Configuration constructor and in the getConnection method
public HikariDataSource(HikariConfig configuration)
{
configuration.validate();
configuration.copyStateTo(this);
this.seal();
LOGGER.info("{} - Starting...", configuration.getPoolName());
pool = fastPathPool = new HikariPool(this);
LOGGER.info("{} - Start completed.", configuration.getPoolName());
}
/** {@inheritDoc} */
@Override
public Connection getConnection() throws SQLException
{
if (isClosed()) {
throw new SQLException("HikariDataSource " + this + " has been closed.");
}
if(fastPathPool ! = null) {return fastPathPool.getConnection();
}
// See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
HikariPool result = pool;
if (result == null) {
synchronized (this) {
result = pool;
if (result == null) {
validate();
LOGGER.info("{} - Starting...", getPoolName());
try {
pool = result = new HikariPool(this);
this.seal();
}
catch (PoolInitializationException pie) {
if (pie.getCause() instanceof SQLException) {
throw (SQLException) pie.getCause();
}
else {
throw pie;
}
}
LOGGER.info("{} - Start completed.", getPoolName()); }}}return result.getConnection();
}
Copy the code
Springboot’s Autoconfig uses BeanUtils reflection to initialize HikariDataSource using the default constructor, so validation relies on set and subsequent getConnection methods.
PoolBase.setLoginTimeout
HikariCP 2.7.6 – sources jar! /com/zaxxer/hikari/pool/PoolBase.java
/**
* Set the loginTimeout on the specified DataSource.
*
* @param dataSource the DataSource
*/
private void setLoginTimeout(final DataSource dataSource)
{
if(connectionTimeout ! = Integer.MAX_VALUE) { try { dataSource.setLoginTimeout(Math.max(1, (int) MILLISECONDS.toSeconds(500L + connectionTimeout))); } catch (Throwable e) { LOGGER.info("{} - Failed to set login timeout for data source. ({})", poolName, e.getMessage()); }}}Copy the code
Math.max(1, (int) MILLISECONDS. ToSeconds (500L + connectionTimeout))
summary
The default values of springboot HikariDataSource are as follows
name | Constructor default value | The default value after validate is configured | Validate the reset |
---|---|---|---|
minIdle | – 1 | 10 | MinIdle <0 or minIdle>maxPoolSize is reset to maxPoolSize |
maxPoolSize | – 1 | 10 | If maxPoolSize is less than 1, it is reset. When minIdle<=0 is reset to DEFAULT_POOL_SIZE, it is 10. If minIdle>0, reset the value to minIdle |
maxLifetime | MINUTES.toMillis(30) = 1800000 | 1800000 | If it is not 0 and less than 30 seconds, it is reset back to 30 minutes |
connectionTimeout | SECONDS.toMillis(30) = 30000 | 30000 | If less than 250 milliseconds, it is reset back to 30 seconds |
validationTimeout | SECONDS.toMillis(5) = 5000 | 5000 | If less than 250 milliseconds, it is reset back to 5 seconds |
loginTimeout | 10 | 30 | Math.max(1, (int) MILLISECONDS. ToSeconds (500L + connectionTimeout)), connectionTimeout+500ms |
idleTimeout | MINUTES.toMillis(10) = 600000 | 600000 | If idleTimeout+1 second >maxLifetime and maxLifetime>0, it will be reset to 0. If idleTimeout! If =0 and less than 10 seconds, it is reset to 10 seconds |
leakDetectionThreshold | 0 | 0 | If it is greater than 0 and not a unit test, then further judge: (leakDetectionThreshold < seconds.tomillis (2) or (leakDetectionThreshold > maxLifetime && maxLifetime > 0), will be reset to 0. That is, to take effect, the value must be greater than 0 and cannot be less than 2 seconds. When maxLifetime is greater than 0, the value cannot be greater than maxLifetime |
initializationFailTimeout | 1 | 1 | – |
isAutoCommit | true | true | – |
isReadOnly | false | fasle | – |
isAllowPoolSuspension | false | false | – |
isIsolateInternalQueries | false | false | – |
isRegisterMbeans | false | false | – |
sealed | false | true | This flag is true after the run is started, indicating that the changes are no longer being run |
poolName | null | HikariPool-1 | – |
catalog | null | null | – |
connectionInitSql | null | null | – |
connectionTestQuery | null | null | – |
dataSourceClassName | null | null | – |
schema | null | null | – |
transactionIsolationName | null | null | – |
dataSource | null | null | – |
dataSourceProperties | {} | {} | – |
threadFactory | null | null | – |
scheduledExecutor | null | null | – |
metricsTrackerFactory | null | null | – |
metricRegistry | null | null | – |
healthCheckRegistry | null | null | – |
healthCheckProperties | {} | {} | – |
doc
- Spring – the Boot – 2.0.0 – M1 – Release – the Notes