Generalize database initialization detection and include R2DBC

Closes gh-25818
pull/25829/head
Andy Wilkinson 4 years ago
parent 22b02a6c6f
commit 9b65409e23

@ -50,7 +50,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializationDependencyConfigurer;
import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@ -88,7 +88,7 @@ import org.springframework.util.StringUtils;
@ConditionalOnProperty(prefix = "spring.flyway", name = "enabled", matchIfMissing = true)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, JdbcTemplateAutoConfiguration.class,
HibernateJpaAutoConfiguration.class })
@Import(DataSourceInitializationDependencyConfigurer.class)
@Import(DatabaseInitializationDependencyConfigurer.class)
public class FlywayAutoConfiguration {
@Bean

@ -19,18 +19,18 @@ package org.springframework.boot.autoconfigure.flyway;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.jdbc.init.dependency.AbstractBeansOfTypeDataSourceInitializerDetector;
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector;
import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;
import org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;
/**
* A {@link DataSourceInitializerDetector} for {@link FlywayMigrationInitializer}.
* A {@link DatabaseInitializerDetector} for {@link FlywayMigrationInitializer}.
*
* @author Andy Wilkinson
*/
class FlywayMigrationInitializerDataSourceInitializerDetector extends AbstractBeansOfTypeDataSourceInitializerDetector {
class FlywayMigrationInitializerDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {
@Override
protected Set<Class<?>> getDataSourceInitializerBeanTypes() {
protected Set<Class<?>> getDatabaseInitializerBeanTypes() {
return Collections.singleton(FlywayMigrationInitializer.class);
}

@ -42,8 +42,8 @@ import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jdbc.DataSourceInitializationMode;
import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializationDependencyConfigurer;
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.DependsOn;
@ -85,7 +85,7 @@ class DataSourceInitializationConfiguration {
// Fully-qualified to work around javac bug in JDK 1.8
@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)
@org.springframework.context.annotation.Conditional(DifferentCredentialsCondition.class)
@org.springframework.context.annotation.Import(DataSourceInitializationDependencyConfigurer.class)
@org.springframework.context.annotation.Import(DatabaseInitializationDependencyConfigurer.class)
@ConditionalOnSingleCandidate(DataSource.class)
@ConditionalOnMissingBean(DataSourceScriptDatabaseInitializer.class)
static class InitializationSpecificCredentialsDataSourceInitializationConfiguration {
@ -141,7 +141,7 @@ class DataSourceInitializationConfiguration {
// Fully-qualified to work around javac bug in JDK 1.8
@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)
@org.springframework.context.annotation.Import(DataSourceInitializationDependencyConfigurer.class)
@org.springframework.context.annotation.Import(DatabaseInitializationDependencyConfigurer.class)
@org.springframework.context.annotation.Conditional(DataSourceInitializationCondition.class)
@ConditionalOnSingleCandidate(DataSource.class)
@ConditionalOnMissingBean(DataSourceScriptDatabaseInitializer.class)

@ -19,7 +19,7 @@ package org.springframework.boot.autoconfigure.jdbc;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostProcessor;
import org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitializationDetector;
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;
import org.springframework.jdbc.core.JdbcOperations;
/**
@ -33,7 +33,7 @@ import org.springframework.jdbc.core.JdbcOperations;
* @author Andrii Hrytsiuk
* @since 2.0.4
* @see BeanDefinition#setDependsOn(String[])
* @deprecated since 2.5.0 in favor of {@link DependsOnDataSourceInitializationDetector}
* @deprecated since 2.5.0 in favor of {@link DependsOnDatabaseInitializationDetector}
*/
@Deprecated
public class JdbcOperationsDependsOnPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {

@ -23,7 +23,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializationDependencyConfigurer;
import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcTemplate;
@ -44,7 +44,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
@Import({ DataSourceInitializationDependencyConfigurer.class, JdbcTemplateConfiguration.class,
@Import({ DatabaseInitializationDependencyConfigurer.class, JdbcTemplateConfiguration.class,
NamedParameterJdbcTemplateConfiguration.class })
public class JdbcTemplateAutoConfiguration {

@ -19,7 +19,7 @@ package org.springframework.boot.autoconfigure.jdbc;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostProcessor;
import org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitializationDetector;
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
@ -31,7 +31,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
* @author Andrii Hrytsiuk
* @since 2.1.4
* @see BeanDefinition#setDependsOn(String[])
* @deprecated since 2.5.0 in favor of {@link DependsOnDataSourceInitializationDetector}
* @deprecated since 2.5.0 in favor of {@link DependsOnDatabaseInitializationDetector}
*/
@Deprecated
public class NamedParameterJdbcOperationsDependsOnPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {

@ -21,7 +21,7 @@ import org.jooq.DSLContext;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostProcessor;
import org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitializationDetector;
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;
/**
* {@link BeanFactoryPostProcessor} that can be used to dynamically declare that all
@ -30,7 +30,7 @@ import org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitiali
* @author Eddú Meléndez
* @since 2.3.9
* @see BeanDefinition#setDependsOn(String[])
* @deprecated since 2.5.0 in favor of {@link DependsOnDataSourceInitializationDetector}
* @deprecated since 2.5.0 in favor of {@link DependsOnDatabaseInitializationDetector}
*/
@Deprecated
public class DslContextDependsOnPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {

@ -34,7 +34,7 @@ import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfigurati
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializationDependencyConfigurer;
import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@ -63,7 +63,7 @@ import org.springframework.util.StringUtils;
@ConditionalOnProperty(prefix = "spring.liquibase", name = "enabled", matchIfMissing = true)
@Conditional(LiquibaseDataSourceCondition.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
@Import(DataSourceInitializationDependencyConfigurer.class)
@Import(DatabaseInitializationDependencyConfigurer.class)
public class LiquibaseAutoConfiguration {
@Bean

@ -22,19 +22,16 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializationDependencyConfigurer;
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.util.StringUtils;
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(AbstractScriptDatabaseInitializer.class)
@ConditionalOnSingleCandidate(DataSource.class)
@Import(DataSourceInitializationDependencyConfigurer.class)
class DataSourceInitializationConfiguration {
@Bean

@ -24,6 +24,7 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -38,7 +39,8 @@ import org.springframework.context.annotation.Import;
@ConditionalOnProperty(prefix = "spring.sql.init", name = "enabled", matchIfMissing = true)
@AutoConfigureAfter({ R2dbcAutoConfiguration.class, DataSourceAutoConfiguration.class })
@EnableConfigurationProperties(SqlInitializationProperties.class)
@Import({ R2dbcInitializationConfiguration.class, DataSourceInitializationConfiguration.class })
@Import({ DatabaseInitializationDependencyConfigurer.class, R2dbcInitializationConfiguration.class,
DataSourceInitializationConfiguration.class })
public class SqlInitializationAutoConfiguration {
}

@ -173,5 +173,5 @@ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityPr
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider
# DataSource initializer detectors
org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector=\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializerDataSourceInitializerDetector
org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializerDatabaseInitializerDetector

@ -44,7 +44,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
import org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitialization;
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitialization;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@ -283,7 +283,7 @@ class DataSourceAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
@DependsOnDataSourceInitialization
@DependsOnDatabaseInitialization
static class TestInitializedDataSourceConfiguration {
private boolean called;

@ -59,10 +59,10 @@ import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfigurat
import org.springframework.boot.autoconfigure.orm.jpa.mapping.NonAnnotatedEntity;
import org.springframework.boot.autoconfigure.orm.jpa.test.City;
import org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration;
import org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitialization;
import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy;
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitialization;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.context.ApplicationEvent;
@ -501,7 +501,7 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
@DependsOnDataSourceInitialization
@DependsOnDatabaseInitialization
static class TestInitializedJpaConfiguration {
private boolean called;

@ -24,6 +24,7 @@ import javax.sql.DataSource;
import io.r2dbc.spi.ConnectionFactory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration;
@ -31,6 +32,7 @@ import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;
import org.springframework.boot.r2dbc.init.R2dbcScriptDatabaseInitializer;
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;
import org.springframework.boot.sql.init.DatabaseInitializationSettings;
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitialization;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -98,6 +100,28 @@ public class SqlInitializationAutoConfigurationTests {
.hasBean("customInitializer"));
}
@Test
void whenBeanIsAnnotatedAsDependingOnDatabaseInitializationThenItDependsOnR2dbcScriptDatabaseInitializer() {
this.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))
.withUserConfiguration(DependsOnInitializedDatabaseConfiguration.class).run((context) -> {
BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition(
"sqlInitializationAutoConfigurationTests.DependsOnInitializedDatabaseConfiguration");
assertThat(beanDefinition.getDependsOn())
.containsExactlyInAnyOrder("r2dbcScriptDatabaseInitializer");
});
}
@Test
void whenBeanIsAnnotatedAsDependingOnDatabaseInitializationThenItDependsOnDataSourceScriptDatabaseInitializer() {
this.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))
.withUserConfiguration(DependsOnInitializedDatabaseConfiguration.class).run((context) -> {
BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition(
"sqlInitializationAutoConfigurationTests.DependsOnInitializedDatabaseConfiguration");
assertThat(beanDefinition.getDependsOn())
.containsExactlyInAnyOrder("dataSourceScriptDatabaseInitializer");
});
}
@Configuration(proxyBeanMethods = false)
static class DatabaseInitializerConfiguration {
@ -116,4 +140,14 @@ public class SqlInitializationAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
@DependsOnDatabaseInitialization
static class DependsOnInitializedDatabaseConfiguration {
DependsOnInitializedDatabaseConfiguration() {
}
}
}

@ -2163,33 +2163,33 @@ See {spring-boot-autoconfigure-module-code}/liquibase/LiquibaseProperties.java[`
[[howto-initialize-a-database-configuring-dependencies]]
=== Depend Upon an Initialized DataSource
DataSource initialization is performed while the application is starting up as part of application context refresh.
To allow an initialized database to be accessed during startup, beans that act as DataSource initializers and beans that
require that DataSource to have been initialized are detected automatically.
Beans whose initialization depends upon the DataSource having been initialized are configured to depend upon those that initialize it.
If, during startup, your application tries to access the database and it has not been initialized, you can configure additional detection of beans that initialize the DataSource and require the DataSource to have been initialized.
=== Depend Upon an Initialized Database
Database initialization is performed while the application is starting up as part of application context refresh.
To allow an initialized database to be accessed during startup, beans that act as database initializers and beans that require that database to have been initialized are detected automatically.
Beans whose initialization depends upon the database having been initialized are configured to depend upon those that initialize it.
If, during startup, your application tries to access the database and it has not been initialized, you can configure additional detection of beans that initialize the database and require the database to have been initialized.
[[howto-initialize-a-database-configuring-dependencies-initializer-detection]]
==== Detect a DataSource Initializer
Spring Boot will automatically detect beans of the following types that initialize a `DataSource`:
==== Detect a Database Initializer
Spring Boot will automatically detect beans of the following types that initialize an SQL database:
- `DataSourceInitialization`
- `DataSourceScriptDatabaseInitializer`
- `EntityManagerFactory`
- `Flyway`
- `FlywayMigrationInitializer`
- `R2dbcScriptDatabaseInitializer`
- `SpringLiquibase`
If you are using a third-party starter for a DataSource initialization library, it may provide a detector such that beans of other types are also detected automatically.
To have other beans be detected, register an implementation of `DataSourceInitializerDetector` in `META-INF/spring-factories`.
If you are using a third-party starter for a database initialization library, it may provide a detector such that beans of other types are also detected automatically.
To have other beans be detected, register an implementation of `DatabaseInitializerDetector` in `META-INF/spring-factories`.
[[howto-initialize-a-database-configuring-dependencies-depends-on-initialization-detection]]
==== Detect a Bean That Depends On DataSource Initialization
Spring Boot will automatically detect beans of the following types that depends upon `DataSource` initialization:
==== Detect a Bean That Depends On Database Initialization
Spring Boot will automatically detect beans of the following types that depends upon database initialization:
- `AbstractEntityManagerFactoryBean` (unless configprop:spring.jpa.defer-datasource-initialization[] is set to `true`)
- `DSLContext` (jOOQ)
@ -2198,8 +2198,8 @@ Spring Boot will automatically detect beans of the following types that depends
- `NamedParameterJdbcOperations`
If you are using a third-party starter data access library, it may provide a detector such that beans of other types are also detected automatically.
To have other beans be detected, register an implementation of `DependsOnDataSourceInitializationDetector` in `META-INF/spring-factories`.
Alternatively, annotate the bean's class or its `@Bean` method with `@DependsOnDataSourceInitializationDetector`.
To have other beans be detected, register an implementation of `DependsOnDatabaseInitializationDetector` in `META-INF/spring-factories`.
Alternatively, annotate the bean's class or its `@Bean` method with `@DependsOnDatabaseInitialization`.

@ -21,18 +21,18 @@ import java.util.Set;
import org.flywaydb.core.Flyway;
import org.springframework.boot.jdbc.init.dependency.AbstractBeansOfTypeDataSourceInitializerDetector;
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector;
import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;
import org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;
/**
* A {@link DataSourceInitializerDetector} for {@link Flyway}.
* A {@link DatabaseInitializerDetector} for {@link Flyway}.
*
* @author Andy Wilkinson
*/
class FlywayDataSourceInitializerDetector extends AbstractBeansOfTypeDataSourceInitializerDetector {
class FlywayDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {
@Override
protected Set<Class<?>> getDataSourceInitializerBeanTypes() {
protected Set<Class<?>> getDatabaseInitializerBeanTypes() {
return Collections.singleton(Flyway.class);
}

@ -20,21 +20,21 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.springframework.boot.jdbc.init.dependency.AbstractBeansOfTypeDependsOnDataSourceInitializationDetector;
import org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitializationDetector;
import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector;
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
* {@link DependsOnDataSourceInitializationDetector} for Spring Framework's JDBC support.
* {@link DependsOnDatabaseInitializationDetector} for Spring Framework's JDBC support.
*
* @author Andy Wilkinson
*/
class SpringJdbcDependsOnDataSourceInitializationDetector
extends AbstractBeansOfTypeDependsOnDataSourceInitializationDetector {
class SpringJdbcDependsOnDatabaseInitializationDetector
extends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {
@Override
protected Set<Class<?>> getDependsOnDataSourceInitializationBeanTypes() {
protected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {
return new HashSet<>(Arrays.asList(JdbcOperations.class, NamedParameterJdbcOperations.class));
}

@ -19,19 +19,18 @@ package org.springframework.boot.jdbc.init;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.jdbc.init.dependency.AbstractBeansOfTypeDataSourceInitializerDetector;
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector;
import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;
import org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;
/**
* A {@link DataSourceInitializerDetector} for
* {@link DataSourceScriptDatabaseInitializer}.
* A {@link DatabaseInitializerDetector} for {@link DataSourceScriptDatabaseInitializer}.
*
* @author Andy Wilkinson
*/
class DataSourceScriptDatabaseInitializerDetector extends AbstractBeansOfTypeDataSourceInitializerDetector {
class DataSourceScriptDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {
@Override
protected Set<Class<?>> getDataSourceInitializerBeanTypes() {
protected Set<Class<?>> getDatabaseInitializerBeanTypes() {
return Collections.singleton(DataSourceScriptDatabaseInitializer.class);
}

@ -21,19 +21,18 @@ import java.util.Set;
import org.jooq.DSLContext;
import org.springframework.boot.jdbc.init.dependency.AbstractBeansOfTypeDependsOnDataSourceInitializationDetector;
import org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitializationDetector;
import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector;
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;
/**
* {@link DependsOnDataSourceInitializationDetector} for jOOQ.
* {@link DependsOnDatabaseInitializationDetector} for jOOQ.
*
* @author Andy Wilkinson
*/
class JooqDependsOnDataSourceInitializationDetector
extends AbstractBeansOfTypeDependsOnDataSourceInitializationDetector {
class JooqDependsOnDatabaseInitializationDetector extends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {
@Override
protected Set<Class<?>> getDependsOnDataSourceInitializationBeanTypes() {
protected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {
return Collections.singleton(DSLContext.class);
}

@ -21,18 +21,18 @@ import java.util.Set;
import liquibase.integration.spring.SpringLiquibase;
import org.springframework.boot.jdbc.init.dependency.AbstractBeansOfTypeDataSourceInitializerDetector;
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector;
import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;
import org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;
/**
* A {@link DataSourceInitializerDetector} for Liquibase.
* A {@link DatabaseInitializerDetector} for Liquibase.
*
* @author Andy Wilkinson
*/
class LiquibaseDataSourceInitializerDetector extends AbstractBeansOfTypeDataSourceInitializerDetector {
class LiquibaseDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {
@Override
protected Set<Class<?>> getDataSourceInitializerBeanTypes() {
protected Set<Class<?>> getDatabaseInitializerBeanTypes() {
return Collections.singleton(SpringLiquibase.class);
}

@ -25,26 +25,26 @@ import javax.persistence.EntityManagerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.jdbc.init.dependency.AbstractBeansOfTypeDataSourceInitializerDetector;
import org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector;
import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;
import org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
/**
* A {@link DataSourceInitializerDetector} for JPA.
* A {@link DatabaseInitializerDetector} for JPA.
*
* @author Andy Wilkinson
*/
class JpaDataSourceInitializerDetector extends AbstractBeansOfTypeDataSourceInitializerDetector {
class JpaDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {
private final Environment environment;
JpaDataSourceInitializerDetector(Environment environment) {
JpaDatabaseInitializerDetector(Environment environment) {
this.environment = environment;
}
@Override
protected Set<Class<?>> getDataSourceInitializerBeanTypes() {
protected Set<Class<?>> getDatabaseInitializerBeanTypes() {
boolean deferred = this.environment.getProperty("spring.jpa.defer-datasource-initialization", boolean.class,
false);
return deferred ? Collections.singleton(EntityManagerFactory.class) : Collections.emptySet();
@ -63,8 +63,8 @@ class JpaDataSourceInitializerDetector extends AbstractBeansOfTypeDataSourceInit
while (iterator.hasNext()) {
String initializerName = iterator.next();
BeanDefinition initializerDefinition = beanFactory.getBeanDefinition(initializerName);
if (JpaDataSourceInitializerDetector.class.getName()
.equals(initializerDefinition.getAttribute(DataSourceInitializerDetector.class.getName()))) {
if (JpaDatabaseInitializerDetector.class.getName()
.equals(initializerDefinition.getAttribute(DatabaseInitializerDetector.class.getName()))) {
iterator.remove();
jpaInitializers.add(initializerName);
}

@ -23,27 +23,26 @@ import java.util.Set;
import javax.persistence.EntityManagerFactory;
import org.springframework.boot.jdbc.init.dependency.AbstractBeansOfTypeDependsOnDataSourceInitializationDetector;
import org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitializationDetector;
import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector;
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;
import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
/**
* {@link DependsOnDataSourceInitializationDetector} for JPA.
* {@link DependsOnDatabaseInitializationDetector} for JPA.
*
* @author Andy Wilkinson
*/
class JpaDependsOnDataSourceInitializationDetector
extends AbstractBeansOfTypeDependsOnDataSourceInitializationDetector {
class JpaDependsOnDatabaseInitializationDetector extends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {
private final Environment environment;
JpaDependsOnDataSourceInitializationDetector(Environment environment) {
JpaDependsOnDatabaseInitializationDetector(Environment environment) {
this.environment = environment;
}
@Override
protected Set<Class<?>> getDependsOnDataSourceInitializationBeanTypes() {
protected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {
boolean postpone = this.environment.getProperty("spring.jpa.defer-datasource-initialization", boolean.class,
false);
return postpone ? Collections.emptySet()

@ -0,0 +1,37 @@
/*
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.r2dbc.init;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;
import org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;
/**
* A {@link DatabaseInitializerDetector} for {@link R2dbcScriptDatabaseInitializer}.
*
* @author Andy Wilkinson
*/
class R2dbcScriptDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {
@Override
protected Set<Class<?>> getDatabaseInitializerBeanTypes() {
return Collections.singleton(R2dbcScriptDatabaseInitializer.class);
}
}

@ -14,34 +14,32 @@
* limitations under the License.
*/
package org.springframework.boot.jdbc.init.dependency;
package org.springframework.boot.sql.init.dependency;
import java.util.Collections;
import java.util.Set;
import javax.sql.DataSource;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* Base class for {@link DataSourceInitializerDetector DataSourceInitializerDetectors}
* that detect {@link DataSource} beans by type.
* Base class for {@link DatabaseInitializerDetector DatabaseInitializerDetectors} that
* detect database initializer beans by type.
*
* @author Andy Wilkinson
* @since 2.5.0
*/
public abstract class AbstractBeansOfTypeDataSourceInitializerDetector implements DataSourceInitializerDetector {
public abstract class AbstractBeansOfTypeDatabaseInitializerDetector implements DatabaseInitializerDetector {
/**
* Returns the bean types that should be detected as being data source initializers.
* @return the data source initializer bean types
* Returns the bean types that should be detected as being database initializers.
* @return the database initializer bean types
*/
protected abstract Set<Class<?>> getDataSourceInitializerBeanTypes();
protected abstract Set<Class<?>> getDatabaseInitializerBeanTypes();
@Override
public Set<String> detect(ConfigurableListableBeanFactory beanFactory) {
try {
Set<Class<?>> types = getDataSourceInitializerBeanTypes();
Set<Class<?>> types = getDatabaseInitializerBeanTypes();
return new BeansOfTypeDetector(types).detect(beanFactory);
}
catch (Throwable ex) {

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.jdbc.init.dependency;
package org.springframework.boot.sql.init.dependency;
import java.util.Collections;
import java.util.Set;
@ -22,27 +22,27 @@ import java.util.Set;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* Base class for {@link DependsOnDataSourceInitializationDetector
* InitializedDataSourceDependentDetector} that detect by type beans that depend upon data
* source initialization.
* Base class for {@link DependsOnDatabaseInitializationDetector
* DependsOnDatabaseInitializationDetectors} that detect by type beans that depend upon
* database initialization.
*
* @author Andy Wilkinson
* @since 2.5.0
*/
public abstract class AbstractBeansOfTypeDependsOnDataSourceInitializationDetector
implements DependsOnDataSourceInitializationDetector {
public abstract class AbstractBeansOfTypeDependsOnDatabaseInitializationDetector
implements DependsOnDatabaseInitializationDetector {
/**
* Returns the bean types that should be detected as depending on data source
* Returns the bean types that should be detected as depending on database
* initialization.
* @return the data source initialization dependent bean types
* @return the database initialization dependent bean types
*/
protected abstract Set<Class<?>> getDependsOnDataSourceInitializationBeanTypes();
protected abstract Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes();
@Override
public Set<String> detect(ConfigurableListableBeanFactory beanFactory) {
try {
Set<Class<?>> types = getDependsOnDataSourceInitializationBeanTypes();
Set<Class<?>> types = getDependsOnDatabaseInitializationBeanTypes();
return new BeansOfTypeDetector(types).detect(beanFactory);
}
catch (Throwable ex) {

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.jdbc.init.dependency;
package org.springframework.boot.sql.init.dependency;
import java.util.HashSet;
import java.util.Set;
@ -22,18 +22,18 @@ import java.util.Set;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* {@link DependsOnDataSourceInitializationDetector} that detects beans annotated with
* {@link DependsOnDataSourceInitialization}.
* {@link DependsOnDatabaseInitializationDetector} that detects beans annotated with
* {@link DependsOnDatabaseInitialization}.
*
* @author Andy Wilkinson
*/
class AnnotationDependsOnDataSourceInitializationDetector implements DependsOnDataSourceInitializationDetector {
class AnnotationDependsOnDatabaseInitializationDetector implements DependsOnDatabaseInitializationDetector {
@Override
public Set<String> detect(ConfigurableListableBeanFactory beanFactory) {
Set<String> dependentBeans = new HashSet<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
if (beanFactory.findAnnotationOnBean(beanName, DependsOnDataSourceInitialization.class) != null) {
if (beanFactory.findAnnotationOnBean(beanName, DependsOnDatabaseInitialization.class) != null) {
dependentBeans.add(beanName);
}
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.jdbc.init.dependency;
package org.springframework.boot.sql.init.dependency;
import java.util.Arrays;
import java.util.HashSet;

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.jdbc.init.dependency;
package org.springframework.boot.sql.init.dependency;
import java.util.Collection;
import java.util.Collections;
@ -22,8 +22,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.sql.DataSource;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
@ -40,93 +38,95 @@ import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;
/**
* Configures beans that depend upon DataSource initialization with
* {@link BeanDefinition#getDependsOn()} dependencies upon beans that perform
* {@link DataSource} initialization. Intended for {@link Import import} in configuration
* classes that define {@code DataSource} initialization beans or that define beans that
* require DataSource initialization to have completed before they are initialized.
* Configures beans that depend upon SQL database initialization with
* {@link BeanDefinition#getDependsOn() dependencies} upon beans that perform database
* initialization. Intended for {@link Import import} in configuration classes that define
* database initialization beans or that define beans that require database initialization
* to have completed before they are initialized.
* <p>
* Beans that initialize a {@link DataSource} are identified by
* {@link DataSourceInitializerDetector DataSourceInitializerDetectors}. Beans that depend
* upon DataSource initialization are identified by
* {@link DependsOnDataSourceInitializationDetector
* DependsOnDataSourceInitializationDetectors}.
* Beans that initialize a database are identified by {@link DatabaseInitializerDetector
* DatabaseInitializerDetectors}. Beans that depend upon database initialization are
* identified by {@link DependsOnDatabaseInitializationDetector
* DependsOnDatabaseInitializationDetectors}.
*
* @author Andy Wilkinson
* @since 2.5.0
* @see DataSourceInitializerDetector
* @see DependsOnDataSourceInitializationDetector
* @see DependsOnDataSourceInitialization
* @see DatabaseInitializerDetector
* @see DependsOnDatabaseInitializationDetector
* @see DependsOnDatabaseInitialization
*/
public class DataSourceInitializationDependencyConfigurer implements ImportBeanDefinitionRegistrar {
public class DatabaseInitializationDependencyConfigurer implements ImportBeanDefinitionRegistrar {
private final Environment environment;
DataSourceInitializationDependencyConfigurer(Environment environment) {
DatabaseInitializationDependencyConfigurer(Environment environment) {
this.environment = environment;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(DependsOnDataSourceInitializationPostProcessor.class.getName())) {
if (registry.containsBeanDefinition(DependsOnDatabaseInitializationPostProcessor.class.getName())) {
return;
}
registry.registerBeanDefinition(DependsOnDataSourceInitializationPostProcessor.class.getName(),
registry.registerBeanDefinition(DependsOnDatabaseInitializationPostProcessor.class.getName(),
BeanDefinitionBuilder
.genericBeanDefinition(DependsOnDataSourceInitializationPostProcessor.class,
() -> new DependsOnDataSourceInitializationPostProcessor(this.environment))
.genericBeanDefinition(DependsOnDatabaseInitializationPostProcessor.class,
() -> new DependsOnDatabaseInitializationPostProcessor(this.environment))
.getBeanDefinition());
}
static class DependsOnDataSourceInitializationPostProcessor implements BeanFactoryPostProcessor {
static class DependsOnDatabaseInitializationPostProcessor implements BeanFactoryPostProcessor {
private final Environment environment;
DependsOnDataSourceInitializationPostProcessor(Environment environment) {
DependsOnDatabaseInitializationPostProcessor(Environment environment) {
this.environment = environment;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
Set<String> detectedDataSourceInitializers = detectDataSourceInitializers(beanFactory);
for (String dependentDefinitionName : detectDependsOnDataSourceInitialization(beanFactory,
Set<String> detectedDatabaseInitializers = detectDatabaseInitializers(beanFactory);
if (detectedDatabaseInitializers.isEmpty()) {
return;
}
for (String dependentDefinitionName : detectDependsOnDatabaseInitialization(beanFactory,
this.environment)) {
BeanDefinition definition = getBeanDefinition(dependentDefinitionName, beanFactory);
String[] dependencies = definition.getDependsOn();
for (String dependencyName : detectedDataSourceInitializers) {
for (String dependencyName : detectedDatabaseInitializers) {
dependencies = StringUtils.addStringToArray(dependencies, dependencyName);
}
definition.setDependsOn(dependencies);
}
}
private Set<String> detectDataSourceInitializers(ConfigurableListableBeanFactory beanFactory) {
List<DataSourceInitializerDetector> detectors = instantiateDetectors(beanFactory, this.environment,
DataSourceInitializerDetector.class);
private Set<String> detectDatabaseInitializers(ConfigurableListableBeanFactory beanFactory) {
List<DatabaseInitializerDetector> detectors = instantiateDetectors(beanFactory, this.environment,
DatabaseInitializerDetector.class);
Set<String> detected = new HashSet<>();
for (DataSourceInitializerDetector detector : detectors) {
for (DatabaseInitializerDetector detector : detectors) {
for (String initializerName : detector.detect(beanFactory)) {
detected.add(initializerName);
beanFactory.getBeanDefinition(initializerName)
.setAttribute(DataSourceInitializerDetector.class.getName(), detector.getClass().getName());
.setAttribute(DatabaseInitializerDetector.class.getName(), detector.getClass().getName());
}
}
detected = Collections.unmodifiableSet(detected);
for (DataSourceInitializerDetector detector : detectors) {
for (DatabaseInitializerDetector detector : detectors) {
detector.detectionComplete(beanFactory, detected);
}
return detected;
}
private Collection<String> detectDependsOnDataSourceInitialization(ConfigurableListableBeanFactory beanFactory,
private Collection<String> detectDependsOnDatabaseInitialization(ConfigurableListableBeanFactory beanFactory,
Environment environment) {
List<DependsOnDataSourceInitializationDetector> detectors = instantiateDetectors(beanFactory, environment,
DependsOnDataSourceInitializationDetector.class);
Set<String> dependentUponDataSourceInitialization = new HashSet<>();
for (DependsOnDataSourceInitializationDetector detector : detectors) {
dependentUponDataSourceInitialization.addAll(detector.detect(beanFactory));
List<DependsOnDatabaseInitializationDetector> detectors = instantiateDetectors(beanFactory, environment,
DependsOnDatabaseInitializationDetector.class);
Set<String> dependentUponDatabaseInitialization = new HashSet<>();
for (DependsOnDatabaseInitializationDetector detector : detectors) {
dependentUponDatabaseInitialization.addAll(detector.detect(beanFactory));
}
return dependentUponDataSourceInitialization;
return dependentUponDatabaseInitialization;
}
private <T> List<T> instantiateDetectors(ConfigurableListableBeanFactory beanFactory, Environment environment,

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.jdbc.init.dependency;
package org.springframework.boot.sql.init.dependency;
import java.util.Set;
@ -23,14 +23,14 @@ import javax.sql.DataSource;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* Detects beans that initialize a {@link DataSource}. Implementations should be
* registered in {@code META-INF/spring.factories} under the key
* {@code org.springframework.boot.jdbc.init.DependsOnDataSourceInitializationDetector}.
* Detects beans that initialize an SQL database. Implementations should be registered in
* {@code META-INF/spring.factories} under the key
* {@code org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector}.
*
* @author Andy Wilkinson
* @since 2.5.0
*/
public interface DataSourceInitializerDetector {
public interface DatabaseInitializerDetector {
/**
* Detect beans defined in the given {@code beanFactory} that initialize a

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.jdbc.init.dependency;
package org.springframework.boot.sql.init.dependency;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@ -25,9 +25,8 @@ import java.lang.annotation.Target;
import org.springframework.context.annotation.Bean;
/**
* Indicate that a bean's creation and initialization depends upon data source
* initialization having completed. May be used on a bean's class or its
* {@link Bean @Bean} definition.
* Indicate that a bean's creation and initialization depends upon database initialization
* having completed. May be used on a bean's class or its {@link Bean @Bean} definition.
*
* @author Andy Wilkinson
* @since 2.5.0
@ -35,6 +34,6 @@ import org.springframework.context.annotation.Bean;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DependsOnDataSourceInitialization {
public @interface DependsOnDatabaseInitialization {
}

@ -14,30 +14,27 @@
* limitations under the License.
*/
package org.springframework.boot.jdbc.init.dependency;
package org.springframework.boot.sql.init.dependency;
import java.util.Set;
import javax.sql.DataSource;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* Detects beans that depend on {@link DataSource} initialization. Implementations should
* be registered in {@code META-INF/spring.factories} under the key
* {@code org.springframework.boot.jdbc.init.DependsOnDataSourceInitializationDetector}.
* Detects beans that depend on database initialization. Implementations should be
* registered in {@code META-INF/spring.factories} under the key
* {@code org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector}.
*
* @author Andy Wilkinson
* @since 2.5.0
*/
public interface DependsOnDataSourceInitializationDetector {
public interface DependsOnDatabaseInitializationDetector {
/**
* Detect beans defined in the given {@code beanFactory} that depend on
* {@link DataSource} initialization. If no beans are detected, an empty set is
* returned.
* Detect beans defined in the given {@code beanFactory} that depend on database
* initialization. If no beans are detected, an empty set is returned.
* @param beanFactory bean factory to examine
* @return names of any beans that depend upon {@code DataSource} initialization
* @return names of any beans that depend upon database initialization
*/
Set<String> detect(ConfigurableListableBeanFactory beanFactory);

@ -15,6 +15,6 @@
*/
/**
* Infrastructure for establishing {@code DataSource} initialization bean dependencies.
* Infrastructure for establishing database initialization bean dependencies.
*/
package org.springframework.boot.jdbc.init.dependency;
package org.springframework.boot.sql.init.dependency;

@ -79,16 +79,17 @@ org.springframework.boot.liquibase.LiquibaseChangelogMissingFailureAnalyzer
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
# DataSource Initializer Detectors
org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector=\
org.springframework.boot.flyway.FlywayDataSourceInitializerDetector,\
# Database Initializer Detectors
org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\
org.springframework.boot.flyway.FlywayDatabaseInitializerDetector,\
org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializerDetector,\
org.springframework.boot.liquibase.LiquibaseDataSourceInitializerDetector,\
org.springframework.boot.orm.jpa.JpaDataSourceInitializerDetector
org.springframework.boot.liquibase.LiquibaseDatabaseInitializerDetector,\
org.springframework.boot.orm.jpa.JpaDatabaseInitializerDetector,\
org.springframework.boot.r2dbc.init.R2dbcScriptDatabaseInitializerDetector
# Depends On DataSource Initialization Detectors
org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitializationDetector=\
org.springframework.boot.jdbc.init.dependency.AnnotationDependsOnDataSourceInitializationDetector,\
org.springframework.boot.jdbc.SpringJdbcDependsOnDataSourceInitializationDetector,\
org.springframework.boot.jooq.JooqDependsOnDataSourceInitializationDetector,\
org.springframework.boot.orm.jpa.JpaDependsOnDataSourceInitializationDetector
# Depends On Database Initialization Detectors
org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\
org.springframework.boot.sql.init.dependency.AnnotationDependsOnDatabaseInitializationDetector,\
org.springframework.boot.jdbc.SpringJdbcDependsOnDatabaseInitializationDetector,\
org.springframework.boot.jooq.JooqDependsOnDatabaseInitializationDetector,\
org.springframework.boot.orm.jpa.JpaDependsOnDatabaseInitializationDetector

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.jdbc.init.dependency;
package org.springframework.boot.sql.init.dependency;
import java.io.File;
import java.io.FileWriter;
@ -51,55 +51,54 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link DataSourceInitializationDependencyConfigurer}.
* Tests for {@link DatabaseInitializationDependencyConfigurer}.
*
* @author Andy Wilkinson
*/
class DataSourceInitializationDependencyConfigurerTests {
class DatabaseInitializationDependencyConfigurerTests {
private final ConfigurableEnvironment environment = new MockEnvironment();
DataSourceInitializerDetector dataSourceInitializerDetector = MockedDataSourceInitializerDetector.mock;
DatabaseInitializerDetector databaseInitializerDetector = MockedDatabaseInitializerDetector.mock;
DependsOnDataSourceInitializationDetector dependsOnDataSourceInitializationDetector = MockedDependsOnDataSourceInitializationDetector.mock;
DependsOnDatabaseInitializationDetector dependsOnDatabaseInitializationDetector = MockedDependsOnDatabaseInitializationDetector.mock;
@TempDir
File temp;
@BeforeEach
void resetMocks() {
reset(MockedDataSourceInitializerDetector.mock, MockedDependsOnDataSourceInitializationDetector.mock);
reset(MockedDatabaseInitializerDetector.mock, MockedDependsOnDatabaseInitializationDetector.mock);
}
@Test
void whenDetectorsAreCreatedThenTheEnvironmentCanBeInjected() {
performDetection(Arrays.asList(ConstructorInjectionDataSourceInitializerDetector.class,
ConstructorInjectionDependsOnDataSourceInitializationDetector.class), (context) -> {
performDetection(Arrays.asList(ConstructorInjectionDatabaseInitializerDetector.class,
ConstructorInjectionDependsOnDatabaseInitializationDetector.class), (context) -> {
context.refresh();
assertThat(ConstructorInjectionDataSourceInitializerDetector.environment)
.isEqualTo(this.environment);
assertThat(ConstructorInjectionDependsOnDataSourceInitializationDetector.environment)
assertThat(ConstructorInjectionDatabaseInitializerDetector.environment).isEqualTo(this.environment);
assertThat(ConstructorInjectionDependsOnDatabaseInitializationDetector.environment)
.isEqualTo(this.environment);
});
}
@Test
void whenDependenciesAreConfiguredThenBeansThatDependUponDataSourceInitializationDependUponDetectedDataSourceInitializers() {
void whenDependenciesAreConfiguredThenBeansThatDependUponDatabaseInitializationDependUponDetectedDatabaseInitializers() {
BeanDefinition alpha = BeanDefinitionBuilder.genericBeanDefinition(String.class).getBeanDefinition();
BeanDefinition bravo = BeanDefinitionBuilder.genericBeanDefinition(String.class).getBeanDefinition();
performDetection(Arrays.asList(MockedDataSourceInitializerDetector.class,
MockedDependsOnDataSourceInitializationDetector.class), (context) -> {
performDetection(Arrays.asList(MockedDatabaseInitializerDetector.class,
MockedDependsOnDatabaseInitializationDetector.class), (context) -> {
context.registerBeanDefinition("alpha", alpha);
context.registerBeanDefinition("bravo", bravo);
given(this.dataSourceInitializerDetector.detect(context.getBeanFactory()))
given(this.databaseInitializerDetector.detect(context.getBeanFactory()))
.willReturn(Collections.singleton("alpha"));
given(this.dependsOnDataSourceInitializationDetector.detect(context.getBeanFactory()))
given(this.dependsOnDatabaseInitializationDetector.detect(context.getBeanFactory()))
.willReturn(Collections.singleton("bravo"));
context.refresh();
assertThat(alpha.getAttribute(DataSourceInitializerDetector.class.getName()))
.isEqualTo(MockedDataSourceInitializerDetector.class.getName());
assertThat(bravo.getAttribute(DataSourceInitializerDetector.class.getName())).isNull();
verify(this.dataSourceInitializerDetector).detectionComplete(context.getBeanFactory(),
assertThat(alpha.getAttribute(DatabaseInitializerDetector.class.getName()))
.isEqualTo(MockedDatabaseInitializerDetector.class.getName());
assertThat(bravo.getAttribute(DatabaseInitializerDetector.class.getName())).isNull();
verify(this.databaseInitializerDetector).detectionComplete(context.getBeanFactory(),
Collections.singleton("alpha"));
assertThat(bravo.getDependsOn()).containsExactly("alpha");
});
@ -118,17 +117,17 @@ class DataSourceInitializationDependencyConfigurerTests {
}
@Configuration(proxyBeanMethods = false)
@Import(DataSourceInitializationDependencyConfigurer.class)
@Import(DatabaseInitializationDependencyConfigurer.class)
static class DependencyConfigurerConfiguration {
}
static class ConstructorInjectionDataSourceInitializerDetector implements DataSourceInitializerDetector {
static class ConstructorInjectionDatabaseInitializerDetector implements DatabaseInitializerDetector {
private static Environment environment;
ConstructorInjectionDataSourceInitializerDetector(Environment environment) {
ConstructorInjectionDataSourceInitializerDetector.environment = environment;
ConstructorInjectionDatabaseInitializerDetector(Environment environment) {
ConstructorInjectionDatabaseInitializerDetector.environment = environment;
}
@Override
@ -138,13 +137,13 @@ class DataSourceInitializationDependencyConfigurerTests {
}
static class ConstructorInjectionDependsOnDataSourceInitializationDetector
implements DependsOnDataSourceInitializationDetector {
static class ConstructorInjectionDependsOnDatabaseInitializationDetector
implements DependsOnDatabaseInitializationDetector {
private static Environment environment;
ConstructorInjectionDependsOnDataSourceInitializationDetector(Environment environment) {
ConstructorInjectionDependsOnDataSourceInitializationDetector.environment = environment;
ConstructorInjectionDependsOnDatabaseInitializationDetector(Environment environment) {
ConstructorInjectionDependsOnDatabaseInitializationDetector.environment = environment;
}
@Override
@ -154,40 +153,40 @@ class DataSourceInitializationDependencyConfigurerTests {
}
static class MockedDataSourceInitializerDetector implements DataSourceInitializerDetector {
static class MockedDatabaseInitializerDetector implements DatabaseInitializerDetector {
private static DataSourceInitializerDetector mock = Mockito.mock(DataSourceInitializerDetector.class);
private static DatabaseInitializerDetector mock = Mockito.mock(DatabaseInitializerDetector.class);
@Override
public Set<String> detect(ConfigurableListableBeanFactory beanFactory) {
return MockedDataSourceInitializerDetector.mock.detect(beanFactory);
return MockedDatabaseInitializerDetector.mock.detect(beanFactory);
}
@Override
public void detectionComplete(ConfigurableListableBeanFactory beanFactory,
Set<String> dataSourceInitializerNames) {
mock.detectionComplete(beanFactory, dataSourceInitializerNames);
Set<String> databaseInitializerNames) {
mock.detectionComplete(beanFactory, databaseInitializerNames);
}
}
static class MockedDependsOnDataSourceInitializationDetector implements DependsOnDataSourceInitializationDetector {
static class MockedDependsOnDatabaseInitializationDetector implements DependsOnDatabaseInitializationDetector {
private static DependsOnDataSourceInitializationDetector mock = Mockito
.mock(DependsOnDataSourceInitializationDetector.class);
private static DependsOnDatabaseInitializationDetector mock = Mockito
.mock(DependsOnDatabaseInitializationDetector.class);
@Override
public Set<String> detect(ConfigurableListableBeanFactory beanFactory) {
return MockedDependsOnDataSourceInitializationDetector.mock.detect(beanFactory);
return MockedDependsOnDatabaseInitializationDetector.mock.detect(beanFactory);
}
}
static class DetectorSpringFactoriesClassLoader extends ClassLoader {
private final Set<Class<DataSourceInitializerDetector>> dataSourceInitializerDetectors = new HashSet<>();
private final Set<Class<DatabaseInitializerDetector>> databaseInitializerDetectors = new HashSet<>();
private final Set<Class<DependsOnDataSourceInitializationDetector>> dependsOnDataSourceInitializationDetectors = new HashSet<>();
private final Set<Class<DependsOnDatabaseInitializationDetector>> dependsOnDatabaseInitializationDetectors = new HashSet<>();
private final File temp;
@ -197,12 +196,12 @@ class DataSourceInitializationDependencyConfigurerTests {
@SuppressWarnings("unchecked")
void register(Class<?> detector) {
if (DataSourceInitializerDetector.class.isAssignableFrom(detector)) {
this.dataSourceInitializerDetectors.add((Class<DataSourceInitializerDetector>) detector);
if (DatabaseInitializerDetector.class.isAssignableFrom(detector)) {
this.databaseInitializerDetectors.add((Class<DatabaseInitializerDetector>) detector);
}
else if (DependsOnDataSourceInitializationDetector.class.isAssignableFrom(detector)) {
this.dependsOnDataSourceInitializationDetectors
.add((Class<DependsOnDataSourceInitializationDetector>) detector);
else if (DependsOnDatabaseInitializationDetector.class.isAssignableFrom(detector)) {
this.dependsOnDatabaseInitializationDetectors
.add((Class<DependsOnDatabaseInitializationDetector>) detector);
}
else {
throw new IllegalArgumentException("Unsupported detector type '" + detector.getName() + "'");
@ -215,10 +214,10 @@ class DataSourceInitializationDependencyConfigurerTests {
return super.findResources(name);
}
Properties properties = new Properties();
properties.put(DataSourceInitializerDetector.class.getName(), String.join(",",
this.dataSourceInitializerDetectors.stream().map(Class::getName).collect(Collectors.toList())));
properties.put(DependsOnDataSourceInitializationDetector.class.getName(),
String.join(",", this.dependsOnDataSourceInitializationDetectors.stream().map(Class::getName)
properties.put(DatabaseInitializerDetector.class.getName(), String.join(",",
this.databaseInitializerDetectors.stream().map(Class::getName).collect(Collectors.toList())));
properties.put(DependsOnDatabaseInitializationDetector.class.getName(),
String.join(",", this.dependsOnDatabaseInitializationDetectors.stream().map(Class::getName)
.collect(Collectors.toList())));
File springFactories = new File(this.temp, "spring.factories");
try (FileWriter writer = new FileWriter(springFactories)) {
Loading…
Cancel
Save