Skip to content

Commit 367a4ed

Browse files
committed
Merge branch '1.3.x'
2 parents ef5087c + 40ffe41 commit 367a4ed

3 files changed

Lines changed: 108 additions & 10 deletions

File tree

spring-boot-devtools/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@
4444
<artifactId>spring-jdbc</artifactId>
4545
<optional>true</optional>
4646
</dependency>
47+
<dependency>
48+
<groupId>org.springframework</groupId>
49+
<artifactId>spring-orm</artifactId>
50+
<optional>true</optional>
51+
</dependency>
52+
<dependency>
53+
<groupId>org.hibernate</groupId>
54+
<artifactId>hibernate-entitymanager</artifactId>
55+
<optional>true</optional>
56+
</dependency>
4757
<dependency>
4858
<groupId>org.springframework</groupId>
4959
<artifactId>spring-web</artifactId>

spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,17 @@
2727
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2828
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
2929
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
30+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
31+
import org.springframework.boot.autoconfigure.data.jpa.EntityManagerFactoryDependsOnPostProcessor;
3032
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
3133
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
3234
import org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration.DevToolsDataSourceCondition;
3335
import org.springframework.context.annotation.Bean;
3436
import org.springframework.context.annotation.Conditional;
3537
import org.springframework.context.annotation.Configuration;
3638
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
39+
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
40+
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
3741

3842
/**
3943
* {@link EnableAutoConfiguration Auto-configuration} for DevTools-specific
@@ -54,6 +58,23 @@ NonEmbeddedInMemoryDatabaseShutdownExecutor inMemoryDatabaseShutdownExecutor(
5458
dataSourceProperties);
5559
}
5660

61+
/**
62+
* Additional configuration to ensure that
63+
* {@link javax.persistence.EntityManagerFactory} beans depend on the
64+
* {@code inMemoryDatabaseShutdownExecutor} bean.
65+
*/
66+
@Configuration
67+
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
68+
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
69+
static class DatabaseShutdownExecutorJpaDependencyConfiguration
70+
extends EntityManagerFactoryDependsOnPostProcessor {
71+
72+
DatabaseShutdownExecutorJpaDependencyConfiguration() {
73+
super("inMemoryDatabaseShutdownExecutor");
74+
}
75+
76+
}
77+
5778
static final class NonEmbeddedInMemoryDatabaseShutdownExecutor
5879
implements DisposableBean {
5980

@@ -82,7 +103,7 @@ public void destroy() throws Exception {
82103

83104
private boolean dataSourceRequiresShutdown() {
84105
return IN_MEMORY_DRIVER_CLASS_NAMES
85-
.contains(this.dataSourceProperties.getDriverClassName())
106+
.contains(this.dataSourceProperties.determineDriverClassName())
86107
&& (!(this.dataSource instanceof EmbeddedDatabase));
87108
}
88109

spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfigurationTests.java

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020
import java.sql.SQLException;
2121
import java.sql.Statement;
2222

23+
import javax.persistence.EntityManagerFactory;
2324
import javax.sql.DataSource;
2425

2526
import org.junit.Test;
27+
import org.mockito.InOrder;
2628

2729
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
2830
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -35,6 +37,7 @@
3537

3638
import static org.assertj.core.api.Assertions.assertThat;
3739
import static org.mockito.BDDMockito.given;
40+
import static org.mockito.Mockito.inOrder;
3841
import static org.mockito.Mockito.mock;
3942
import static org.mockito.Mockito.times;
4043
import static org.mockito.Mockito.verify;
@@ -48,7 +51,7 @@ public class DevToolsDataSourceAutoConfigurationTests {
4851

4952
@Test
5053
public void embeddedDatabaseIsNotShutDown() throws SQLException {
51-
ConfigurableApplicationContext context = createContext("org.h2.Driver",
54+
ConfigurableApplicationContext context = createContextWithDriver("org.h2.Driver",
5255
EmbeddedDatabaseConfiguration.class);
5356
DataSource dataSource = context.getBean(DataSource.class);
5457
context.close();
@@ -57,16 +60,44 @@ public void embeddedDatabaseIsNotShutDown() throws SQLException {
5760

5861
@Test
5962
public void externalDatabaseIsNotShutDown() throws SQLException {
60-
ConfigurableApplicationContext context = createContext("org.postgresql.Driver",
61-
DataSourceConfiguration.class);
63+
ConfigurableApplicationContext context = createContextWithDriver(
64+
"org.postgresql.Driver", DataSourceConfiguration.class);
6265
DataSource dataSource = context.getBean(DataSource.class);
6366
context.close();
6467
verify(dataSource, times(0)).getConnection();
6568
}
6669

6770
@Test
6871
public void nonEmbeddedInMemoryDatabaseIsShutDown() throws SQLException {
69-
ConfigurableApplicationContext context = createContext("org.h2.Driver",
72+
ConfigurableApplicationContext context = createContextWithDriver("org.h2.Driver",
73+
DataSourceConfiguration.class);
74+
DataSource dataSource = context.getBean(DataSource.class);
75+
Connection connection = mock(Connection.class);
76+
given(dataSource.getConnection()).willReturn(connection);
77+
Statement statement = mock(Statement.class);
78+
given(connection.createStatement()).willReturn(statement);
79+
context.close();
80+
verify(statement).execute("SHUTDOWN");
81+
}
82+
83+
@Test
84+
public void nonEmbeddedInMemoryDatabaseConfiguredWithDriverIsShutDown()
85+
throws SQLException {
86+
ConfigurableApplicationContext context = createContextWithDriver("org.h2.Driver",
87+
DataSourceConfiguration.class);
88+
DataSource dataSource = context.getBean(DataSource.class);
89+
Connection connection = mock(Connection.class);
90+
given(dataSource.getConnection()).willReturn(connection);
91+
Statement statement = mock(Statement.class);
92+
given(connection.createStatement()).willReturn(statement);
93+
context.close();
94+
verify(statement).execute("SHUTDOWN");
95+
}
96+
97+
@Test
98+
public void nonEmbeddedInMemoryDatabaseConfiguredWithUrlIsShutDown()
99+
throws SQLException {
100+
ConfigurableApplicationContext context = createContextWithUrl("jdbc:h2:mem:test",
70101
DataSourceConfiguration.class);
71102
DataSource dataSource = context.getBean(DataSource.class);
72103
Connection connection = mock(Connection.class);
@@ -85,13 +116,40 @@ public void configurationBacksOffWithoutDataSourceProperties() throws SQLExcepti
85116
.isEmpty();
86117
}
87118

88-
private ConfigurableApplicationContext createContext(String driver,
119+
@Test
120+
public void entityManagerFactoryIsClosedBeforeDatabaseIsShutDown()
121+
throws SQLException {
122+
ConfigurableApplicationContext context = createContextWithUrl("jdbc:h2:mem:test",
123+
DataSourceConfiguration.class, EntityManagerFactoryConfiguration.class);
124+
DataSource dataSource = context.getBean(DataSource.class);
125+
Connection connection = mock(Connection.class);
126+
given(dataSource.getConnection()).willReturn(connection);
127+
Statement statement = mock(Statement.class);
128+
given(connection.createStatement()).willReturn(statement);
129+
EntityManagerFactory entityManagerFactory = context
130+
.getBean(EntityManagerFactory.class);
131+
context.close();
132+
InOrder inOrder = inOrder(statement, entityManagerFactory);
133+
inOrder.verify(statement).execute("SHUTDOWN");
134+
inOrder.verify(entityManagerFactory).close();
135+
}
136+
137+
private ConfigurableApplicationContext createContextWithDriver(String driver,
138+
Class<?>... classes) {
139+
return createContext("spring.datasource.driver-class-name:" + driver, classes);
140+
}
141+
142+
private ConfigurableApplicationContext createContextWithUrl(String url,
143+
Class<?>... classes) {
144+
return createContext("spring.datasource.url:" + url, classes);
145+
}
146+
147+
private ConfigurableApplicationContext createContext(String property,
89148
Class<?>... classes) {
90149
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
91150
context.register(classes);
92151
context.register(DevToolsDataSourceAutoConfiguration.class);
93-
EnvironmentTestUtils.addEnvironment(context,
94-
"spring.datasource.driver-class-name:" + driver);
152+
EnvironmentTestUtils.addEnvironment(context, property);
95153
context.refresh();
96154
return context;
97155
}
@@ -111,7 +169,7 @@ public EmbeddedDatabase embeddedDatabase() {
111169
static class DataSourceConfiguration {
112170

113171
@Bean
114-
public DataSource in() {
172+
public DataSource dataSource() {
115173
return mock(DataSource.class);
116174
}
117175

@@ -121,10 +179,19 @@ public DataSource in() {
121179
static class NoDataSourcePropertiesConfiguration {
122180

123181
@Bean
124-
public DataSource in() {
182+
public DataSource dataSource() {
125183
return mock(DataSource.class);
126184
}
127185

128186
}
129187

188+
@Configuration
189+
static class EntityManagerFactoryConfiguration {
190+
191+
@Bean
192+
public EntityManagerFactory entityManagerFactory() {
193+
return mock(EntityManagerFactory.class);
194+
}
195+
}
196+
130197
}

0 commit comments

Comments
 (0)