Browse Source
Rework several aspects of database auto-configuration: - Use RelaxedPropertyResolver to obtain property values - Extract EmbeddedDatabaseConnection from EmbeddedDatabaseConfiguration - Rename several configuration classes for consistency Issue: #53028397pull/50/head
18 changed files with 504 additions and 377 deletions
@ -0,0 +1,61 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2013 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 |
||||||
|
* |
||||||
|
* http://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 javax.annotation.PreDestroy; |
||||||
|
import javax.sql.DataSource; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.BeanClassLoaderAware; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; |
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; |
||||||
|
|
||||||
|
/** |
||||||
|
* Configuration for embedded data sources. |
||||||
|
* |
||||||
|
* @author Phillip Webb |
||||||
|
* @see DataSourceAutoConfiguration |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
public class EmbeddedDataSourceConfiguration implements BeanClassLoaderAware { |
||||||
|
|
||||||
|
private EmbeddedDatabase database; |
||||||
|
|
||||||
|
private ClassLoader classLoader; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setBeanClassLoader(ClassLoader classLoader) { |
||||||
|
this.classLoader = classLoader; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public DataSource dataSource() { |
||||||
|
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder() |
||||||
|
.setType(EmbeddedDatabaseConnection.get(this.classLoader).getType()); |
||||||
|
this.database = builder.build(); |
||||||
|
return this.database; |
||||||
|
} |
||||||
|
|
||||||
|
@PreDestroy |
||||||
|
public void close() { |
||||||
|
if (this.database != null) { |
||||||
|
this.database.shutdown(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,96 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2012-2013 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 |
|
||||||
* |
|
||||||
* http://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.LinkedHashMap; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import javax.annotation.PreDestroy; |
|
||||||
import javax.sql.DataSource; |
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
|
||||||
import org.springframework.context.annotation.Bean; |
|
||||||
import org.springframework.context.annotation.Configuration; |
|
||||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; |
|
||||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; |
|
||||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; |
|
||||||
import org.springframework.util.ClassUtils; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@link EnableAutoConfiguration Auto-configuration} for embedded databases. |
|
||||||
* |
|
||||||
* @author Phillip Webb |
|
||||||
*/ |
|
||||||
@Configuration |
|
||||||
public class EmbeddedDatabaseConfiguration { |
|
||||||
|
|
||||||
private static final Map<EmbeddedDatabaseType, String> EMBEDDED_DATABASE_DRIVER_CLASSES; |
|
||||||
static { |
|
||||||
Map<EmbeddedDatabaseType, String> drivers = new LinkedHashMap<EmbeddedDatabaseType, String>(); |
|
||||||
drivers.put(EmbeddedDatabaseType.H2, "org.h2.Driver"); |
|
||||||
drivers.put(EmbeddedDatabaseType.DERBY, "org.apache.derby.jdbc.EmbeddedDriver"); |
|
||||||
drivers.put(EmbeddedDatabaseType.HSQL, "org.hsqldb.jdbcDriver"); |
|
||||||
EMBEDDED_DATABASE_DRIVER_CLASSES = drivers; |
|
||||||
} |
|
||||||
|
|
||||||
private static final Map<EmbeddedDatabaseType, String> EMBEDDED_DATABASE_URLS; |
|
||||||
static { |
|
||||||
Map<EmbeddedDatabaseType, String> urls = new LinkedHashMap<EmbeddedDatabaseType, String>(); |
|
||||||
urls.put(EmbeddedDatabaseType.H2, "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1"); |
|
||||||
urls.put(EmbeddedDatabaseType.DERBY, "jdbc:derby:memory:testdb;create=true"); |
|
||||||
urls.put(EmbeddedDatabaseType.HSQL, "jdbc:hsqldb:mem:testdb"); |
|
||||||
EMBEDDED_DATABASE_URLS = urls; |
|
||||||
} |
|
||||||
|
|
||||||
private EmbeddedDatabase database; |
|
||||||
|
|
||||||
@Bean |
|
||||||
public DataSource dataSource() { |
|
||||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder() |
|
||||||
.setType(getEmbeddedDatabaseType()); |
|
||||||
this.database = builder.build(); |
|
||||||
return this.database; |
|
||||||
} |
|
||||||
|
|
||||||
@PreDestroy |
|
||||||
public void close() { |
|
||||||
if (this.database != null) { |
|
||||||
this.database.shutdown(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static String getEmbeddedDatabaseDriverClass( |
|
||||||
EmbeddedDatabaseType embeddedDatabaseType) { |
|
||||||
return EMBEDDED_DATABASE_DRIVER_CLASSES.get(embeddedDatabaseType); |
|
||||||
} |
|
||||||
|
|
||||||
public static String getEmbeddedDatabaseUrl(EmbeddedDatabaseType embeddedDatabaseType) { |
|
||||||
return EMBEDDED_DATABASE_URLS.get(embeddedDatabaseType); |
|
||||||
} |
|
||||||
|
|
||||||
public static EmbeddedDatabaseType getEmbeddedDatabaseType() { |
|
||||||
for (Map.Entry<EmbeddedDatabaseType, String> entry : EMBEDDED_DATABASE_DRIVER_CLASSES |
|
||||||
.entrySet()) { |
|
||||||
if (ClassUtils.isPresent(entry.getValue(), |
|
||||||
EmbeddedDatabaseConfiguration.class.getClassLoader())) { |
|
||||||
return entry.getKey(); |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -0,0 +1,109 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2013 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 |
||||||
|
* |
||||||
|
* http://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 org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; |
||||||
|
import org.springframework.util.ClassUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* Connection details for {@link EmbeddedDatabaseType embedded databases}. |
||||||
|
* |
||||||
|
* @author Phillip Webb |
||||||
|
* @author Dave Syer |
||||||
|
* @see #get(ClassLoader) |
||||||
|
*/ |
||||||
|
public enum EmbeddedDatabaseConnection { |
||||||
|
|
||||||
|
/** |
||||||
|
* No Connection. |
||||||
|
*/ |
||||||
|
NONE(null, null, null), |
||||||
|
|
||||||
|
/** |
||||||
|
* H2 Database Connection. |
||||||
|
*/ |
||||||
|
H2(EmbeddedDatabaseType.H2, "org.h2.Driver", "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1"), |
||||||
|
|
||||||
|
/** |
||||||
|
* Derby Database Connection. |
||||||
|
*/ |
||||||
|
DERBY(EmbeddedDatabaseType.DERBY, "org.apache.derby.jdbc.EmbeddedDriver", |
||||||
|
"jdbc:derby:memory:testdb;create=true"), |
||||||
|
|
||||||
|
/** |
||||||
|
* HSQL Database Connection. |
||||||
|
*/ |
||||||
|
HSQL(EmbeddedDatabaseType.HSQL, "org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem:testdb"); |
||||||
|
|
||||||
|
private final EmbeddedDatabaseType type; |
||||||
|
|
||||||
|
private final String driverClass; |
||||||
|
|
||||||
|
private final String url; |
||||||
|
|
||||||
|
private EmbeddedDatabaseConnection(EmbeddedDatabaseType type, String driverClass, |
||||||
|
String url) { |
||||||
|
this.type = type; |
||||||
|
this.driverClass = driverClass; |
||||||
|
this.url = url; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the driver class name. |
||||||
|
*/ |
||||||
|
public String getDriverClassName() { |
||||||
|
return this.driverClass; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the {@link EmbeddedDatabaseType} for the connection. |
||||||
|
*/ |
||||||
|
public EmbeddedDatabaseType getType() { |
||||||
|
return this.type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the URL for the connection. |
||||||
|
*/ |
||||||
|
public String getUrl() { |
||||||
|
return this.url; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Override for testing. |
||||||
|
*/ |
||||||
|
static EmbeddedDatabaseConnection override; |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the most suitable {@link EmbeddedDatabaseConnection} for the given class
|
||||||
|
* loader. |
||||||
|
* @param classLoader the class loader used to check for classes |
||||||
|
* @return an {@link EmbeddedDatabaseConnection} or {@link #NONE}. |
||||||
|
*/ |
||||||
|
public static EmbeddedDatabaseConnection get(ClassLoader classLoader) { |
||||||
|
if (override != null) { |
||||||
|
return override; |
||||||
|
} |
||||||
|
for (EmbeddedDatabaseConnection candidate : EmbeddedDatabaseConnection.values()) { |
||||||
|
if (candidate != NONE |
||||||
|
&& ClassUtils.isPresent(candidate.getDriverClassName(), classLoader)) { |
||||||
|
return candidate; |
||||||
|
} |
||||||
|
} |
||||||
|
return NONE; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,162 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2013 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 |
||||||
|
* |
||||||
|
* http://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 javax.sql.DataSource; |
||||||
|
|
||||||
|
import org.junit.After; |
||||||
|
import org.junit.Test; |
||||||
|
import org.springframework.boot.TestUtils; |
||||||
|
import org.springframework.boot.autoconfigure.ComponentScanDetectorConfiguration; |
||||||
|
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; |
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; |
||||||
|
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; |
||||||
|
import org.springframework.boot.autoconfigure.orm.jpa.test.City; |
||||||
|
import org.springframework.context.ApplicationContext; |
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.ComponentScan; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.orm.jpa.JpaTransactionManager; |
||||||
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; |
||||||
|
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; |
||||||
|
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor; |
||||||
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; |
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo; |
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertNotNull; |
||||||
|
import static org.junit.Assert.assertThat; |
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
|
||||||
|
/** |
||||||
|
* Base for JPA tests and tests for {@link JpaBaseConfiguration}. |
||||||
|
* |
||||||
|
* @author Phillip Webb |
||||||
|
* @author Dave Syer |
||||||
|
*/ |
||||||
|
public abstract class AbstractJpaAutoConfigurationTests { |
||||||
|
|
||||||
|
protected AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); |
||||||
|
|
||||||
|
@After |
||||||
|
public void close() { |
||||||
|
this.context.close(); |
||||||
|
} |
||||||
|
|
||||||
|
protected abstract Class<?> getAutoConfigureClass(); |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testEntityManagerCreated() throws Exception { |
||||||
|
setupTestConfiguration(); |
||||||
|
this.context.refresh(); |
||||||
|
assertNotNull(this.context.getBean(DataSource.class)); |
||||||
|
assertNotNull(this.context.getBean(JpaTransactionManager.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testDataSourceTransactionManagerNotCreated() throws Exception { |
||||||
|
setupTestConfiguration(); |
||||||
|
this.context.register(DataSourceTransactionManagerAutoConfiguration.class); |
||||||
|
this.context.refresh(); |
||||||
|
assertNotNull(this.context.getBean(DataSource.class)); |
||||||
|
assertTrue(this.context.getBean("transactionManager") instanceof JpaTransactionManager); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testOpenEntityManagerInViewInterceptorCreated() throws Exception { |
||||||
|
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); |
||||||
|
context.register(TestConfiguration.class, |
||||||
|
ComponentScanDetectorConfiguration.class, |
||||||
|
EmbeddedDataSourceConfiguration.class, |
||||||
|
PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); |
||||||
|
context.refresh(); |
||||||
|
assertNotNull(context.getBean(OpenEntityManagerInViewInterceptor.class)); |
||||||
|
context.close(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testOpenEntityManagerInViewInterceptorNotRegisteredWhenFilterPresent() |
||||||
|
throws Exception { |
||||||
|
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); |
||||||
|
context.register(TestFilterConfiguration.class, |
||||||
|
ComponentScanDetectorConfiguration.class, |
||||||
|
EmbeddedDataSourceConfiguration.class, |
||||||
|
PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); |
||||||
|
context.refresh(); |
||||||
|
assertEquals(0, getInterceptorBeans(context).length); |
||||||
|
context.close(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testOpenEntityManagerInViewInterceptorNotRegisteredWhenExplicitlyOff() |
||||||
|
throws Exception { |
||||||
|
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); |
||||||
|
TestUtils.addEnviroment(context, "spring.jpa.open_in_view:false"); |
||||||
|
context.register(TestConfiguration.class, |
||||||
|
ComponentScanDetectorConfiguration.class, |
||||||
|
EmbeddedDataSourceConfiguration.class, |
||||||
|
PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); |
||||||
|
context.refresh(); |
||||||
|
assertEquals(0, getInterceptorBeans(context).length); |
||||||
|
context.close(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void customJpaProperties() throws Exception { |
||||||
|
TestUtils.addEnviroment(this.context, "spring.jpa.properties.a:b", |
||||||
|
"spring.jpa.properties.c:d"); |
||||||
|
setupTestConfiguration(); |
||||||
|
this.context.refresh(); |
||||||
|
LocalContainerEntityManagerFactoryBean bean = this.context |
||||||
|
.getBean(LocalContainerEntityManagerFactoryBean.class); |
||||||
|
Map<String, Object> map = bean.getJpaPropertyMap(); |
||||||
|
assertThat(map.get("a"), equalTo((Object) "b")); |
||||||
|
assertThat(map.get("c"), equalTo((Object) "d")); |
||||||
|
} |
||||||
|
|
||||||
|
protected void setupTestConfiguration() { |
||||||
|
this.context.register(TestConfiguration.class, |
||||||
|
ComponentScanDetectorConfiguration.class, |
||||||
|
EmbeddedDataSourceConfiguration.class, |
||||||
|
PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); |
||||||
|
} |
||||||
|
|
||||||
|
private String[] getInterceptorBeans(ApplicationContext context) { |
||||||
|
return context.getBeanNamesForType(OpenEntityManagerInViewInterceptor.class); |
||||||
|
} |
||||||
|
|
||||||
|
@Configuration |
||||||
|
@ComponentScan(basePackageClasses = { City.class }) |
||||||
|
protected static class TestConfiguration { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Configuration |
||||||
|
@ComponentScan(basePackageClasses = { City.class }) |
||||||
|
protected static class TestFilterConfiguration { |
||||||
|
|
||||||
|
@Bean |
||||||
|
public OpenEntityManagerInViewFilter openEntityManagerInViewFilter() { |
||||||
|
return new OpenEntityManagerInViewFilter(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue