Make Bean depend on list of beans in springboot

4.3k views Asked by At

I have following @Configuration class, in which I am declaring a @Bean that depends on an @Autowired list of beans. However, this list is not complete when I am accessing to it. All @Bean definitions been executed, except the one defined in the same class.

@Configuration
public class MyConfig {

  @Autowired
  List<RequiredBean> requiredBeans;

  @Bean(name="ProblemHere")
  public CustomObject customObject() {
    log.info(requiredBeans.size()); // 1 (debugging, I can see is the one defined in "AnotherConfigClass")
  }

  @Bean(name="reqBeanInsideClass")
  public RequiredBean reqBean() {
    // this method does not get executed
    return new RequiredBean();
  }

}

Having other classes like;

@Configuration
public class AnotherConfigClass {

  @Bean(name="ThisOneGetsExecuted")
  public RequiredBean reqBean() {
    // this gets executed, and therefore, added to the list
    return new RequiredBean();
  }

}

Probably, the easiest solution would be to add @DependsOn("reqBeanInsideClass").

However:

  1. I wonder why it works for all @Beans defined in different classes, but not in this one.
  2. I'm not really sure that's exactly like that, and I'm afraid later on, another @Bean does not get executed
  3. I guess the correct approach should be something like

    @DependsOn(List<RequiredBean>) // Obviously this does not work
    

How should I solve this?

Update

I have copied the exact same class twice, in order to see what would happen, so now I have also:

@Configuration
public class MyConfig2 {

  @Autowired
  List<RequiredBean> requiredBeans;

  @Bean(name="ProblemHere2")
  public CustomObject customObject() {
    log.info(requiredBeans.size());
  }

  @Bean(name="reqBeanInsideClass2")
  public RequiredBean reqBean() {
    // this method does not get executed
    return new RequiredBean();
  }

}

Amazingly, by doing this, both @Beans methods (ProblemHere & ProblemHere2) are called before both reqBeanInsideClass and reqBeanInsideClass2 methods.

For some reason I guess, Springboot is able to recognize @Beans required for a class as long as they are defined in another class.

  1. Does this sound logic to anyone?
1

There are 1 answers

12
buræquete On BEST ANSWER

Can you not utilize the array input for @DependsOn rather than passing singular value, since it accepts String[]? That would wait for all the beans that are explicitly declared in the array before initializing, though has to be defined manually.

@Configuration
public class MyConfig {

  @Autowired
  List<RequiredBean> requiredBeans;

  @Bean(name="customObject")
  @DependsOn({"reqBeanInsideClass", "thisOneGetsExecuted"})
  public CustomObject customObject() {
    log.info(requiredBeans.size());
  }

  @Bean(name="reqBeanInsideClass")
  public RequiredBean reqBean() {
    return new RequiredBean();
  }
}

@Autowired list of beans will be same as a single bean of same type, it will contain all beans with that type or with that superclass via springs injection, the problem is the ordering of bean initialization is not controlled properly, @DependsOn with array bean input should resolve this!

Or

You can make CustomObject bean @Lazy, so it will be initialized only when it is used within the code after initialization is done. The bean must not be used within another non-lazy bean I think. Just call some logic where an @Autowired CustomObject is used, it should instantiate the bean at that moment, where the list will contain all possible RequiredBeans

@Lazy
@Bean(name="customObject")
public CustomObject customObject() {
  log.info(requiredBeans.size());
}