Merge branch '3.4.x'
Closes gh-45003
This commit is contained in:
@@ -33,6 +33,7 @@ import org.springframework.boot.jdbc.DataSourceBuilder;
|
|||||||
import org.springframework.boot.jdbc.DatabaseDriver;
|
import org.springframework.boot.jdbc.DatabaseDriver;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,10 +51,17 @@ abstract class DataSourceConfiguration {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static <T> T createDataSource(JdbcConnectionDetails connectionDetails, Class<? extends DataSource> type,
|
private static <T> T createDataSource(JdbcConnectionDetails connectionDetails, Class<? extends DataSource> type,
|
||||||
ClassLoader classLoader) {
|
ClassLoader classLoader) {
|
||||||
return (T) DataSourceBuilder.create(classLoader)
|
return createDataSource(connectionDetails, type, classLoader, true);
|
||||||
.type(type)
|
}
|
||||||
.driverClassName(connectionDetails.getDriverClassName())
|
|
||||||
.url(connectionDetails.getJdbcUrl())
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <T> T createDataSource(JdbcConnectionDetails connectionDetails, Class<? extends DataSource> type,
|
||||||
|
ClassLoader classLoader, boolean applyDriverClassName) {
|
||||||
|
DataSourceBuilder<? extends DataSource> builder = DataSourceBuilder.create(classLoader).type(type);
|
||||||
|
if (applyDriverClassName) {
|
||||||
|
builder.driverClassName(connectionDetails.getDriverClassName());
|
||||||
|
}
|
||||||
|
return (T) builder.url(connectionDetails.getJdbcUrl())
|
||||||
.username(connectionDetails.getUsername())
|
.username(connectionDetails.getUsername())
|
||||||
.password(connectionDetails.getPassword())
|
.password(connectionDetails.getPassword())
|
||||||
.build();
|
.build();
|
||||||
@@ -113,9 +121,11 @@ abstract class DataSourceConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties("spring.datasource.hikari")
|
@ConfigurationProperties("spring.datasource.hikari")
|
||||||
HikariDataSource dataSource(DataSourceProperties properties, JdbcConnectionDetails connectionDetails) {
|
HikariDataSource dataSource(DataSourceProperties properties, JdbcConnectionDetails connectionDetails,
|
||||||
|
Environment environment) {
|
||||||
|
String dataSourceClassName = environment.getProperty("spring.datasource.hikari.data-source-class-name");
|
||||||
HikariDataSource dataSource = createDataSource(connectionDetails, HikariDataSource.class,
|
HikariDataSource dataSource = createDataSource(connectionDetails, HikariDataSource.class,
|
||||||
properties.getClassLoader());
|
properties.getClassLoader(), dataSourceClassName == null);
|
||||||
if (StringUtils.hasText(properties.getName())) {
|
if (StringUtils.hasText(properties.getName())) {
|
||||||
dataSource.setPoolName(properties.getName());
|
dataSource.setPoolName(properties.getName());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,6 +171,15 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
|
|||||||
* @since 1.4.0
|
* @since 1.4.0
|
||||||
*/
|
*/
|
||||||
public String determineDriverClassName() {
|
public String determineDriverClassName() {
|
||||||
|
String driverClassName = findDriverClassName();
|
||||||
|
if (!StringUtils.hasText(driverClassName)) {
|
||||||
|
throw new DataSourceBeanCreationException("Failed to determine a suitable driver class", this,
|
||||||
|
this.embeddedDatabaseConnection);
|
||||||
|
}
|
||||||
|
return driverClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
String findDriverClassName() {
|
||||||
if (StringUtils.hasText(this.driverClassName)) {
|
if (StringUtils.hasText(this.driverClassName)) {
|
||||||
Assert.state(driverClassIsLoadable(), () -> "Cannot load driver class: " + this.driverClassName);
|
Assert.state(driverClassIsLoadable(), () -> "Cannot load driver class: " + this.driverClassName);
|
||||||
return this.driverClassName;
|
return this.driverClassName;
|
||||||
@@ -182,10 +191,6 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
|
|||||||
if (!StringUtils.hasText(driverClassName)) {
|
if (!StringUtils.hasText(driverClassName)) {
|
||||||
driverClassName = this.embeddedDatabaseConnection.getDriverClassName();
|
driverClassName = this.embeddedDatabaseConnection.getDriverClassName();
|
||||||
}
|
}
|
||||||
if (!StringUtils.hasText(driverClassName)) {
|
|
||||||
throw new DataSourceBeanCreationException("Failed to determine a suitable driver class", this,
|
|
||||||
this.embeddedDatabaseConnection);
|
|
||||||
}
|
|
||||||
return driverClassName;
|
return driverClassName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +282,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
|
|||||||
if (StringUtils.hasText(this.username)) {
|
if (StringUtils.hasText(this.username)) {
|
||||||
return this.username;
|
return this.username;
|
||||||
}
|
}
|
||||||
if (EmbeddedDatabaseConnection.isEmbedded(determineDriverClassName(), determineUrl())) {
|
if (EmbeddedDatabaseConnection.isEmbedded(findDriverClassName(), determineUrl())) {
|
||||||
return "sa";
|
return "sa";
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -305,7 +310,7 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
|
|||||||
if (StringUtils.hasText(this.password)) {
|
if (StringUtils.hasText(this.password)) {
|
||||||
return this.password;
|
return this.password;
|
||||||
}
|
}
|
||||||
if (EmbeddedDatabaseConnection.isEmbedded(determineDriverClassName(), determineUrl())) {
|
if (EmbeddedDatabaseConnection.isEmbedded(findDriverClassName(), determineUrl())) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class HikariJdbcConnectionDetailsBeanPostProcessor extends JdbcConnectionDetails
|
|||||||
dataSource.setPassword(connectionDetails.getPassword());
|
dataSource.setPassword(connectionDetails.getPassword());
|
||||||
String driverClassName = connectionDetails.getDriverClassName();
|
String driverClassName = connectionDetails.getDriverClassName();
|
||||||
if (driverClassName != null) {
|
if (driverClassName != null) {
|
||||||
dataSource.setDriverClassName(connectionDetails.getDriverClassName());
|
dataSource.setDriverClassName(driverClassName);
|
||||||
}
|
}
|
||||||
return dataSource;
|
return dataSource;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,6 +16,12 @@
|
|||||||
|
|
||||||
package org.springframework.boot.autoconfigure.jdbc;
|
package org.springframework.boot.autoconfigure.jdbc;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.SQLFeatureNotSupportedException;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
@@ -28,12 +34,15 @@ import org.springframework.boot.autoconfigure.AutoConfigurations;
|
|||||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||||
import org.springframework.boot.jdbc.HikariCheckpointRestoreLifecycle;
|
import org.springframework.boot.jdbc.HikariCheckpointRestoreLifecycle;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||||
import org.springframework.boot.testsupport.classpath.ClassPathOverrides;
|
import org.springframework.boot.testsupport.classpath.ClassPathOverrides;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.jdbc.datasource.DelegatingDataSource;
|
import org.springframework.jdbc.datasource.DelegatingDataSource;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link DataSourceAutoConfiguration} with Hikari.
|
* Tests for {@link DataSourceAutoConfiguration} with Hikari.
|
||||||
@@ -80,7 +89,33 @@ class HikariDataSourceConfigurationTests {
|
|||||||
HikariDataSource ds = context.getBean(HikariDataSource.class);
|
HikariDataSource ds = context.getBean(HikariDataSource.class);
|
||||||
assertThat(ds.getDataSourceProperties().getProperty("dataSourceClassName"))
|
assertThat(ds.getDataSourceProperties().getProperty("dataSourceClassName"))
|
||||||
.isEqualTo("org.h2.JDBCDataSource");
|
.isEqualTo("org.h2.JDBCDataSource");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("resource")
|
||||||
|
@ClassPathExclusions({ "h2-*.jar", "hsqldb-*.jar" })
|
||||||
|
void configureDataSourceClassNameWithNoEmbeddedDatabaseAvailable() {
|
||||||
|
this.contextRunner
|
||||||
|
.withPropertyValues("spring.datasource.url=jdbc:example//",
|
||||||
|
"spring.datasource.hikari.data-source-class-name=" + MockDataSource.class.getName())
|
||||||
|
.run((context) -> {
|
||||||
|
HikariDataSource ds = context.getBean(HikariDataSource.class);
|
||||||
|
assertThat(ds.getDataSourceClassName()).isEqualTo(MockDataSource.class.getName());
|
||||||
|
assertThatNoException().isThrownBy(() -> ds.getConnection().close());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("resource")
|
||||||
|
void configureDataSourceClassNameToOverrideUseOfAnEmbeddedDatabase() {
|
||||||
|
this.contextRunner
|
||||||
|
.withPropertyValues("spring.datasource.url=jdbc:example//",
|
||||||
|
"spring.datasource.hikari.data-source-class-name=" + MockDataSource.class.getName())
|
||||||
|
.run((context) -> {
|
||||||
|
HikariDataSource ds = context.getBean(HikariDataSource.class);
|
||||||
|
assertThat(ds.getDataSourceClassName()).isEqualTo(MockDataSource.class.getName());
|
||||||
|
assertThatNoException().isThrownBy(() -> ds.getConnection().close());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,4 +236,51 @@ class HikariDataSourceConfigurationTests {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class MockDataSource implements DataSource {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Connection getConnection() throws SQLException {
|
||||||
|
return mock(Connection.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Connection getConnection(String username, String password) throws SQLException {
|
||||||
|
return getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrintWriter getLogWriter() throws SQLException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLogWriter(PrintWriter out) throws SQLException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLoginTimeout(int seconds) throws SQLException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLoginTimeout() throws SQLException {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user