mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-23 17:59:03 +00:00
Merge pull request #50271 from vpavic
* improve-datasourcebuilder: Polish "Handle lazy connection proxy datasource in DataSourceBuilder" Handle lazy connection proxy datasource in DataSourceBuilder Closes gh-50271
This commit is contained in:
+1
-17
@@ -237,23 +237,7 @@ public final class DataSourceBuilder<T extends DataSource> {
|
||||
* @return a new {@link DataSource} builder
|
||||
*/
|
||||
public static DataSourceBuilder<?> derivedFrom(DataSource dataSource) {
|
||||
return new DataSourceBuilder<>(unwrap(dataSource));
|
||||
}
|
||||
|
||||
private static DataSource unwrap(DataSource dataSource) {
|
||||
try {
|
||||
while (dataSource.isWrapperFor(DataSource.class)) {
|
||||
DataSource unwrapped = dataSource.unwrap(DataSource.class);
|
||||
if (unwrapped == dataSource) {
|
||||
return unwrapped;
|
||||
}
|
||||
dataSource = unwrapped;
|
||||
}
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
// Try to continue with the existing, potentially still wrapped, DataSource
|
||||
}
|
||||
return dataSource;
|
||||
return new DataSourceBuilder<>(DataSourceUnwrapper.unwrapRoot(dataSource));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+43
@@ -93,6 +93,37 @@ public final class DataSourceUnwrapper {
|
||||
return unwrap(dataSource, target, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the root {@link DataSource} by recursively unwrapping all
|
||||
* {@link org.springframework.jdbc.datasource.DelegatingDataSource delegating}, proxy,
|
||||
* and {@link java.sql.Wrapper} layers until no further unwrapping is possible.
|
||||
* @param dataSource the datasource to unwrap
|
||||
* @return the root {@link DataSource}
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public static DataSource unwrapRoot(DataSource dataSource) {
|
||||
if (DELEGATING_DATA_SOURCE_PRESENT) {
|
||||
DataSource targetDataSource = DelegatingDataSourceUnwrapper.getTargetDataSource(dataSource);
|
||||
if (targetDataSource != null) {
|
||||
return unwrapRoot(targetDataSource);
|
||||
}
|
||||
}
|
||||
if (AopUtils.isAopProxy(dataSource)) {
|
||||
Object proxyTarget = AopProxyUtils.getSingletonTarget(dataSource);
|
||||
if (proxyTarget instanceof DataSource proxyDataSource) {
|
||||
return unwrapRoot(proxyDataSource);
|
||||
}
|
||||
}
|
||||
DataSource unwrapped = safeUnwrap(dataSource);
|
||||
if (unwrapped != null) {
|
||||
if (unwrapped == dataSource) {
|
||||
return unwrapped;
|
||||
}
|
||||
return unwrapRoot(unwrapped);
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
private static <S> @Nullable S safeUnwrap(Wrapper wrapper, Class<S> target) {
|
||||
try {
|
||||
if (target.isInterface() && wrapper.isWrapperFor(target)) {
|
||||
@@ -105,6 +136,18 @@ public final class DataSourceUnwrapper {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static @Nullable DataSource safeUnwrap(DataSource dataSource) {
|
||||
try {
|
||||
if (dataSource.isWrapperFor(DataSource.class)) {
|
||||
return dataSource.unwrap(DataSource.class);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// continue
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final class DelegatingDataSourceUnwrapper {
|
||||
|
||||
private static @Nullable DataSource getTargetDataSource(DataSource dataSource) {
|
||||
|
||||
+15
@@ -46,6 +46,7 @@ import org.postgresql.ds.PGSimpleDataSource;
|
||||
import org.vibur.dbcp.ViburDBCPDataSource;
|
||||
|
||||
import org.springframework.jdbc.datasource.AbstractDataSource;
|
||||
import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
|
||||
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
@@ -61,6 +62,7 @@ import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
* @author Stephane Nicoll
|
||||
* @author Fabio Grassi
|
||||
* @author Phillip Webb
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
class DataSourceBuilderTests {
|
||||
|
||||
@@ -427,6 +429,19 @@ class DataSourceBuilderTests {
|
||||
assertThat(built.getJdbcUrl()).isEqualTo("jdbc:h2:test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWhenDerivedFromLazyConnectionDataSourceProxy() {
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
dataSource.setUsername("test");
|
||||
dataSource.setPassword("secret");
|
||||
dataSource.setJdbcUrl("jdbc:h2:test");
|
||||
DataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(new LazyConnectionDataSourceProxy(dataSource));
|
||||
HikariDataSource built = (HikariDataSource) builder.username("test2").password("secret2").build();
|
||||
assertThat(built.getUsername()).isEqualTo("test2");
|
||||
assertThat(built.getPassword()).isEqualTo("secret2");
|
||||
assertThat(built.getJdbcUrl()).isEqualTo("jdbc:h2:test");
|
||||
}
|
||||
|
||||
@Test // gh-26644
|
||||
void buildWhenDerivedFromExistingDatabaseWithTypeChange() {
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
|
||||
+34
@@ -106,6 +106,40 @@ class DataSourceUnwrapperTests {
|
||||
.isSameAs(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void unwrapRootWithPlainDataSource() {
|
||||
DataSource dataSource = new HikariDataSource();
|
||||
assertThat(DataSourceUnwrapper.unwrapRoot(dataSource)).isSameAs(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void unwrapRootWithDelegate() {
|
||||
DataSource dataSource = new HikariDataSource();
|
||||
DataSource actual = wrapInDelegate(wrapInDelegate(dataSource));
|
||||
assertThat(DataSourceUnwrapper.unwrapRoot(actual)).isSameAs(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void unwrapRootWithProxy() {
|
||||
DataSource dataSource = new HikariDataSource();
|
||||
DataSource actual = wrapInProxy(wrapInProxy(dataSource));
|
||||
assertThat(DataSourceUnwrapper.unwrapRoot(actual)).isSameAs(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void unwrapRootWithLazyConnectionDataSource() {
|
||||
DataSource dataSource = new HikariDataSource();
|
||||
DataSource actual = new LazyConnectionDataSourceProxy(dataSource);
|
||||
assertThat(DataSourceUnwrapper.unwrapRoot(actual)).isSameAs(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void unwrapRootWithSeveralLevelOfWrapping() {
|
||||
DataSource dataSource = new HikariDataSource();
|
||||
DataSource actual = wrapInProxy(wrapInDelegate(wrapInDelegate(wrapInProxy(wrapInDelegate(dataSource)))));
|
||||
assertThat(DataSourceUnwrapper.unwrapRoot(actual)).isSameAs(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
void unwrappingIsNotAttemptedWhenTargetIsNotAnInterface() {
|
||||
DataSource dataSource = mock(DataSource.class);
|
||||
|
||||
+16
@@ -51,6 +51,7 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;
|
||||
import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration;
|
||||
@@ -90,6 +91,7 @@ import static org.assertj.core.api.Assertions.contentOf;
|
||||
* @author Moritz Halbritter
|
||||
* @author Phillip Webb
|
||||
* @author Ahmed Ashour
|
||||
* @author Vedran Pavic
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class LiquibaseAutoConfigurationTests {
|
||||
@@ -373,6 +375,20 @@ class LiquibaseAutoConfigurationTests {
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithDbChangelogMasterYamlResource
|
||||
void lazyConnectionDataSource() {
|
||||
String jdbcUrl = "jdbc:h2:mem:liquibase-" + UUID.randomUUID();
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))
|
||||
.withPropertyValues("spring.datasource.url:" + jdbcUrl, "spring.datasource.username:not-sa",
|
||||
"spring.datasource.connection-fetch:lazy", "spring.liquibase.user:sa")
|
||||
.run(assertLiquibase((liquibase) -> {
|
||||
SimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();
|
||||
assertThat(dataSource.getUrl()).isEqualTo(jdbcUrl);
|
||||
assertThat(dataSource.getUsername()).isEqualTo("sa");
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithDbChangelogMasterYamlResource
|
||||
void overrideUserWhenCustom() {
|
||||
|
||||
Reference in New Issue
Block a user