Provide more pluggable way to indicate DataSource init dependencies

Closes gh-17619
Closes gh-25559
This commit is contained in:
Andy Wilkinson
2021-02-19 13:18:03 +00:00
parent 99b7d29c2c
commit ed72bca6c8
40 changed files with 1230 additions and 476 deletions

View File

@@ -26,7 +26,6 @@ import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.flywaydb.core.Flyway;
@@ -34,7 +33,6 @@ import org.flywaydb.core.api.MigrationVersion;
import org.flywaydb.core.api.callback.Callback;
import org.flywaydb.core.api.configuration.FluentConfiguration;
import org.flywaydb.core.api.migration.JavaMigration;
import org.jooq.DSLContext;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
@@ -45,22 +43,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayDataSourceCondition;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayDslContextDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayEntityManagerFactoryDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayJdbcOperationsDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayNamedParameterJdbcOperationsDependencyConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.jdbc.JdbcOperationsDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.NamedParameterJdbcOperationsDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.jooq.DslContextDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.jdbc.init.DataSourceInitializationDependencyConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@@ -68,12 +59,8 @@ import org.springframework.context.annotation.Import;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -100,8 +87,7 @@ import org.springframework.util.StringUtils;
@ConditionalOnProperty(prefix = "spring.flyway", name = "enabled", matchIfMissing = true)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, JdbcTemplateAutoConfiguration.class,
HibernateJpaAutoConfiguration.class })
@Import({ FlywayEntityManagerFactoryDependsOnPostProcessor.class, FlywayJdbcOperationsDependsOnPostProcessor.class,
FlywayNamedParameterJdbcOperationsDependencyConfiguration.class, FlywayDslContextDependsOnPostProcessor.class })
@Import(DataSourceInitializationDependencyConfigurer.class)
public class FlywayAutoConfiguration {
@Bean
@@ -118,10 +104,6 @@ public class FlywayAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(Flyway.class)
@EnableConfigurationProperties({ DataSourceProperties.class, FlywayProperties.class })
@Import({ FlywayMigrationInitializerEntityManagerFactoryDependsOnPostProcessor.class,
FlywayMigrationInitializerJdbcOperationsDependsOnPostProcessor.class,
FlywayMigrationInitializerNamedParameterJdbcOperationsDependsOnPostProcessor.class,
FlywayMigrationInitializerDslContextDependsOnPostProcessor.class })
public static class FlywayConfiguration {
@Bean
@@ -325,122 +307,6 @@ public class FlywayAutoConfiguration {
}
/**
* Post processor to ensure that {@link EntityManagerFactory} beans depend on any
* {@link FlywayMigrationInitializer} beans.
*/
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
static class FlywayMigrationInitializerEntityManagerFactoryDependsOnPostProcessor
extends EntityManagerFactoryDependsOnPostProcessor {
FlywayMigrationInitializerEntityManagerFactoryDependsOnPostProcessor() {
super(FlywayMigrationInitializer.class);
}
}
/**
* Post processor to ensure that {@link JdbcOperations} beans depend on any
* {@link FlywayMigrationInitializer} beans.
*/
@ConditionalOnClass(JdbcOperations.class)
@ConditionalOnBean(JdbcOperations.class)
static class FlywayMigrationInitializerJdbcOperationsDependsOnPostProcessor
extends JdbcOperationsDependsOnPostProcessor {
FlywayMigrationInitializerJdbcOperationsDependsOnPostProcessor() {
super(FlywayMigrationInitializer.class);
}
}
/**
* Post processor to ensure that {@link NamedParameterJdbcOperations} beans depend on
* any {@link FlywayMigrationInitializer} beans.
*/
@ConditionalOnClass(NamedParameterJdbcOperations.class)
@ConditionalOnBean(NamedParameterJdbcOperations.class)
static class FlywayMigrationInitializerNamedParameterJdbcOperationsDependsOnPostProcessor
extends NamedParameterJdbcOperationsDependsOnPostProcessor {
FlywayMigrationInitializerNamedParameterJdbcOperationsDependsOnPostProcessor() {
super(FlywayMigrationInitializer.class);
}
}
/**
* Post processor to ensure that {@link DSLContext} beans depend on any
* {@link FlywayMigrationInitializer} beans.
*/
@ConditionalOnClass(DSLContext.class)
@ConditionalOnBean(DSLContext.class)
static class FlywayMigrationInitializerDslContextDependsOnPostProcessor extends DslContextDependsOnPostProcessor {
FlywayMigrationInitializerDslContextDependsOnPostProcessor() {
super(FlywayMigrationInitializer.class);
}
}
/**
* Post processor to ensure that {@link EntityManagerFactory} beans depend on any
* {@link Flyway} beans.
*/
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
static class FlywayEntityManagerFactoryDependsOnPostProcessor extends EntityManagerFactoryDependsOnPostProcessor {
FlywayEntityManagerFactoryDependsOnPostProcessor() {
super(Flyway.class);
}
}
/**
* Post processor to ensure that {@link JdbcOperations} beans depend on any
* {@link Flyway} beans.
*/
@ConditionalOnClass(JdbcOperations.class)
@ConditionalOnBean(JdbcOperations.class)
static class FlywayJdbcOperationsDependsOnPostProcessor extends JdbcOperationsDependsOnPostProcessor {
FlywayJdbcOperationsDependsOnPostProcessor() {
super(Flyway.class);
}
}
/**
* Post processor to ensure that {@link NamedParameterJdbcOperations} beans depend on
* any {@link Flyway} beans.
*/
@ConditionalOnClass(NamedParameterJdbcOperations.class)
@ConditionalOnBean(NamedParameterJdbcOperations.class)
protected static class FlywayNamedParameterJdbcOperationsDependencyConfiguration
extends NamedParameterJdbcOperationsDependsOnPostProcessor {
public FlywayNamedParameterJdbcOperationsDependencyConfiguration() {
super(Flyway.class);
}
}
/**
* Post processor to ensure that {@link DSLContext} beans depend on any {@link Flyway}
* beans.
*/
@ConditionalOnClass(DSLContext.class)
@ConditionalOnBean(DSLContext.class)
protected static class FlywayDslContextDependsOnPostProcessor extends DslContextDependsOnPostProcessor {
public FlywayDslContextDependsOnPostProcessor() {
super(Flyway.class);
}
}
private static class LocationResolver {
private static final String VENDOR_PLACEHOLDER = "{vendor}";

View File

@@ -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.autoconfigure.flyway;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.jdbc.init.AbstractBeansOfTypeDataSourceInitializerDetector;
import org.springframework.boot.jdbc.init.DataSourceInitializerDetector;
/**
* A {@link DataSourceInitializerDetector} for {@link FlywayMigrationInitializer}.
*
* @author Andy Wilkinson
*/
class FlywayMigrationInitializerDataSourceInitializerDetector extends AbstractBeansOfTypeDataSourceInitializerDetector {
@Override
protected Set<Class<?>> getDataSourceInitializerBeanTypes() {
return Collections.singleton(FlywayMigrationInitializer.class);
}
}

View File

@@ -16,19 +16,13 @@
package org.springframework.boot.autoconfigure.jdbc;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryDependsOnPostProcessor;
import org.springframework.boot.jdbc.init.DataSourceInitializationDependencyConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
/**
* Configuration for {@link DataSource} initialization using DDL and DML scripts.
@@ -37,63 +31,12 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(DataSource.class)
@Import(DataSourceInitializationDependencyConfigurer.class)
class DataSourceInitializationConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.datasource", name = "initialization-order", havingValue = "before-jpa",
matchIfMissing = true)
@Import({ DataSourceInitializationJdbcOperationsDependsOnPostProcessor.class,
DataSourceInitializationNamedParameterJdbcOperationsDependsOnPostProcessor.class,
DataSourceInitializationEntityManagerFactoryDependsOnPostProcessor.class })
static class BeforeJpaDataSourceInitializationConfiguration {
@Bean
DataSourceInitialization dataSourceInitialization(DataSource dataSource, DataSourceProperties properties) {
return new DataSourceInitialization(dataSource, properties);
}
}
/**
* Post processor to ensure that {@link EntityManagerFactory} beans depend on any
* {@link DataSourceInitialization} beans.
*/
@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManagerFactory.class })
static class DataSourceInitializationEntityManagerFactoryDependsOnPostProcessor
extends EntityManagerFactoryDependsOnPostProcessor {
DataSourceInitializationEntityManagerFactoryDependsOnPostProcessor() {
super(DataSourceInitialization.class);
}
}
/**
* Post processor to ensure that {@link JdbcOperations} beans depend on any
* {@link DataSourceInitialization} beans.
*/
@ConditionalOnClass(JdbcOperations.class)
static class DataSourceInitializationJdbcOperationsDependsOnPostProcessor
extends JdbcOperationsDependsOnPostProcessor {
DataSourceInitializationJdbcOperationsDependsOnPostProcessor() {
super(DataSourceInitialization.class);
}
}
/**
* Post processor to ensure that {@link NamedParameterJdbcOperations} beans depend on
* any {@link DataSourceInitialization} beans.
*/
@ConditionalOnClass(NamedParameterJdbcOperations.class)
protected static class DataSourceInitializationNamedParameterJdbcOperationsDependsOnPostProcessor
extends NamedParameterJdbcOperationsDependsOnPostProcessor {
public DataSourceInitializationNamedParameterJdbcOperationsDependsOnPostProcessor() {
super(DataSourceInitialization.class);
}
@Bean
DataSourceInitialization dataSourceInitialization(DataSource dataSource, DataSourceProperties properties) {
return new DataSourceInitialization(dataSource, properties);
}
}

View File

@@ -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.autoconfigure.jdbc;
import java.util.Collections;
import java.util.Set;
import org.springframework.boot.jdbc.init.AbstractBeansOfTypeDataSourceInitializerDetector;
import org.springframework.boot.jdbc.init.DataSourceInitializerDetector;
/**
* A {@link DataSourceInitializerDetector} for {@link DataSourceInitialization}.
*
* @author Andy Wilkinson
*/
class DataSourceInitializationDataSourceInitializerDetector extends AbstractBeansOfTypeDataSourceInitializerDetector {
@Override
protected Set<Class<?>> getDataSourceInitializerBeanTypes() {
return Collections.singleton(DataSourceInitialization.class);
}
}

View File

@@ -1,43 +0,0 @@
/*
* 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.autoconfigure.jdbc;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.sql.DataSource;
import org.springframework.context.annotation.DependsOn;
/**
* Annotation used to indicate that a bean depends upon the auto-configured DataSource
* initialization having completed before the {@link DataSource} is injected. If the
* DataSource is not used during startup, no such dependency is required.
*
* @author Andy Wilkinson
* @since 2.5.0
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@DependsOn("dataSourceInitialization")
public @interface DependsOnDataSourceInitialization {
}

View File

@@ -19,6 +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.DependsOnDataSourceInitializationDetector;
import org.springframework.jdbc.core.JdbcOperations;
/**
@@ -32,7 +33,9 @@ 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
public class JdbcOperationsDependsOnPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {
/**

View File

@@ -23,6 +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.DataSourceInitializationDependencyConfigurer;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -43,7 +44,8 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
@Import({ JdbcTemplateConfiguration.class, NamedParameterJdbcTemplateConfiguration.class })
@Import({ DataSourceInitializationDependencyConfigurer.class, JdbcTemplateConfiguration.class,
NamedParameterJdbcTemplateConfiguration.class })
public class JdbcTemplateAutoConfiguration {
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* 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.
@@ -19,6 +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.DependsOnDataSourceInitializationDetector;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
/**
@@ -30,7 +31,9 @@ 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
public class NamedParameterJdbcOperationsDependsOnPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {
/**

View File

@@ -21,6 +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.DependsOnDataSourceInitializationDetector;
/**
* {@link BeanFactoryPostProcessor} that can be used to dynamically declare that all
@@ -29,7 +30,9 @@ import org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostPr
* @author Eddú Meléndez
* @since 2.3.9
* @see BeanDefinition#setDependsOn(String[])
* @deprecated since 2.5.0 in favor of {@link DependsOnDataSourceInitializationDetector}
*/
@Deprecated
public class DslContextDependsOnPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {
/**

View File

@@ -18,12 +18,10 @@ package org.springframework.boot.autoconfigure.liquibase;
import java.util.function.Supplier;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import liquibase.change.DatabaseChange;
import liquibase.integration.spring.SpringLiquibase;
import org.jooq.DSLContext;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
@@ -35,28 +33,17 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.jdbc.JdbcOperationsDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.jdbc.NamedParameterJdbcOperationsDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.jooq.DslContextDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseDataSourceCondition;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseDslContextDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseEntityManagerFactoryDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseJdbcOperationsDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseNamedParameterJdbcOperationsDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryDependsOnPostProcessor;
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.DatabaseDriver;
import org.springframework.boot.jdbc.init.DataSourceInitializationDependencyConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.util.StringUtils;
/**
@@ -79,10 +66,7 @@ import org.springframework.util.StringUtils;
@ConditionalOnProperty(prefix = "spring.liquibase", name = "enabled", matchIfMissing = true)
@Conditional(LiquibaseDataSourceCondition.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
@Import({ LiquibaseEntityManagerFactoryDependsOnPostProcessor.class,
LiquibaseJdbcOperationsDependsOnPostProcessor.class,
LiquibaseNamedParameterJdbcOperationsDependsOnPostProcessor.class,
LiquibaseDslContextDependsOnPostProcessor.class })
@Import(DataSourceInitializationDependencyConfigurer.class)
public class LiquibaseAutoConfiguration {
@Bean
@@ -175,64 +159,6 @@ public class LiquibaseAutoConfiguration {
}
/**
* Post processor to ensure that {@link EntityManagerFactory} beans depend on any
* {@link SpringLiquibase} beans.
*/
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
static class LiquibaseEntityManagerFactoryDependsOnPostProcessor
extends EntityManagerFactoryDependsOnPostProcessor {
LiquibaseEntityManagerFactoryDependsOnPostProcessor() {
super(SpringLiquibase.class);
}
}
/**
* Additional configuration to ensure that {@link JdbcOperations} beans depend on any
* {@link SpringLiquibase} beans.
*/
@ConditionalOnClass(JdbcOperations.class)
@ConditionalOnBean(JdbcOperations.class)
static class LiquibaseJdbcOperationsDependsOnPostProcessor extends JdbcOperationsDependsOnPostProcessor {
LiquibaseJdbcOperationsDependsOnPostProcessor() {
super(SpringLiquibase.class);
}
}
/**
* Post processor to ensure that {@link NamedParameterJdbcOperations} beans depend on
* any {@link SpringLiquibase} beans.
*/
@ConditionalOnClass(NamedParameterJdbcOperations.class)
@ConditionalOnBean(NamedParameterJdbcOperations.class)
static class LiquibaseNamedParameterJdbcOperationsDependsOnPostProcessor
extends NamedParameterJdbcOperationsDependsOnPostProcessor {
LiquibaseNamedParameterJdbcOperationsDependsOnPostProcessor() {
super(SpringLiquibase.class);
}
}
/**
* Post processor to ensure that {@link DSLContext} beans depend on any
* {@link SpringLiquibase} beans.
*/
@ConditionalOnClass(DSLContext.class)
@ConditionalOnBean(DSLContext.class)
static class LiquibaseDslContextDependsOnPostProcessor extends DslContextDependsOnPostProcessor {
LiquibaseDslContextDependsOnPostProcessor() {
super(SpringLiquibase.class);
}
}
static final class LiquibaseDataSourceCondition extends AnyNestedCondition {
LiquibaseDataSourceCondition() {

View File

@@ -17,23 +17,16 @@
package org.springframework.boot.autoconfigure.orm.jpa;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.spi.SessionImplementor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.ResourceLoader;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
/**
@@ -52,18 +45,4 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@Import(HibernateJpaConfiguration.class)
public class HibernateJpaAutoConfiguration {
@ConditionalOnProperty(prefix = "spring.datasource", name = "initialization-order", havingValue = "after-jpa",
matchIfMissing = false)
static class AfterJpaDataSourceInitializationConfiguration {
@Bean
HibernatePropertiesCustomizer dataSourceInitializationCustomizer(DataSource dataSource,
DataSourceProperties properties, ResourceLoader resourceLoader) {
return (hibernateProperties) -> hibernateProperties.put(AvailableSettings.SCHEMA_MANAGEMENT_TOOL,
new SpringBootSchemaManagementTool(
new DataSourceInitializer(dataSource, properties, resourceLoader)));
}
}
}

View File

@@ -1,87 +0,0 @@
/*
* 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.autoconfigure.orm.jpa;
import org.hibernate.boot.Metadata;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.resource.transaction.spi.DdlTransactionIsolator;
import org.hibernate.tool.schema.TargetType;
import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool;
import org.hibernate.tool.schema.internal.exec.GenerationTarget;
import org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase;
import org.hibernate.tool.schema.internal.exec.JdbcContext;
import org.hibernate.tool.schema.spi.ExecutionOptions;
import org.hibernate.tool.schema.spi.SchemaCreator;
import org.hibernate.tool.schema.spi.SourceDescriptor;
import org.hibernate.tool.schema.spi.TargetDescriptor;
import org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer;
/**
* Spring Boot {@link SchemaCreator}.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
class SpringBootSchemaCreator implements SchemaCreator {
private static final CoreMessageLogger log = CoreLogging.messageLogger(SpringBootSchemaCreator.class);
private final HibernateSchemaManagementTool tool;
private final DataSourceInitializer dataSourceInitializer;
private final SchemaCreator creator;
SpringBootSchemaCreator(HibernateSchemaManagementTool tool, SchemaCreator creator,
DataSourceInitializer dataSourceInitializer) {
this.tool = tool;
this.creator = creator;
this.dataSourceInitializer = dataSourceInitializer;
}
@Override
public void doCreation(Metadata metadata, ExecutionOptions options, SourceDescriptor sourceDescriptor,
TargetDescriptor targetDescriptor) {
if (!targetDescriptor.getTargetTypes().contains(TargetType.DATABASE)) {
this.creator.doCreation(metadata, options, sourceDescriptor, targetDescriptor);
return;
}
GenerationTarget databaseTarget = getDatabaseTarget(options, targetDescriptor);
databaseTarget.prepare();
try {
this.creator.doCreation(metadata, options, sourceDescriptor, targetDescriptor);
this.dataSourceInitializer.initializeDataSource();
}
finally {
try {
databaseTarget.release();
}
catch (Exception ex) {
log.debugf("Problem releasing GenerationTarget [%s] : %s", databaseTarget, ex.getMessage());
}
}
}
private GenerationTarget getDatabaseTarget(ExecutionOptions options, TargetDescriptor targetDescriptor) {
JdbcContext jdbcContext = this.tool.resolveJdbcContext(options.getConfigurationValues());
DdlTransactionIsolator ddlTransactionIsolator = this.tool.getDdlTransactionIsolator(jdbcContext);
return new GenerationTargetToDatabase(ddlTransactionIsolator);
}
}

View File

@@ -1,48 +0,0 @@
/*
* 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.autoconfigure.orm.jpa;
import java.util.Map;
import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool;
import org.hibernate.tool.schema.spi.SchemaCreator;
import org.hibernate.tool.schema.spi.SchemaManagementTool;
import org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer;
/**
* Spring Boot {@link SchemaManagementTool}.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
class SpringBootSchemaManagementTool extends HibernateSchemaManagementTool {
private final DataSourceInitializer dataSourceInitializer;
SpringBootSchemaManagementTool(DataSourceInitializer dataSourceInitializer) {
this.dataSourceInitializer = dataSourceInitializer;
}
@Override
@SuppressWarnings("rawtypes")
public SchemaCreator getSchemaCreator(Map options) {
SchemaCreator creator = super.getSchemaCreator(options);
return new SpringBootSchemaCreator(this, creator, this.dataSourceInitializer);
}
}

View File

@@ -756,10 +756,6 @@
"name": "spring.datasource.initialization-mode",
"defaultValue": "embedded"
},
{
"name": "spring.datasource.initialization-order",
"defaultValue": "before-jpa"
},
{
"name": "spring.datasource.jmx-enabled",
"type": "java.lang.Boolean",
@@ -1905,17 +1901,6 @@
}
]
},
{
"name": "spring.datasource.initialization-order",
"values": [
{
"value": "before-jpa"
},
{
"value": "after-jpa"
}
]
},
{
"name": "spring.datasource.schema",
"providers": [

View File

@@ -166,3 +166,9 @@ org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProv
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider
# DataSource initializer detectors
org.springframework.boot.jdbc.init.DataSourceInitializerDetector=\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializerDataSourceInitializerDetector,\
org.springframework.boot.autoconfigure.jdbc.DataSourceInitializationDataSourceInitializerDetector

View File

@@ -577,7 +577,7 @@ class FlywayAutoConfigurationTests {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, JooqConfiguration.class)
.run((context) -> {
BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("dslContext");
assertThat(beanDefinition.getDependsOn()).containsExactly("flywayInitializer", "flyway");
assertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder("flywayInitializer", "flyway");
});
}
@@ -586,7 +586,8 @@ class FlywayAutoConfigurationTests {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, JooqConfiguration.class,
CustomFlywayMigrationInitializer.class).run((context) -> {
BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("dslContext");
assertThat(beanDefinition.getDependsOn()).containsExactly("flywayMigrationInitializer", "flyway");
assertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder("flywayMigrationInitializer",
"flyway");
});
}
@@ -595,7 +596,7 @@ class FlywayAutoConfigurationTests {
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, JooqConfiguration.class,
CustomFlyway.class).run((context) -> {
BeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition("dslContext");
assertThat(beanDefinition.getDependsOn()).containsExactly("customFlyway");
assertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder("customFlyway");
});
}

View File

@@ -43,6 +43,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
import org.springframework.boot.jdbc.init.DependsOnDataSourceInitialization;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;

View File

@@ -60,6 +60,7 @@ 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.DependsOnDataSourceInitialization;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy;
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
@@ -123,8 +124,7 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes
contextRunner().withUserConfiguration(TestInitializedJpaConfiguration.class)
.withClassLoader(new HideDataScriptClassLoader())
.withPropertyValues("spring.jpa.show-sql=true", "spring.jpa.hibernate.ddl-auto:create-drop",
"spring.datasource.data:classpath:/city.sql",
"spring.datasource.initialization-order=after-jpa")
"spring.datasource.data:classpath:/city.sql", "spring.jpa.defer-datasource-initialization=true")
.run((context) -> assertThat(context.getBean(TestInitializedJpaConfiguration.class).called).isTrue());
}
@@ -287,7 +287,7 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes
contextRunner().withClassLoader(new HideDataScriptClassLoader())
.withPropertyValues("spring.datasource.data:classpath:/db/non-annotated-data.sql",
"spring.jpa.mapping-resources=META-INF/mappings/non-annotated.xml",
"spring.datasource.initialization-order=after-jpa")
"spring.jpa.defer-datasource-initialization=true")
.run((context) -> {
EntityManager em = context.getBean(EntityManagerFactory.class).createEntityManager();
NonAnnotatedEntity found = em.find(NonAnnotatedEntity.class, 2000L);
@@ -360,8 +360,7 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes
.withUserConfiguration(TestInitializedJpaConfiguration.class)
.withClassLoader(new HideDataScriptClassLoader())
.withPropertyValues("spring.jpa.show-sql=true", "spring.jpa.hibernate.ddl-auto:create-drop",
"spring.datasource.data:classpath:/city.sql",
"spring.datasource.initialization-order=after-jpa")
"spring.datasource.data:classpath:/city.sql", "spring.jpa.defer-datasource-initialization=true")
.run((context) -> {
// See CityListener
assertThat(context).hasSingleBean(City.class);
@@ -418,6 +417,7 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
@DependsOnDataSourceInitialization
static class TestInitializedJpaConfiguration {
private boolean called;