Skip to content

Commit a051e30

Browse files
committed
Publish an event after refresh but before runners are called
This commit partially reverts the changes made in ec470fb. While the started message continues to be logged before any application and command line runners are called, the publishing of ApplicationReadyEvent now happens after the runners have been called. Additionally, a new event, named ApplicationStartedEvent, has been introduced. This new event is published after the context has been refreshed but before any application and command line runners are called. Closes gh-11484 The reworking of the events described above also means that either an ApplicationReadyEvent or an ApplicationFailedEvent will be published and the latter should never be published once the former has been published. Closes gh-11485
1 parent 4a9123d commit a051e30

File tree

7 files changed

+253
-80
lines changed

7 files changed

+253
-80
lines changed

spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

+4-2
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,10 @@ except for the registration of listeners and initializers.
235235
the context is known but before the context is created.
236236
. An `ApplicationPreparedEvent` is sent just before the refresh is started but after bean
237237
definitions have been loaded.
238-
. An `ApplicationReadyEvent` is sent after the refresh and any related callbacks have
239-
been processed, to indicate that the application is ready to service requests.
238+
. An `ApplicationStartedEvent` is sent after the context has been refreshed but before any
239+
application and command-line runners have been called.
240+
. An `ApplicationReadyEvent` is sent after any application and command-line runners have
241+
been called. It indicates that the application is ready to service requests.
240242
. An `ApplicationFailedEvent` is sent if there is an exception on startup.
241243

242244
TIP: You often need not use application events, but it can be handy to know that they

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -326,19 +326,20 @@ public ConfigurableApplicationContext run(String... args) {
326326
printedBanner);
327327
refreshContext(context);
328328
afterRefresh(context, applicationArguments);
329-
listeners.finished(context, null);
330329
stopWatch.stop();
331330
if (this.logStartupInfo) {
332331
new StartupInfoLogger(this.mainApplicationClass)
333332
.logStarted(getApplicationLog(), stopWatch);
334333
}
334+
listeners.started(context);
335335
callRunners(context, applicationArguments);
336-
return context;
337336
}
338337
catch (Throwable ex) {
339338
handleRunFailure(context, listeners, exceptionReporters, ex);
340339
throw new IllegalStateException(ex);
341340
}
341+
listeners.running(context);
342+
return context;
342343
}
343344

344345
private ConfigurableEnvironment prepareEnvironment(
@@ -800,7 +801,7 @@ private void handleRunFailure(ConfigurableApplicationContext context,
800801
try {
801802
try {
802803
handleExitCode(context, exception);
803-
listeners.finished(context, exception);
804+
listeners.failed(context, exception);
804805
}
805806
finally {
806807
reportFailure(exceptionReporters, exception);
@@ -829,7 +830,7 @@ private void reportFailure(Collection<SpringBootExceptionReporter> exceptionRepo
829830
// Continue with normal handling of the original failure
830831
}
831832
if (logger.isErrorEnabled()) {
832-
logger.error("Application startup failed", failure);
833+
logger.error("Application run failed", failure);
833834
registerLoggedException(failure);
834835
}
835836
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListener.java

+25-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
3030
*
3131
* @author Phillip Webb
3232
* @author Dave Syer
33+
* @author Andy Wilkinson
3334
*/
3435
public interface SpringApplicationRunListener {
3536

@@ -61,11 +62,29 @@ public interface SpringApplicationRunListener {
6162
void contextLoaded(ConfigurableApplicationContext context);
6263

6364
/**
64-
* Called immediately before the run method finishes.
65-
* @param context the application context or null if a failure occurred before the
66-
* context was created
67-
* @param exception any run exception or null if run completed successfully.
65+
* The context has been refreshed and the application has started but
66+
* {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
67+
* ApplicationRunners} have not been called.
68+
* @param context the application context.
6869
*/
69-
void finished(ConfigurableApplicationContext context, Throwable exception);
70+
void started(ConfigurableApplicationContext context);
71+
72+
/**
73+
* Called immediately before the run method finishes, when the application context has
74+
* been refreshed and all {@link CommandLineRunner CommandLineRunners} and
75+
* {@link ApplicationRunner ApplicationRunners} have been called.
76+
* @param context the application context.
77+
* @since 2.0.0
78+
*/
79+
void running(ConfigurableApplicationContext context);
80+
81+
/**
82+
* Called when a failure occurs when running the application.
83+
* @param context the application context or {@code null} if a failure occurred before
84+
* the context was created
85+
* @param exception the failure
86+
* @since 2.0.0
87+
*/
88+
void failed(ConfigurableApplicationContext context, Throwable exception);
7089

7190
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListeners.java

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -67,16 +67,28 @@ public void contextLoaded(ConfigurableApplicationContext context) {
6767
}
6868
}
6969

70-
public void finished(ConfigurableApplicationContext context, Throwable exception) {
70+
public void started(ConfigurableApplicationContext context) {
7171
for (SpringApplicationRunListener listener : this.listeners) {
72-
callFinishedListener(listener, context, exception);
72+
listener.started(context);
7373
}
7474
}
7575

76-
private void callFinishedListener(SpringApplicationRunListener listener,
76+
public void running(ConfigurableApplicationContext context) {
77+
for (SpringApplicationRunListener listener : this.listeners) {
78+
listener.running(context);
79+
}
80+
}
81+
82+
public void failed(ConfigurableApplicationContext context, Throwable exception) {
83+
for (SpringApplicationRunListener listener : this.listeners) {
84+
callFailedListener(listener, context, exception);
85+
}
86+
}
87+
88+
private void callFailedListener(SpringApplicationRunListener listener,
7789
ConfigurableApplicationContext context, Throwable exception) {
7890
try {
79-
listener.finished(context, exception);
91+
listener.failed(context, exception);
8092
}
8193
catch (Throwable ex) {
8294
if (exception == null) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.context.event;
18+
19+
import org.springframework.boot.ApplicationRunner;
20+
import org.springframework.boot.CommandLineRunner;
21+
import org.springframework.boot.SpringApplication;
22+
import org.springframework.context.ConfigurableApplicationContext;
23+
24+
/**
25+
* Event published once the application context has been refreshed but before any
26+
* {@link ApplicationRunner application} and {@link CommandLineRunner command line}
27+
* runners have been called.
28+
*
29+
* @author Andy Wilkinson
30+
* @since 2.0.0
31+
*/
32+
@SuppressWarnings("serial")
33+
public class ApplicationStartedEvent extends SpringApplicationEvent {
34+
35+
private final ConfigurableApplicationContext context;
36+
37+
/**
38+
* Create a new {@link ApplicationStartedEvent} instance.
39+
* @param application the current application
40+
* @param args the arguments the application is running with
41+
* @param context the context that was being created
42+
*/
43+
public ApplicationStartedEvent(SpringApplication application, String[] args,
44+
ConfigurableApplicationContext context) {
45+
super(application, args);
46+
this.context = context;
47+
}
48+
49+
/**
50+
* Return the application context.
51+
* @return the context
52+
*/
53+
public ConfigurableApplicationContext getApplicationContext() {
54+
return this.context;
55+
}
56+
57+
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java

+18-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@
3939
*
4040
* @author Phillip Webb
4141
* @author Stephane Nicoll
42+
* @author Andy Wilkinson
4243
*/
4344
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
4445

@@ -92,8 +93,21 @@ public void contextLoaded(ConfigurableApplicationContext context) {
9293
}
9394

9495
@Override
95-
public void finished(ConfigurableApplicationContext context, Throwable exception) {
96-
SpringApplicationEvent event = getFinishedEvent(context, exception);
96+
public void started(ConfigurableApplicationContext context) {
97+
context.publishEvent(
98+
new ApplicationStartedEvent(this.application, this.args, context));
99+
}
100+
101+
@Override
102+
public void running(ConfigurableApplicationContext context) {
103+
context.publishEvent(
104+
new ApplicationReadyEvent(this.application, this.args, context));
105+
}
106+
107+
@Override
108+
public void failed(ConfigurableApplicationContext context, Throwable exception) {
109+
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application,
110+
this.args, context, exception);
97111
if (context != null && context.isActive()) {
98112
// Listeners have been registered to the application context so we should
99113
// use it at this point if we can
@@ -108,22 +122,11 @@ public void finished(ConfigurableApplicationContext context, Throwable exception
108122
this.initialMulticaster.addApplicationListener(listener);
109123
}
110124
}
111-
if (event instanceof ApplicationFailedEvent) {
112-
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
113-
}
125+
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
114126
this.initialMulticaster.multicastEvent(event);
115127
}
116128
}
117129

118-
private SpringApplicationEvent getFinishedEvent(
119-
ConfigurableApplicationContext context, Throwable exception) {
120-
if (exception != null) {
121-
return new ApplicationFailedEvent(this.application, this.args, context,
122-
exception);
123-
}
124-
return new ApplicationReadyEvent(this.application, this.args, context);
125-
}
126-
127130
private static class LoggingErrorHandler implements ErrorHandler {
128131

129132
private static Log logger = LogFactory.getLog(EventPublishingRunListener.class);

0 commit comments

Comments
 (0)