diff --git a/spring-boot-devtools/pom.xml b/spring-boot-devtools/pom.xml
index 4a3a73e458..db189e46ec 100644
--- a/spring-boot-devtools/pom.xml
+++ b/spring-boot-devtools/pom.xml
@@ -44,6 +44,16 @@
spring-jdbc
true
+
+ org.springframework
+ spring-orm
+ true
+
+
+ org.hibernate
+ hibernate-entitymanager
+ true
+
org.springframework
spring-web
diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java
index 1a5c712918..0e76695220 100644
--- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java
+++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java
@@ -27,6 +27,8 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.data.jpa.EntityManagerFactoryDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration.DevToolsDataSourceCondition;
@@ -34,6 +36,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
+import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
/**
* {@link EnableAutoConfiguration Auto-configuration} for DevTools-specific
@@ -54,6 +58,23 @@ public class DevToolsDataSourceAutoConfiguration {
dataSourceProperties);
}
+ /**
+ * Additional configuration to ensure that
+ * {@link javax.persistence.EntityManagerFactory} beans depend on the
+ * {@code inMemoryDatabaseShutdownExecutor} bean.
+ */
+ @Configuration
+ @ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
+ @ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
+ static class DatabaseShutdownExecutorJpaDependencyConfiguration
+ extends EntityManagerFactoryDependsOnPostProcessor {
+
+ DatabaseShutdownExecutorJpaDependencyConfiguration() {
+ super("inMemoryDatabaseShutdownExecutor");
+ }
+
+ }
+
static final class NonEmbeddedInMemoryDatabaseShutdownExecutor
implements DisposableBean {
diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfigurationTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfigurationTests.java
index 2371550a63..700f39509e 100644
--- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfigurationTests.java
+++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfigurationTests.java
@@ -20,9 +20,11 @@ import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
+import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.junit.Test;
+import org.mockito.InOrder;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -36,6 +38,7 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -49,7 +52,7 @@ public class DevToolsDataSourceAutoConfigurationTests {
@Test
public void embeddedDatabaseIsNotShutDown() throws SQLException {
- ConfigurableApplicationContext context = createContext("org.h2.Driver",
+ ConfigurableApplicationContext context = createContextWithDriver("org.h2.Driver",
EmbeddedDatabaseConfiguration.class);
DataSource dataSource = context.getBean(DataSource.class);
context.close();
@@ -58,8 +61,8 @@ public class DevToolsDataSourceAutoConfigurationTests {
@Test
public void externalDatabaseIsNotShutDown() throws SQLException {
- ConfigurableApplicationContext context = createContext("org.postgresql.Driver",
- DataSourceConfiguration.class);
+ ConfigurableApplicationContext context = createContextWithDriver(
+ "org.postgresql.Driver", DataSourceConfiguration.class);
DataSource dataSource = context.getBean(DataSource.class);
context.close();
verify(dataSource, times(0)).getConnection();
@@ -67,7 +70,35 @@ public class DevToolsDataSourceAutoConfigurationTests {
@Test
public void nonEmbeddedInMemoryDatabaseIsShutDown() throws SQLException {
- ConfigurableApplicationContext context = createContext("org.h2.Driver",
+ ConfigurableApplicationContext context = createContextWithDriver("org.h2.Driver",
+ DataSourceConfiguration.class);
+ DataSource dataSource = context.getBean(DataSource.class);
+ Connection connection = mock(Connection.class);
+ given(dataSource.getConnection()).willReturn(connection);
+ Statement statement = mock(Statement.class);
+ given(connection.createStatement()).willReturn(statement);
+ context.close();
+ verify(statement).execute("SHUTDOWN");
+ }
+
+ @Test
+ public void nonEmbeddedInMemoryDatabaseConfiguredWithDriverIsShutDown()
+ throws SQLException {
+ ConfigurableApplicationContext context = createContextWithDriver("org.h2.Driver",
+ DataSourceConfiguration.class);
+ DataSource dataSource = context.getBean(DataSource.class);
+ Connection connection = mock(Connection.class);
+ given(dataSource.getConnection()).willReturn(connection);
+ Statement statement = mock(Statement.class);
+ given(connection.createStatement()).willReturn(statement);
+ context.close();
+ verify(statement).execute("SHUTDOWN");
+ }
+
+ @Test
+ public void nonEmbeddedInMemoryDatabaseConfiguredWithUrlIsShutDown()
+ throws SQLException {
+ ConfigurableApplicationContext context = createContextWithUrl("jdbc:h2:mem:test",
DataSourceConfiguration.class);
DataSource dataSource = context.getBean(DataSource.class);
Connection connection = mock(Connection.class);
@@ -87,13 +118,40 @@ public class DevToolsDataSourceAutoConfigurationTests {
is(0));
}
- private ConfigurableApplicationContext createContext(String driver,
+ @Test
+ public void entityManagerFactoryIsClosedBeforeDatabaseIsShutDown()
+ throws SQLException {
+ ConfigurableApplicationContext context = createContextWithUrl("jdbc:h2:mem:test",
+ DataSourceConfiguration.class, EntityManagerFactoryConfiguration.class);
+ DataSource dataSource = context.getBean(DataSource.class);
+ Connection connection = mock(Connection.class);
+ given(dataSource.getConnection()).willReturn(connection);
+ Statement statement = mock(Statement.class);
+ given(connection.createStatement()).willReturn(statement);
+ EntityManagerFactory entityManagerFactory = context
+ .getBean(EntityManagerFactory.class);
+ context.close();
+ InOrder inOrder = inOrder(statement, entityManagerFactory);
+ inOrder.verify(statement).execute("SHUTDOWN");
+ inOrder.verify(entityManagerFactory).close();
+ }
+
+ private ConfigurableApplicationContext createContextWithDriver(String driver,
+ Class>... classes) {
+ return createContext("spring.datasource.driver-class-name:" + driver, classes);
+ }
+
+ private ConfigurableApplicationContext createContextWithUrl(String url,
+ Class>... classes) {
+ return createContext("spring.datasource.url:" + url, classes);
+ }
+
+ private ConfigurableApplicationContext createContext(String property,
Class>... classes) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(classes);
context.register(DevToolsDataSourceAutoConfiguration.class);
- EnvironmentTestUtils.addEnvironment(context,
- "spring.datasource.driver-class-name:" + driver);
+ EnvironmentTestUtils.addEnvironment(context, property);
context.refresh();
return context;
}
@@ -113,7 +171,7 @@ public class DevToolsDataSourceAutoConfigurationTests {
static class DataSourceConfiguration {
@Bean
- public DataSource in() {
+ public DataSource dataSource() {
return mock(DataSource.class);
}
@@ -123,10 +181,19 @@ public class DevToolsDataSourceAutoConfigurationTests {
static class NoDataSourcePropertiesConfiguration {
@Bean
- public DataSource in() {
+ public DataSource dataSource() {
return mock(DataSource.class);
}
}
+ @Configuration
+ static class EntityManagerFactoryConfiguration {
+
+ @Bean
+ public EntityManagerFactory entityManagerFactory() {
+ return mock(EntityManagerFactory.class);
+ }
+ }
+
}