This is a new feature request to add a new annotation (and capability) to the core Spring Framework that has the opposite effect of the @DependsOn
annotation (Javadoc).
With Spring's @DependsOn
annotation users can say bean B depends on bean A, like so:
@Configuration
class MyApplicationConfiguration {
@Bean("B")
@DependsOn("A")
B bBean() {
return new B();
}
@Bean("A")
A aBean(..) {
return new A();
}
}
The new, inverse annotation, which I have dubbed @DependencyOf
, exists in the Spring Test for Apache Geode (STDG) project; see here.
The equivalent effect using @DependencyOf
is the following configuration:
@Configuration
class MyApplicationConfiguration {
@Bean("A")
@DependencyOf("B")
A aBean(..) {
return new A();
}
@Bean("B")
B bBean() {
return new B();
}
}
While this is not very useful in this particular configuration arrangement, it is merely to demonstrate the effect. So, when would @DependencyOf
be useful?
The need for this new @DependencyOf
annotation came about in testing.
I use the STDG project to consistently and reliably test across Spring Data for Apache Geode (SDG), Spring Session for Apache Geode (SSDG) and Spring Boot for Apache Geode (SBDG). In certain [test] cases, I need beans / components from SDG, SSDG or SBDG to depend on STDG components for testing purposes. Clearly SDG, SSDG and SBDG production components cannot be made to "depend on" STDG test components only used during test runtime.
You can see an example of the @DependencyOf
annotation in action in this STDG test class. In a nutshell, a TestCacheLifecycleListener
component and bean is a "dependency of" the "gemfireCache" bean which is created in SDG by the declaration of the ClientCacheApplication
annotation in the configuration (here).
NOTE: The SDG
@ClientCacheApplication
annotation responsible for creating aGemFireCache
bean is also meta-annotated with Spring's@Configuration
annotation making theTestConfiguration
class a proper Spring JavaConfig class.
Of course, 1 way this might be accomplished is by having STDG components implement the [Smart]Lifecycle
interface. However, this is problematic for 2 reasons 1) SDG, SSDG or SBDG also has SmartLifecycle
implementations with a potentially higher precedence and 2) the precedence of SmartLifecycle
components in SDG, SSDG and SBDG could change in the future and become higher. There are other situations to consider.
There are of course hooks in the Spring TestContext
framework where it might be possible to perform certain initialization in TestExecutionListeners
and what not. I have considered multiple angles here.
Yet another implementation would be to use a BeanFactoryPostProcessor
to change the dependencies of the SDG, SSDG and SBDG bean definitions.
And, in fact, this is exactly how the @DependencyOf
annotation configuration is implemented, by using a BeanFactoryPostProcessor
to modify the (would be) dependent beans / components from upstream frameworks. See here.
The @DependencyOf
annotation is flexible and easy to add to any (downstream) project that might require beans to get initialized before the upstream framework initializes certain beans.
I am proposing this additional, complimentary annotation as an addition to the core Spring Framework if the team feels this would have value (merit) beyond the use cases I identified. I would be happy to work with interested parties on its integration as needed.
Comment From: funky-eyes
I believe it would bea great convenience to have this feature in place when we sometimes get frustrated with not being able to control the loading order of beans in other components
Comment From: jhoeller
After a team discussion this morning, while we do understand the intention here, we have no plans to introduce such an inverse dependency annotation as a common first-class concept. Any such bean relationships can be programmatically expressed via ConfigurableBeanFactory.registerDependentBean
(e.g. in a BeanFactoryPostProcessor
as suggested above) already, in a separate piece of logic that understands the overall relationships in a given application context setup.
Conceptually, an annotation that introduces an understanding of a higher-level bean in a lower-level bean definition seems a bit backwards. In the example above, bean A should arguably not be aware of bean B, not even through metadata on its bean definition. It seems cleaner to put such dependency registrations in a separate place that conceptually knows about A as well as B. In particular for production setups, we prefer to strongly suggest such conceptual alignment.
For test setups, there is nothing wrong with declaring extra dependency declarations if needed, on inferring them from the overall setup (or even from annotation declarations) in a BeanFactoryPostProcessor
- ideally via ConfigurableBeanFactory.registerDependentBean
rather than BeanDefinition.setDependsOn
, keeping the dependency declarations separate. We don't really see preferred use cases beyond such scenarios.
Thanks for raising the topic, in any case!
Comment From: agoston
@jxblum can you extract that specific @DependencyOf
from the library you referenced? I think I speak for many who would really need this during testing.
Comment From: jxblum
Hi @agoston - Thank you for your continued interests in this feature. I am planning to break this out into a separate library along with many other Spring Framework (and other Spring project, e.g. Spring Boot) extensions I have developed in my specific Spring projects over the years. I have no planned timeframe yet for doing so.
I will give this more thought and post back here soon when I have some concrete details.