Browse Source

Merge branch '2.5.x' into 2.6.x

Closes gh-29905
pull/30003/head
Brian Clozel 4 years ago
parent
commit
16c47595e7
  1. 1
      spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
  2. 12
      spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHook.java
  3. 37
      spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java
  4. 17
      spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java

1
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java

@ -786,6 +786,7 @@ public class SpringApplication { @@ -786,6 +786,7 @@ public class SpringApplication {
reportFailure(getExceptionReporters(context), exception);
if (context != null) {
context.close();
shutdownHook.deregisterFailedApplicationContext(context);
}
}
}

12
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHook.java

@ -43,6 +43,7 @@ import org.springframework.util.Assert; @@ -43,6 +43,7 @@ import org.springframework.util.Assert;
*
* @author Andy Wilkinson
* @author Phillip Webb
* @author Brian Clozel
*/
class SpringApplicationShutdownHook implements Runnable {
@ -92,6 +93,17 @@ class SpringApplicationShutdownHook implements Runnable { @@ -92,6 +93,17 @@ class SpringApplicationShutdownHook implements Runnable {
}
}
void deregisterFailedApplicationContext(ConfigurableApplicationContext applicationContext) {
synchronized (SpringApplicationShutdownHook.class) {
if (!applicationContext.isActive()) {
SpringApplicationShutdownHook.this.contexts.remove(applicationContext);
}
else {
throw new IllegalStateException("Cannot unregister active application context");
}
}
}
@Override
public void run() {
Set<ConfigurableApplicationContext> contexts;

37
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -26,6 +26,7 @@ import java.util.concurrent.CountDownLatch; @@ -26,6 +26,7 @@ import java.util.concurrent.CountDownLatch;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
@ -36,12 +37,14 @@ import org.springframework.context.support.GenericApplicationContext; @@ -36,12 +37,14 @@ import org.springframework.context.support.GenericApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link SpringApplicationShutdownHook}.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @author Brian Clozel
*/
class SpringApplicationShutdownHookTests {
@ -154,6 +157,29 @@ class SpringApplicationShutdownHookTests { @@ -154,6 +157,29 @@ class SpringApplicationShutdownHookTests {
.withMessage("Shutdown in progress");
}
@Test
void failsWhenDeregisterActiveContext() {
TestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();
ConfigurableApplicationContext context = new GenericApplicationContext();
shutdownHook.registerApplicationContext(context);
context.refresh();
assertThatThrownBy(() -> shutdownHook.deregisterFailedApplicationContext(context))
.isInstanceOf(IllegalStateException.class);
assertThat(shutdownHook.isApplicationContextRegistered(context)).isTrue();
}
@Test
void deregistersFailedContext() {
TestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();
GenericApplicationContext context = new GenericApplicationContext();
shutdownHook.registerApplicationContext(context);
context.registerBean(FailingBean.class);
assertThatThrownBy(context::refresh).isInstanceOf(BeanCreationException.class);
assertThat(shutdownHook.isApplicationContextRegistered(context)).isTrue();
shutdownHook.deregisterFailedApplicationContext(context);
assertThat(shutdownHook.isApplicationContextRegistered(context)).isFalse();
}
static class TestSpringApplicationShutdownHook extends SpringApplicationShutdownHook {
private boolean runtimeShutdownHookAdded;
@ -259,4 +285,13 @@ class SpringApplicationShutdownHookTests { @@ -259,4 +285,13 @@ class SpringApplicationShutdownHookTests {
}
static class FailingBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
throw new IllegalArgumentException("test failure");
}
}
}

17
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java

@ -16,10 +16,12 @@ @@ -16,10 +16,12 @@
package org.springframework.boot;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
@ -150,6 +152,7 @@ import static org.mockito.Mockito.spy; @@ -150,6 +152,7 @@ import static org.mockito.Mockito.spy;
* @author Marten Deinum
* @author Nguyen Bao Sach
* @author Chris Bono
* @author Brian Clozel
*/
@ExtendWith(OutputCaptureExtension.class)
class SpringApplicationTests {
@ -1247,6 +1250,20 @@ class SpringApplicationTests { @@ -1247,6 +1250,20 @@ class SpringApplicationTests {
assertThat(application.getEnvironmentPrefix()).isEqualTo("my");
}
@Test
void deregistersShutdownHookForFailedApplicationContext() {
SpringApplication application = new SpringApplication(BrokenPostConstructConfig.class);
List<ApplicationEvent> events = new ArrayList<>();
application.addListeners(events::add);
application.setWebApplicationType(WebApplicationType.NONE);
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(application::run);
assertThat(events).hasAtLeastOneElementOfType(ApplicationFailedEvent.class);
ApplicationFailedEvent failure = events.stream().filter((event) -> event instanceof ApplicationFailedEvent)
.map(ApplicationFailedEvent.class::cast).findFirst().get();
assertThat(SpringApplicationShutdownHookInstance.get())
.didNotRegisterApplicationContext(failure.getApplicationContext());
}
private <S extends AvailabilityState> ArgumentMatcher<ApplicationEvent> isAvailabilityChangeEventWithState(
S state) {
return (argument) -> (argument instanceof AvailabilityChangeEvent<?>)

Loading…
Cancel
Save