Commit d844a0cf authored by Andy Wilkinson's avatar Andy Wilkinson

Merge branch '1.5.x'

parents d0c8f801 aa6dbdba
...@@ -26,6 +26,7 @@ import org.springframework.context.ApplicationListener; ...@@ -26,6 +26,7 @@ import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ApplicationEventMulticaster; import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.ErrorHandler; import org.springframework.util.ErrorHandler;
...@@ -93,12 +94,20 @@ public class EventPublishingRunListener implements SpringApplicationRunListener, ...@@ -93,12 +94,20 @@ public class EventPublishingRunListener implements SpringApplicationRunListener,
@Override @Override
public void finished(ConfigurableApplicationContext context, Throwable exception) { public void finished(ConfigurableApplicationContext context, Throwable exception) {
SpringApplicationEvent event = getFinishedEvent(context, exception); SpringApplicationEvent event = getFinishedEvent(context, exception);
if (context != null) { if (context != null && context.isActive()) {
// Listeners have been registered to the application context so we should // Listeners have been registered to the application context so we should
// use it at this point if we can // use it at this point if we can
context.publishEvent(event); context.publishEvent(event);
} }
else { else {
// An inactive context may not have a multicaster so we use our multicaster to
// call all of the context's listeners instead
if (context instanceof AbstractApplicationContext) {
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
if (event instanceof ApplicationFailedEvent) { if (event instanceof ApplicationFailedEvent) {
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler()); this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
} }
......
...@@ -41,10 +41,12 @@ import reactor.core.publisher.Mono; ...@@ -41,10 +41,12 @@ import reactor.core.publisher.Mono;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.CachedIntrospectionResults; import org.springframework.beans.CachedIntrospectionResults;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultBeanNameGenerator; import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent; import org.springframework.boot.context.event.ApplicationStartingEvent;
...@@ -56,6 +58,7 @@ import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicatio ...@@ -56,6 +58,7 @@ import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicatio
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
...@@ -790,11 +793,92 @@ public class SpringApplicationTests { ...@@ -790,11 +793,92 @@ public class SpringApplicationTests {
private void verifyTestListenerEvents() { private void verifyTestListenerEvents() {
ApplicationListener<ApplicationEvent> listener = this.context ApplicationListener<ApplicationEvent> listener = this.context
.getBean("testApplicationListener", ApplicationListener.class); .getBean("testApplicationListener", ApplicationListener.class);
verify(listener).onApplicationEvent(isA(ContextRefreshedEvent.class)); verifyListenerEvents(listener, ContextRefreshedEvent.class,
verify(listener).onApplicationEvent(isA(ApplicationReadyEvent.class)); ApplicationReadyEvent.class);
}
@SuppressWarnings("unchecked")
private void verifyListenerEvents(ApplicationListener<ApplicationEvent> listener,
Class<? extends ApplicationEvent>... eventTypes) {
for (Class<? extends ApplicationEvent> eventType : eventTypes) {
verify(listener).onApplicationEvent(isA(eventType));
}
verifyNoMoreInteractions(listener); verifyNoMoreInteractions(listener);
} }
@SuppressWarnings("unchecked")
@Test
public void applicationListenerFromApplicationIsCalledWhenContextFailsRefreshBeforeListenerRegistration() {
ApplicationListener<ApplicationEvent> listener = mock(ApplicationListener.class);
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.addListeners(listener);
try {
application.run();
fail("Run should have failed with an ApplicationContextException");
}
catch (ApplicationContextException ex) {
verifyListenerEvents(listener, ApplicationStartingEvent.class,
ApplicationEnvironmentPreparedEvent.class,
ApplicationPreparedEvent.class, ApplicationFailedEvent.class);
}
}
@SuppressWarnings("unchecked")
@Test
public void applicationListenerFromApplicationIsCalledWhenContextFailsRefreshAfterListenerRegistration() {
ApplicationListener<ApplicationEvent> listener = mock(ApplicationListener.class);
SpringApplication application = new SpringApplication(
BrokenPostConstructConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.addListeners(listener);
try {
application.run();
fail("Run should have failed with a BeanCreationException");
}
catch (BeanCreationException ex) {
verifyListenerEvents(listener, ApplicationStartingEvent.class,
ApplicationEnvironmentPreparedEvent.class,
ApplicationPreparedEvent.class, ApplicationFailedEvent.class);
}
}
@SuppressWarnings("unchecked")
@Test
public void applicationListenerFromContextIsCalledWhenContextFailsRefreshBeforeListenerRegistration() {
final ApplicationListener<ApplicationEvent> listener = mock(
ApplicationListener.class);
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.addInitializers((applicationContext) -> {
applicationContext.addApplicationListener(listener);
});
try {
application.run();
fail("Run should have failed with an ApplicationContextException");
}
catch (ApplicationContextException ex) {
verifyListenerEvents(listener, ApplicationFailedEvent.class);
}
}
@SuppressWarnings("unchecked")
@Test
public void applicationListenerFromContextIsCalledWhenContextFailsRefreshAfterListenerRegistration() {
ApplicationListener<ApplicationEvent> listener = mock(ApplicationListener.class);
SpringApplication application = new SpringApplication(
BrokenPostConstructConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.addInitializers((applicationContext) -> {
applicationContext.addApplicationListener(listener);
});
try {
application.run();
fail("Run should have failed with a BeanCreationException");
}
catch (BeanCreationException ex) {
verifyListenerEvents(listener, ApplicationFailedEvent.class);
}
}
@Test @Test
public void registerShutdownHookOff() throws Exception { public void registerShutdownHookOff() throws Exception {
SpringApplication application = new SpringApplication(ExampleConfig.class); SpringApplication application = new SpringApplication(ExampleConfig.class);
...@@ -1017,6 +1101,25 @@ public class SpringApplicationTests { ...@@ -1017,6 +1101,25 @@ public class SpringApplicationTests {
} }
@Configuration
static class BrokenPostConstructConfig {
@Bean
public Thing thing() {
return new Thing();
}
static class Thing {
@PostConstruct
public void boom() {
throw new IllegalStateException();
}
}
}
@Configuration @Configuration
static class ListenerConfig { static class ListenerConfig {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment