-
Notifications
You must be signed in to change notification settings - Fork 38.9k
Description
Background
Spring Framework currently provides @DependsOn to declare that a bean depends on other beans. This is useful when certain beans must be initialized before the annotated bean. However, there is no built‑in way to express the reverse relationship: a bean that is depended upon by other beans and therefore must be initialized before those beans.
In large applications, especially when working with auto‑configured infrastructure beans like DataSource, it is common to need some custom beans (e.g., connection pool decorators, security initializers, logging components) to be fully initialized before the DataSource is created. Currently, achieving this without modifying the auto‑configuration or manually defining the DataSource bean is cumbersome.
Use Case
Consider a Spring Boot application that uses the default DataSourceAutoConfiguration. You have a custom bean MyEarlyBean that must be initialized before the DataSource bean.
With the existing @DependsOn, you would have to:
- Exclude
DataSourceAutoConfiguration - Define your own
DataSourcebean and annotate it with@DependsOn("myEarlyBean")
This works, but it forces you to take full control over the DataSource definition, losing the benefits of auto‑configuration. A more declarative, non‑intrusive approach would be desirable.
Proposed API
Introduce a new annotation @RequiredBy that can be placed on a bean class or a @Bean method. It declares that the annotated bean must be initialized before the beans specified by the annotation.
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiredBy {
/**
* Bean names that depend on the annotated bean.
*/
String[] value() default {};
/**
* Bean types that depend on the annotated bean.
* All beans matching these types will be made to depend on the annotated bean.
*/
Class<?>[] type() default {};
}Example Usage
@Component
@RequiredBy(type = DataSource.class)
public class MyEarlyBean {
// this bean will be initialized before any DataSource bean
}or with bean name:
@Component
@RequiredBy("dataSource")
public class MyEarlyBean {
// ...
}How It Would Work
When the application context is refreshed, a BeanFactoryPostProcessor would scan all bean definitions for the @RequiredBy annotation. For each annotated bean, it would add the bean’s name to the dependsOn set of every target bean specified via value or type. This is essentially the inverse of what @DependsOn does: instead of modifying the annotated bean’s dependencies, it modifies the dependencies of the target beans.
This approach:
- Works with auto‑configuration (no need to exclude
DataSourceAutoConfiguration) - Preserves all existing dependency handling logic
- Can be implemented efficiently using
AnnotatedBeanDefinitionmetadata to avoid class loading where possible
Why This Cannot Be Solved Elegantly by Existing Features
@DependsOnrequires modifying the bean that should be later (theDataSource) to list its prerequisites. In the case of auto‑configured beans, that would mean either excluding the auto‑configuration and re‑declaring the bean, or usingBeanFactoryPostProcessorto programmatically adddependsOn– which is exactly what we want to standardize.@Order/@Priorityaffect only beans of the same type and are not designed for inter‑bean ordering across arbitrary types.@AutoConfigureBefore/@AutoConfigureAfterwork at the auto‑configuration level, not at the individual bean level.
Implementation Sketch
A minimal implementation could be a BeanFactoryPostProcessor similar to:
@Component
public class RequiredByBeanPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 1. Find all beans annotated with @RequiredBy
// 2. For each target bean (by name or type), add the annotated bean to its dependsOn
}
}Performance considerations:
- Use
AnnotatedBeanDefinitionmetadata when available to avoid unnecessary class loading. - If performance is a concern, the scanning could be limited to bean definitions that actually need processing.
Alternatives Considered
- Manual
BeanFactoryPostProcessorin user code – possible but requires boilerplate code and is not standardized. Many developers would benefit from a built‑in, well‑tested solution. @DependsOnwith auto‑configuration exclusion – works but is invasive and discards auto‑configuration features.ApplicationListener<ContextRefreshedEvent>– runs too late (after all beans are already initialized) and cannot affect initialization order.
Benefits
- Declarative – clearly expresses “this bean must be ready before that bean”.
- Non‑intrusive – works with auto‑configuration and third‑party beans.
- Symmetry with
@DependsOn– completes the dependency declaration picture. - Reduces boilerplate – no need to write custom
BeanFactoryPostProcessorfor common ordering needs.
Related Discussions
- Stack Overflow: How to make a bean initialize before DataSource without excluding auto‑configuration
Next Steps
I would like to open a discussion on whether this feature aligns with Spring’s roadmap. If there is interest, I can prepare a pull request with an implementation, documentation, and tests.
Thank you for considering this feature!