|
26 | 26 | import org.awaitility.Awaitility; |
27 | 27 | import org.junit.jupiter.api.Test; |
28 | 28 |
|
| 29 | +import org.springframework.beans.factory.InitializingBean; |
29 | 30 | import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; |
30 | 31 | import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
31 | 32 | import org.springframework.context.ConfigurableApplicationContext; |
32 | 33 | import org.springframework.context.support.AbstractApplicationContext; |
| 34 | +import org.springframework.context.support.GenericApplicationContext; |
33 | 35 |
|
34 | 36 | import static org.assertj.core.api.Assertions.assertThat; |
35 | 37 | import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; |
@@ -91,6 +93,15 @@ void runWhenContextIsBeingClosedInAnotherThreadWaitsUntilContextIsInactive() thr |
91 | 93 | assertThat(finished).containsExactly(context, handlerAction); |
92 | 94 | } |
93 | 95 |
|
| 96 | + @Test |
| 97 | + void runDueToExitDuringRefreshWhenContextHasBeenClosedDoesNotDeadlock() throws InterruptedException { |
| 98 | + GenericApplicationContext context = new GenericApplicationContext(); |
| 99 | + TestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook(); |
| 100 | + shutdownHook.registerApplicationContext(context); |
| 101 | + context.registerBean(CloseContextAndExit.class, context, shutdownHook); |
| 102 | + context.refresh(); |
| 103 | + } |
| 104 | + |
94 | 105 | @Test |
95 | 106 | void runWhenContextIsClosedDirectlyRunsHandlerActions() { |
96 | 107 | TestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook(); |
@@ -221,4 +232,28 @@ public void run() { |
221 | 232 |
|
222 | 233 | } |
223 | 234 |
|
| 235 | + static class CloseContextAndExit implements InitializingBean { |
| 236 | + |
| 237 | + private final ConfigurableApplicationContext context; |
| 238 | + |
| 239 | + private final Runnable shutdownHook; |
| 240 | + |
| 241 | + CloseContextAndExit(ConfigurableApplicationContext context, SpringApplicationShutdownHook shutdownHook) { |
| 242 | + this.context = context; |
| 243 | + this.shutdownHook = shutdownHook; |
| 244 | + } |
| 245 | + |
| 246 | + @Override |
| 247 | + public void afterPropertiesSet() throws Exception { |
| 248 | + this.context.close(); |
| 249 | + // Simulate System.exit by running the hook on a separate thread and waiting |
| 250 | + // for it to complete |
| 251 | + Thread thread = new Thread(this.shutdownHook); |
| 252 | + thread.start(); |
| 253 | + thread.join(15000); |
| 254 | + assertThat(thread.isAlive()).isFalse(); |
| 255 | + } |
| 256 | + |
| 257 | + } |
| 258 | + |
224 | 259 | } |
0 commit comments