While updating Spring-Boot in a production Web-Application I encountered a strange issue where the Application Context would not start. I've tracked it down to the behavior of the DefaultListableBeanFactory
. It's however probably a corner case, but as it manifest in springs DelegatingWebSocketMessageBrokerConfiguration
I think it should be thought about and at least in the concrete case corrected.
Pre-Conditions:
- Classes A and B where B extends A
- A primary instance of B in the context (I'll call this primaryB below)
- A named instance (say beanA) of type A and runtime type B
- A bean that requires a bean of type B to be wired (I'll call this needsB below)
- A bean that requires a bean of type B with name beanA to be wired (I'll call this needsA below)
Actual behavior:
If the bean needsB is created first, the bean factory will only discover primaryB as candidate for auto-wiring, as beanA has not been instantiated and the configuration says it's of type A which does not fulfill the requirement of type B (which at runtime it would).
Trying to later wire an instance of type B in needsA will now fail. Because primaryB is a primary bean, the BeanFactory
skips looking for the dependency directly (step 3 in the implementation), and tries to get the beans from the type to beanName cache. But this has been filled earlier only with primaryB and therefor no bean names beanA is found (even though it is defined).
If needsA is handled first, the cache is not yet set up and wiring works. The same is true if primaryB is not flagged as Primary
as in this case the resolution in step 3 is not skipped.
Expected behavior:
It's not 100% clear what exactly should be the behavior. But I would expect the spring shipped web socket config to be stable (should be possible by making the Executors
actually TaskExecutors
). Also dependency on the sequence and Primary bean being available doesn't seem right.
I could imagine that beans should not be wired if the declared type is not enough to fulfill the requirement (even if the runtime type would). But this seems to be quite a big change.
Comment From: frommeyerc
Here is a repository with a test that illustrates the issue: https://github.com/frommeyerc/bean-resolve-repro
Comment From: jhoeller
This turned out as a long-standing misbehavior in the by-type cache: It does not get invalidated once the most specific type becomes available on singleton instance creation. The resolution shortcut introduced in 6.2 (#28122) does not suffer from this deficit, so it made the deficit in the regular code path more obvious. To be fixed for 6.2.10.