Spring external library beans initialization order

Viewed 1004

I've encountered a problem in my application and somehow i need to force one bean A to be initialized before another bean B. These beans are provided by external dependencies (different dependencies) so I cannot simply do it with @DependsOn annotation.
Is there any solution available?

1 Answers

I set up a simple (modular, maven) project and did experience no issues using @DependsOn annotation on an "external component". Only few things to accomplish:

  1. Ensure A is in the (runtime) classpath of B.
  2. Ensure B's application context @ComponentScans (also) A.
  3. Find out/guess the "logical bean name" of A and use that value in your @DependsOn annotation. ..then @DependsOn works as expected (also on "external dependencies").

The sample uses , but (I am sure) the configuration details are applicable to a "boot-less" environment/context.


And considering the javadoc of DependsOn:

Used infrequently in cases where a bean does not explicitly depend on another through properties or constructor arguments, but rather depends on the side effects of another bean's initialization.

@Autowired would give you the same effect (with similar effort), but with type safety/without "name guessing" - I added it to the sample.


REWORK: Regarding this from a third project (baz), you have again several options to force A initialization before B.

  1. If A and B initialization is trivial (e.g. default constructor), you can proceed in your configuration/application like this:

    import ...A;
    import ...B;
    ...
    @Configuration// @SpringBootApplication ..or idempotent
    public class MyConfig {
        ...
        @Bean("a")
        public A a() {
          return new A();
        }
    
        @Bean
        @DependsOn("a")
        public B b() {
          return new B();
        }
        ...
    }
    
  2. If initialization (of A and B) is not trivial, but you can refer to existing (external) Configurations, then this works (redefining autowired beans, adding dependsOn annotation):

    @Configuration
    @Import(value = {BConfig.class, AConfig.class})
    class MyConfig {
    
      @Bean("a")
      public A a(@Autowired A a) {
        return a;
      }
    
      @Bean
      @DependsOn("a")
      public B b(@Autowired B b) {
        return b;
      }
    }
    
  3. You rely on component scan, and redefine the beans (with dependsOn):

    @Configuration
    @ComponentScan(basePackageClasses = {B.class, A.class})
    class MyConfig {
        // same as 2.
    }
    
  4. ...

If the external config (2., 3.) defines the beans with the same "name", then spring.main.allow-bean-definition-overriding property must be set to true (in application.properties or idempotent).

Related