New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ApplicationReadyEvent fires multiple time while using SpringApplicationBuilder #8899
Comments
This mainly due to the mismatch between I agree that it's a little odd to get the One option you might have is to check for
|
@LeckerMaedschen why not register the listener only on one of the children? Like this: public class Application {
public static void main(String[] args) {
SpringApplicationBuilder parentBuilder
= new SpringApplicationBuilder(Application.class);
// parentBuilder.listeners(new AfterStart());
parentBuilder.child(Config1.class)
.properties("server.port:8443")
.listeners(new AfterStart()) // register listener only on this child
.run(args);
parentBuilder.child(Config2.class)
.properties("server.port:9443")
.run(args);
}
} |
Regardless I think we should fix it somehow. If we agree the scope of the application is independent of the structure of the application context, then we should fire it only once and at the appropriate time. Not sure however that everybody share the same concept of "application" (perhaps the builder is used to start several apps in isolation in child context?). |
We've discussed in the past if there shouldn't be a better way for |
There was a related, but not identical issue in Spring Cloud. We wanted more flexibility in the hierarchy building, so we could identify the parent context when the child is being created. The solution for now is a reflective workaround: https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/BootstrapApplicationListener.java#L104 (see |
It feels like we should either tackle this in 2.0 or close it as a known limitation. Thoughts? |
I vote known issue. |
As discussed with @dsyer on gitter I think it would be useful to be able to check what kind of context triggered the event -> application context, management context, cloud-stream or feign. Maybe a qualifier or something similar to determine a context without hacks? Other solution could be an event that the main application context has started. However, there are already a lot of events related to this, so I'm not sure it it's a best idea to add another one |
The management context won't fire an |
@wilkinsona I think it'd be easier to add some |
Let's ask @garyrussell what he thinks. It might actually be a bug in Spring Cloud Stream, since I know other child contexts do not suffer the same way exactly (cf Andy's comment about the management context, and also Feign). Perhaps Stream child contexts are too "heavy"? Or perhaps there's a reason they need to include all the listeners from the parent. |
If someone can provide an example that exhibits the problem with Spring Cloud Stream, I'd be happy to take a look. I don't see a problem with Stream if the listener is a @dsyer said:
I just need a pointer to reproduce. |
@SpringBootApplication
@EnableBinding(Processor.class)
public class StreamListenerApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(StreamListenerApplication.class)
.listeners(new Listener()).run(args);
}
}
class Listener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.err.println("Ready: " + event.getApplicationContext().hashCode());
}
} Prints "Ready" twice. And there's no way to know from the listener that you are in the "main" context or not. The Bootstrap context is also there (created by Spring Cloud Context) and it uses |
Yikes! IMHO, such listeners should be registered as beans in the main context and initialized like any other bean ( |
Depending on the events that you want to consume, you can't always do that. For example, |
Right, but you could still do it before adding to the context.
I would suggest running the Annotation BPP against the listener and |
Sorry, I don't understand how that would help. The context is already available from the I think the problem here is really that Spring Cloud Stream creates a whole new child application when just a child context may well be sufficient. This is what the Actuator does when creating its child context when a separate management HTTP port is required. If SCS just used a child context, none of the |
I'm not sure I'm following all of this, but having an |
It sounds dangerous to me, particularly if the listeners are being copied from a parent SpringApplication to a child. You'd then have |
I'm not sure, but I don't think any actual listener instances are copied. It's just that any registered via |
For those coming from |
That's the whole point I think. You get events from all the contexts in the hierarchy, but you can't tell from a listener if their source is from "your" application or not. |
Aaah, I get it now. Thanks for bearing with me. So for the specific problem raised by this issue, you can use register your This solution won't work for events that are multicast before any application listener beans are instantiated. Those are With or without the |
I was able to simplify my listeners in the benchmarks quite a lot, now that I know about the |
Doh - I didn't notice that code. I guess I am ok with not doing auto wiring - agreed that doco is probably enough at this point. That said, I am sure I would only use this feature when interested with those "early" events and use a |
Using
ApplicationListener<ApplicatioReadyEvent>
with the usage ofSpringApplicationBuilder
fires multiple notification to that listener (for every child). Please have a look to that small demonstration: demo.zipIssue created after stackoverflow question comment: here
The text was updated successfully, but these errors were encountered: