Skip to content

Commit 6dbcc33

Browse files
committed
1 parent 235daf8 commit 6dbcc33

10 files changed

+186
-292
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java

+5-19
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
import javax.sql.DataSource;
2020
import javax.sql.XADataSource;
2121

22-
import org.apache.commons.logging.Log;
23-
import org.apache.commons.logging.LogFactory;
24-
2522
import org.springframework.beans.factory.BeanFactoryUtils;
2623
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
2724
import org.springframework.beans.factory.config.BeanDefinition;
@@ -34,11 +31,8 @@
3431
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3532
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3633
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
37-
import org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerPostProcessor.Registrar;
3834
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration;
3935
import org.springframework.boot.context.properties.EnableConfigurationProperties;
40-
import org.springframework.context.ApplicationContext;
41-
import org.springframework.context.annotation.Bean;
4236
import org.springframework.context.annotation.Condition;
4337
import org.springframework.context.annotation.ConditionContext;
4438
import org.springframework.context.annotation.Conditional;
@@ -60,19 +54,9 @@
6054
@Configuration
6155
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
6256
@EnableConfigurationProperties(DataSourceProperties.class)
63-
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
57+
@Import(DataSourcePoolMetadataProvidersConfiguration.class)
6458
public class DataSourceAutoConfiguration {
6559

66-
private static final Log logger = LogFactory
67-
.getLog(DataSourceAutoConfiguration.class);
68-
69-
@Bean
70-
@ConditionalOnMissingBean
71-
public DataSourceInitializer dataSourceInitializer(DataSourceProperties properties,
72-
ApplicationContext applicationContext) {
73-
return new DataSourceInitializer(properties, applicationContext);
74-
}
75-
7660
/**
7761
* Determines if the {@code dataSource} being used by Spring was created from
7862
* {@link EmbeddedDataSourceConfiguration}.
@@ -94,7 +78,8 @@ public static boolean containsAutoConfiguredDataSource(
9478
@Configuration
9579
@Conditional(EmbeddedDatabaseCondition.class)
9680
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
97-
@Import(EmbeddedDataSourceConfiguration.class)
81+
@Import({ EmbeddedDataSourceConfiguration.class,
82+
DataSourceInitializationConfiguration.class })
9883
protected static class EmbeddedDatabaseConfiguration {
9984

10085
}
@@ -104,7 +89,8 @@ protected static class EmbeddedDatabaseConfiguration {
10489
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
10590
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
10691
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
107-
DataSourceJmxConfiguration.class })
92+
DataSourceJmxConfiguration.class,
93+
DataSourceInitializationConfiguration.class })
10894
protected static class PooledDataSourceConfiguration {
10995

11096
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.jdbc;
18+
19+
import org.springframework.beans.factory.config.BeanDefinition;
20+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
21+
import org.springframework.beans.factory.support.GenericBeanDefinition;
22+
import org.springframework.context.annotation.Configuration;
23+
import org.springframework.context.annotation.Import;
24+
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
25+
import org.springframework.core.type.AnnotationMetadata;
26+
27+
/**
28+
* Configures DataSource initialization.
29+
*
30+
* @author Stephane Nicoll
31+
*/
32+
@Configuration
33+
@Import({ DataSourceInitializationConfiguration.Registrar.class,
34+
DataSourceInitializerInvoker.class })
35+
class DataSourceInitializationConfiguration {
36+
37+
38+
/**
39+
* {@link ImportBeanDefinitionRegistrar} to register the
40+
* {@link DataSourceInitializerPostProcessor} without causing early bean instantiation
41+
* issues.
42+
*/
43+
static class Registrar implements ImportBeanDefinitionRegistrar {
44+
45+
private static final String BEAN_NAME = "dataSourceInitializerPostProcessor";
46+
47+
@Override
48+
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
49+
BeanDefinitionRegistry registry) {
50+
if (!registry.containsBeanDefinition(BEAN_NAME)) {
51+
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
52+
beanDefinition.setBeanClass(DataSourceInitializerPostProcessor.class);
53+
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
54+
// We don't need this one to be post processed otherwise it can cause a
55+
// cascade of bean instantiation that we would rather avoid.
56+
beanDefinition.setSynthetic(true);
57+
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
58+
}
59+
}
60+
61+
}
62+
63+
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializedEvent.java

-43
This file was deleted.

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializer.java

+43-61
Original file line numberDiff line numberDiff line change
@@ -20,107 +20,89 @@
2020
import java.util.Collections;
2121
import java.util.List;
2222

23-
import javax.annotation.PostConstruct;
2423
import javax.sql.DataSource;
2524

2625
import org.apache.commons.logging.Log;
2726
import org.apache.commons.logging.LogFactory;
2827

2928
import org.springframework.boot.context.config.ResourceNotFoundException;
30-
import org.springframework.context.ApplicationContext;
31-
import org.springframework.context.ApplicationListener;
29+
import org.springframework.core.io.DefaultResourceLoader;
3230
import org.springframework.core.io.Resource;
31+
import org.springframework.core.io.ResourceLoader;
3332
import org.springframework.jdbc.config.SortedResourcesFactoryBean;
3433
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
3534
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
3635
import org.springframework.util.StringUtils;
3736

3837
/**
39-
* Bean to handle {@link DataSource} initialization by running {@literal schema-*.sql} on
40-
* {@link PostConstruct} and {@literal data-*.sql} SQL scripts on a
41-
* {@link DataSourceInitializedEvent}.
38+
* Initialize a {@link DataSource} based on a matching {@link DataSourceProperties}
39+
* config.
4240
*
43-
* @author Dave Syer
44-
* @author Phillip Webb
45-
* @author Eddú Meléndez
4641
* @author Stephane Nicoll
47-
* @author Kazuki Shimizu
48-
* @since 1.1.0
49-
* @see DataSourceAutoConfiguration
42+
* @since 2.0.0
5043
*/
51-
class DataSourceInitializer implements ApplicationListener<DataSourceInitializedEvent> {
44+
public class DataSourceInitializer {
5245

5346
private static final Log logger = LogFactory.getLog(DataSourceInitializer.class);
5447

55-
private final DataSourceProperties properties;
56-
57-
private final ApplicationContext applicationContext;
58-
59-
private DataSource dataSource;
48+
private final DataSource dataSource;
6049

61-
private boolean initialized = false;
50+
private final DataSourceProperties properties;
6251

63-
DataSourceInitializer(DataSourceProperties properties,
64-
ApplicationContext applicationContext) {
52+
private final ResourceLoader resourceLoader;
53+
54+
/**
55+
* Create a new instance with the {@link DataSource} to initialize and its matching
56+
* {@link DataSourceProperties configuration}.
57+
* @param dataSource the datasource to initialize
58+
* @param properties the matching configuration
59+
* @param resourceLoader the resource loader to use (can be null)
60+
*/
61+
public DataSourceInitializer(DataSource dataSource, DataSourceProperties properties,
62+
ResourceLoader resourceLoader) {
63+
this.dataSource = dataSource;
6564
this.properties = properties;
66-
this.applicationContext = applicationContext;
65+
this.resourceLoader = (resourceLoader != null ? resourceLoader
66+
: new DefaultResourceLoader());
6767
}
6868

69-
@PostConstruct
70-
public void init() {
69+
/**
70+
* Create a new instance with the {@link DataSource} to initialize and its matching
71+
* {@link DataSourceProperties configuration}.
72+
* @param dataSource the datasource to initialize
73+
* @param properties the matching configuration
74+
*/
75+
public DataSourceInitializer(DataSource dataSource, DataSourceProperties properties) {
76+
this(dataSource, properties, null);
77+
}
78+
79+
/**
80+
* Create the schema if necessary.
81+
* @see DataSourceProperties#getSchema()
82+
*/
83+
public void createSchema() {
7184
if (!this.properties.isInitialize()) {
7285
logger.debug("Initialization disabled (not running DDL scripts)");
7386
return;
7487
}
75-
if (this.applicationContext.getBeanNamesForType(DataSource.class, false,
76-
false).length > 0) {
77-
this.dataSource = this.applicationContext.getBean(DataSource.class);
78-
}
79-
if (this.dataSource == null) {
80-
logger.debug("No DataSource found so not initializing");
81-
return;
82-
}
83-
runSchemaScripts();
84-
}
85-
86-
private void runSchemaScripts() {
8788
List<Resource> scripts = getScripts("spring.datasource.schema",
8889
this.properties.getSchema(), "schema");
8990
if (!scripts.isEmpty()) {
9091
String username = this.properties.getSchemaUsername();
9192
String password = this.properties.getSchemaPassword();
9293
runScripts(scripts, username, password);
93-
try {
94-
this.applicationContext
95-
.publishEvent(new DataSourceInitializedEvent(this.dataSource));
96-
// The listener might not be registered yet, so don't rely on it.
97-
if (!this.initialized) {
98-
runDataScripts();
99-
this.initialized = true;
100-
}
101-
}
102-
catch (IllegalStateException ex) {
103-
logger.warn("Could not send event to complete DataSource initialization ("
104-
+ ex.getMessage() + ")");
105-
}
10694
}
10795
}
10896

109-
@Override
110-
public void onApplicationEvent(DataSourceInitializedEvent event) {
97+
/**
98+
* Initialize the schema if necessary.
99+
* @see DataSourceProperties#getData()
100+
*/
101+
public void initSchema() {
111102
if (!this.properties.isInitialize()) {
112103
logger.debug("Initialization disabled (not running data scripts)");
113104
return;
114105
}
115-
// NOTE the event can happen more than once and
116-
// the event datasource is not used here
117-
if (!this.initialized) {
118-
runDataScripts();
119-
this.initialized = true;
120-
}
121-
}
122-
123-
private void runDataScripts() {
124106
List<Resource> scripts = getScripts("spring.datasource.data",
125107
this.properties.getData(), "data");
126108
String username = this.properties.getDataUsername();
@@ -159,7 +141,7 @@ else if (validate) {
159141
private Resource[] doGetResources(String location) {
160142
try {
161143
SortedResourcesFactoryBean factory = new SortedResourcesFactoryBean(
162-
this.applicationContext, Collections.singletonList(location));
144+
this.resourceLoader, Collections.singletonList(location));
163145
factory.afterPropertiesSet();
164146
return factory.getObject();
165147
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.jdbc;
18+
19+
import javax.annotation.PostConstruct;
20+
import javax.sql.DataSource;
21+
22+
import org.springframework.beans.factory.InitializingBean;
23+
import org.springframework.beans.factory.ObjectProvider;
24+
import org.springframework.beans.factory.SmartInitializingSingleton;
25+
import org.springframework.context.ApplicationContext;
26+
27+
/**
28+
* Bean to handle {@link DataSource} initialization by running {@literal schema-*.sql} on
29+
* {@link InitializingBean#afterPropertiesSet()} and {@literal data-*.sql} SQL scripts on
30+
* a {@link SmartInitializingSingleton#afterSingletonsInstantiated()}.
31+
*
32+
* @author Dave Syer
33+
* @author Phillip Webb
34+
* @author Eddú Meléndez
35+
* @author Stephane Nicoll
36+
* @author Kazuki Shimizu
37+
* @since 1.1.0
38+
* @see DataSourceAutoConfiguration
39+
*/
40+
class DataSourceInitializerInvoker implements InitializingBean {
41+
42+
private final DataSourceInitializer dataSourceInitializer;
43+
44+
DataSourceInitializerInvoker(ObjectProvider<DataSource> dataSource,
45+
DataSourceProperties properties,
46+
ApplicationContext applicationContext) {
47+
DataSource ds = dataSource.getIfAvailable();
48+
this.dataSourceInitializer = ds != null
49+
? new DataSourceInitializer(ds, properties, applicationContext) : null;
50+
}
51+
52+
@Override
53+
public void afterPropertiesSet() {
54+
if (this.dataSourceInitializer != null) {
55+
this.dataSourceInitializer.createSchema();
56+
this.dataSourceInitializer.initSchema();
57+
}
58+
}
59+
60+
}

0 commit comments

Comments
 (0)