Skip to content

Commit d0494f5

Browse files
author
Phillip Webb
committed
Rework database auto-configure
Rework several aspects of database auto-configuration: - Use RelaxedPropertyResolver to obtain property values - Extract EmbeddedDatabaseConnection from EmbeddedDatabaseConfiguration - Rename several configuration classes for consistency Issue: #53028397
1 parent 3bbdc75 commit d0494f5

18 files changed

+504
-377
lines changed

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

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@
1616

1717
package org.springframework.boot.autoconfigure.jdbc;
1818

19+
import org.springframework.beans.factory.BeanClassLoaderAware;
1920
import org.springframework.beans.factory.BeanCreationException;
2021
import org.springframework.boot.context.properties.ConfigurationProperties;
21-
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
2222
import org.springframework.util.StringUtils;
2323

2424
/**
2525
* Base class for configuration of a database pool.
2626
*
2727
* @author Dave Syer
2828
*/
29-
@ConfigurationProperties(path = "spring.data")
30-
public abstract class AbstractDataSourceConfiguration {
29+
@ConfigurationProperties(path = "spring.datasource")
30+
public abstract class AbstractDataSourceConfiguration implements BeanClassLoaderAware {
3131

3232
private String driverClassName;
3333

@@ -49,19 +49,25 @@ public abstract class AbstractDataSourceConfiguration {
4949

5050
private boolean testOnReturn = false;
5151

52+
private ClassLoader classLoader;
53+
54+
@Override
55+
public void setBeanClassLoader(ClassLoader classLoader) {
56+
this.classLoader = classLoader;
57+
}
58+
5259
protected String getDriverClassName() {
5360
if (StringUtils.hasText(this.driverClassName)) {
5461
return this.driverClassName;
5562
}
56-
EmbeddedDatabaseType embeddedDatabaseType = EmbeddedDatabaseConfiguration
57-
.getEmbeddedDatabaseType();
58-
this.driverClassName = EmbeddedDatabaseConfiguration
59-
.getEmbeddedDatabaseDriverClass(embeddedDatabaseType);
63+
EmbeddedDatabaseConnection embeddedDatabaseConnection = EmbeddedDatabaseConnection
64+
.get(this.classLoader);
65+
this.driverClassName = embeddedDatabaseConnection.getDriverClassName();
6066
if (!StringUtils.hasText(this.driverClassName)) {
6167
throw new BeanCreationException(
6268
"Cannot determine embedded database driver class for database type "
63-
+ embeddedDatabaseType
64-
+ ". If you want an embedded database please put a supoprted one on the classpath.");
69+
+ embeddedDatabaseConnection + ". If you want an embedded "
70+
+ "database please put a supoprted one on the classpath.");
6571
}
6672
return this.driverClassName;
6773
}
@@ -70,15 +76,14 @@ protected String getUrl() {
7076
if (StringUtils.hasText(this.url)) {
7177
return this.url;
7278
}
73-
EmbeddedDatabaseType embeddedDatabaseType = EmbeddedDatabaseConfiguration
74-
.getEmbeddedDatabaseType();
75-
this.url = EmbeddedDatabaseConfiguration
76-
.getEmbeddedDatabaseUrl(embeddedDatabaseType);
79+
EmbeddedDatabaseConnection embeddedDatabaseConnection = EmbeddedDatabaseConnection
80+
.get(this.classLoader);
81+
this.url = embeddedDatabaseConnection.getUrl();
7782
if (!StringUtils.hasText(this.url)) {
7883
throw new BeanCreationException(
7984
"Cannot determine embedded database url for database type "
80-
+ embeddedDatabaseType
81-
+ ". If you want an embedded database please put a supported on on the classpath.");
85+
+ embeddedDatabaseConnection + ". If you want an embedded "
86+
+ "database please put a supported on on the classpath.");
8287
}
8388
return this.url;
8489
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@
3333
* recommended in high volume environments (the Tomcat DataSource is more reliable).
3434
*
3535
* @author Dave Syer
36+
* @see DataSourceAutoConfiguration
3637
*/
3738
@Configuration
38-
public class BasicDataSourceConfiguration extends AbstractDataSourceConfiguration {
39+
public class CommonsDataSourceConfiguration extends AbstractDataSourceConfiguration {
3940

40-
private static Log logger = LogFactory.getLog(BasicDataSourceConfiguration.class);
41+
private static Log logger = LogFactory.getLog(CommonsDataSourceConfiguration.class);
4142

4243
private BasicDataSource pool;
4344

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

Lines changed: 76 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,17 @@
2626
import org.apache.commons.logging.Log;
2727
import org.apache.commons.logging.LogFactory;
2828
import org.springframework.beans.factory.BeanFactoryUtils;
29+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
2930
import org.springframework.beans.factory.annotation.Autowired;
30-
import org.springframework.beans.factory.annotation.Value;
31+
import org.springframework.beans.factory.config.BeanDefinition;
32+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3133
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
3234
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3335
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3436
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
37+
import org.springframework.boot.bind.RelaxedPropertyResolver;
3538
import org.springframework.context.ApplicationContext;
39+
import org.springframework.context.EnvironmentAware;
3640
import org.springframework.context.annotation.Bean;
3741
import org.springframework.context.annotation.Condition;
3842
import org.springframework.context.annotation.ConditionContext;
@@ -61,7 +65,7 @@
6165
@Configuration
6266
@ConditionalOnClass(EmbeddedDatabaseType.class /* Spring JDBC */)
6367
@ConditionalOnMissingBean(DataSource.class)
64-
public class DataSourceAutoConfiguration {
68+
public class DataSourceAutoConfiguration implements EnvironmentAware {
6569

6670
private static Log logger = LogFactory.getLog(DataSourceAutoConfiguration.class);
6771

@@ -71,8 +75,66 @@ public class DataSourceAutoConfiguration {
7175
@Autowired
7276
private ApplicationContext applicationContext;
7377

78+
private RelaxedPropertyResolver environment;
79+
80+
@Override
81+
public void setEnvironment(Environment environment) {
82+
this.environment = new RelaxedPropertyResolver(environment, "spring.database.");
83+
}
84+
85+
@PostConstruct
86+
protected void initialize() throws Exception {
87+
if (this.dataSource == null) {
88+
logger.debug("No DataSource found so not initializing");
89+
return;
90+
}
91+
92+
String schema = this.environment.getProperty("schema");
93+
if (schema == null) {
94+
schema = "classpath*:schema-"
95+
+ this.environment.getProperty("platform", "all") + ".sql";
96+
}
97+
98+
List<Resource> resources = new ArrayList<Resource>();
99+
for (String schemaLocation : StringUtils.commaDelimitedListToStringArray(schema)) {
100+
resources.addAll(Arrays.asList(this.applicationContext
101+
.getResources(schemaLocation)));
102+
}
103+
104+
boolean exists = false;
105+
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
106+
for (Resource resource : resources) {
107+
if (resource.exists()) {
108+
exists = true;
109+
populator.addScript(resource);
110+
populator.setContinueOnError(true);
111+
}
112+
}
113+
114+
if (exists) {
115+
DatabasePopulatorUtils.execute(populator, this.dataSource);
116+
}
117+
}
118+
119+
/**
120+
* Determines if the {@code dataSource} being used by Spring was created from
121+
* {@link EmbeddedDataSourceConfiguration}.
122+
* @return true if the data source was auto-configured.
123+
*/
124+
public static boolean containsAutoConfiguredDataSource(
125+
ConfigurableListableBeanFactory beanFactory) {
126+
try {
127+
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("dataSource");
128+
return EmbeddedDataSourceConfiguration.class.getName().equals(
129+
beanDefinition.getFactoryBeanName());
130+
}
131+
catch (NoSuchBeanDefinitionException ex) {
132+
return false;
133+
}
134+
}
135+
74136
@Conditional(DataSourceAutoConfiguration.EmbeddedDatabaseCondition.class)
75-
@Import(EmbeddedDatabaseConfiguration.class)
137+
@Import(EmbeddedDataSourceConfiguration.class)
76138
protected static class EmbeddedConfiguration {
77139
}
78140

@@ -82,7 +144,7 @@ protected static class TomcatConfiguration {
82144
}
83145

84146
@Conditional(DataSourceAutoConfiguration.BasicDatabaseCondition.class)
85-
@Import(BasicDataSourceConfiguration.class)
147+
@Import(CommonsDataSourceConfiguration.class)
86148
protected static class DbcpConfiguration {
87149
}
88150

@@ -107,35 +169,6 @@ public NamedParameterJdbcOperations namedParameterJdbcTemplate() {
107169

108170
}
109171

110-
@Value("${spring.database.schema:classpath*:schema-${spring.database.platform:all}.sql}")
111-
private String schemaLocations = "";
112-
113-
@PostConstruct
114-
protected void initialize() throws Exception {
115-
if (this.dataSource == null) {
116-
logger.debug("No DataSource found so not initializing");
117-
return;
118-
}
119-
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
120-
boolean exists = false;
121-
List<Resource> resources = new ArrayList<Resource>();
122-
for (String location : StringUtils
123-
.commaDelimitedListToStringArray(this.schemaLocations)) {
124-
resources
125-
.addAll(Arrays.asList(this.applicationContext.getResources(location)));
126-
}
127-
for (Resource resource : resources) {
128-
if (resource.exists()) {
129-
exists = true;
130-
populator.addScript(resource);
131-
populator.setContinueOnError(true);
132-
}
133-
}
134-
if (exists) {
135-
DatabasePopulatorUtils.execute(populator, this.dataSource);
136-
}
137-
}
138-
139172
static abstract class NonEmbeddedDatabaseCondition extends SpringBootCondition {
140173

141174
protected abstract String getDataSourceClassName();
@@ -149,12 +182,13 @@ public Outcome getMatchOutcome(ConditionContext context,
149182
+ " DataSource class not found");
150183
}
151184

152-
String driverClassName = getDriverClassName(context.getEnvironment());
185+
String driverClassName = getDriverClassName(context.getEnvironment(),
186+
context.getClassLoader());
153187
if (driverClassName == null) {
154188
return Outcome.noMatch("no database driver");
155189
}
156190

157-
String url = getUrl(context.getEnvironment());
191+
String url = getUrl(context.getEnvironment(), context.getClassLoader());
158192
if (url == null) {
159193
return Outcome.noMatch("no database URL");
160194
}
@@ -166,24 +200,21 @@ public Outcome getMatchOutcome(ConditionContext context,
166200
return Outcome.match("missing database driver " + driverClassName);
167201
}
168202

169-
private String getDriverClassName(Environment environment) {
203+
private String getDriverClassName(Environment environment, ClassLoader classLoader) {
170204
String driverClassName = environment == null ? null : environment
171205
.getProperty("spring.database.driverClassName");
172206
if (driverClassName == null) {
173-
driverClassName = EmbeddedDatabaseConfiguration
174-
.getEmbeddedDatabaseDriverClass(EmbeddedDatabaseConfiguration
175-
.getEmbeddedDatabaseType());
207+
driverClassName = EmbeddedDatabaseConnection.get(classLoader)
208+
.getDriverClassName();
176209
}
177210
return driverClassName;
178211
}
179212

180-
private String getUrl(Environment environment) {
213+
private String getUrl(Environment environment, ClassLoader classLoader) {
181214
String url = (environment == null ? null : environment
182215
.getProperty("spring.database.url"));
183216
if (url == null) {
184-
url = EmbeddedDatabaseConfiguration
185-
.getEmbeddedDatabaseUrl(EmbeddedDatabaseConfiguration
186-
.getEmbeddedDatabaseType());
217+
url = EmbeddedDatabaseConnection.get(classLoader).getUrl();
187218
}
188219
return url;
189220
}
@@ -229,8 +260,8 @@ public Outcome getMatchOutcome(ConditionContext context,
229260
if (anyMatches(context, metadata, this.tomcatCondition, this.dbcpCondition)) {
230261
return Outcome.noMatch("existing non-embedded database detected");
231262
}
232-
EmbeddedDatabaseType type = EmbeddedDatabaseConfiguration
233-
.getEmbeddedDatabaseType();
263+
EmbeddedDatabaseType type = EmbeddedDatabaseConnection.get(
264+
context.getClassLoader()).getType();
234265
if (type == null) {
235266
return Outcome.noMatch("no embedded database detected");
236267
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2012-2013 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.PreDestroy;
20+
import javax.sql.DataSource;
21+
22+
import org.springframework.beans.factory.BeanClassLoaderAware;
23+
import org.springframework.context.annotation.Bean;
24+
import org.springframework.context.annotation.Configuration;
25+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
26+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
27+
28+
/**
29+
* Configuration for embedded data sources.
30+
*
31+
* @author Phillip Webb
32+
* @see DataSourceAutoConfiguration
33+
*/
34+
@Configuration
35+
public class EmbeddedDataSourceConfiguration implements BeanClassLoaderAware {
36+
37+
private EmbeddedDatabase database;
38+
39+
private ClassLoader classLoader;
40+
41+
@Override
42+
public void setBeanClassLoader(ClassLoader classLoader) {
43+
this.classLoader = classLoader;
44+
}
45+
46+
@Bean
47+
public DataSource dataSource() {
48+
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
49+
.setType(EmbeddedDatabaseConnection.get(this.classLoader).getType());
50+
this.database = builder.build();
51+
return this.database;
52+
}
53+
54+
@PreDestroy
55+
public void close() {
56+
if (this.database != null) {
57+
this.database.shutdown();
58+
}
59+
}
60+
61+
}

0 commit comments

Comments
 (0)