Spring bean depends on a conditional bean

12,239

Solution 1

How about the following approach:

interface Something {}

public class FirstBean implements Something {}

public class SecondBean implements Something{} // maybe empty implementation

Now the configuration goes like this:

@Configuration
public class MyConfiguration {

  @Bean(name = "hello")
  @ConditionalOnProperty(name = "some.property", havingValue = true) 
  public Something helloBean() {
     return new FirstBean();
  }

  @Bean(name = "hello")
  @ConditionalOnProperty(name = "some.property", havingValue = false) 
  public Something secondBean() {
     return new SecondBean();
  }

  @Bean
  @DependsOn("hello")
  public MyDependantBean dependantBean() {
       return new MyDependantBean();
  }
}

The idea is to create the "Something" bean anyway (even if its an empty implementation), so that the dependant bean will depend on Something in any case.

I've not tried this myself, you know, spring is full of magic, but probably it worth a try:)

Solution 2

Instead of using @DependsOn you can use @AutoConfigureAfter()which will allow the second bean to be created even if the first bean was not created, but still keep the order.

@Configuration
public class FirstConfiguration {

  @Bean(name = "firstBean")
  @ConditionalOnProperty(name = "some.property", havingValue = true) 
  public FirstBean firstBean() {
     return new FirstBean();
  }
}

@Configuration
@AutoConfigureAfter(name = {"firstBean"})
public class SecondConfiguration {

  @Bean
  public SecondBean secondBean() {
       return new SecondBean();
  }
}

Solution 3

Could you create two definitions for the dependent bean, to cater for the two cases where the other bean is or isn't there?

E.g.:

@Bean(name = "myDependentBean")
@DependsOn("otherBean")
@ConditionalOnProperty(name = "some.property", havingValue = true) 
public DependentBean myDependentBean() {
    return new DependentBean();
}

@Bean(name = "myDependentBean")
@ConditionalOnProperty(name = "some.property", havingValue = false, matchIfMissing = true) 
public DependentBean myDependentBean_fallback() {
    return new DependentBean();
}

(This is the approach I've just taken today to solve a similar problem!)

Then Spring would use the first definition if some.property is true, and so instantiate myDependentBean after otherBean. If some.property is missing or false, Spring will use the second definition, and so not care about otherBean.

Alternatively, you could probably use @ConditionalOnBean/@ConditionalOnMissingBean on these, instead of @ConditionalOnProperty (though I've not tried this).

Share:
12,239

Related videos on Youtube

gnos
Author by

gnos

Updated on June 04, 2022

Comments

  • gnos
    gnos almost 2 years

    I want a spring bean to be instanciated after another bean. So I simply use the @DependsOn annotation.

    The thing is : this other bean is a conditional bean wearing the @ConditionalOnProperty(name = "some.property", havingValue = "true") annotation. So when the property is false then the bean is not instanciated (and that's what we want), and the @DependsOn obviously fails. The goal here is : create the second bean anyway, but create it after the first one if it was created.

    Is there a way to do that without removing the @ConditionalOnProperty ? And without playing with the @Order annotation ?

    Thank you for your help

  • gnos
    gnos about 6 years
    On what bean ? The second one ? This would just instanciate the second bean if the first one exists .. That is not what I want. I might have not got your point though
  • gnos
    gnos about 6 years
    I'd like to avoid creating the conditional bean in both cases. The question is all about producing clean code here. I am probably too demanding. Yes indeed your solution would work as needed :).
  • Mark Bramnik
    Mark Bramnik about 6 years
    I saw solutions like this a couple of times in spring boot code itself so I've borrowed an idea from there: don't really remember where exactly, but they do sometimes create no-op beans for various purposes
  • Amit Goldstein
    Amit Goldstein almost 6 years
    You really don't need the "Something" interface. I have a similar setup but I just use an Object for the mock bean since anyway @DependsOn works on bean name.
  • turbofood
    turbofood over 2 years
    It's disappointing to find out that the @AutoConfigureAfter annotation doesn't apply to methods.