1

Using Springboot2 and java8.

I've a @Configuration class, that will instantiate a bean depending on some properties, and depending on those properties, the bean instantiated should be Primary or not.

@Configuration
public class MyConfClass {

    @Autowired
    private MyProperties myProperties;


    @Bean
    @ConditionalOnProperty(name = "property.use-default", havingValue = "false", matchIfMissing = true)
    public MySpringBean buildMySpringBean() {
        MySpringBean bean = new MySpringBean();
        if (myProperties.isPrimary()) {
           // Should be primary like if annotated with @Primary
        } else {
           // should not
        }
        return bean;
    }
}
TheBakker
  • 2,852
  • 2
  • 28
  • 49

1 Answers1

0

In general You might try to create your own BeanFactoryPostProcessor that will set Primary parameter to bean definition based on configuration, however it means that you'll dive pretty deep into spring internals.

If you don't want to fiddle with this pretty advanced concept,

Probably you can go with following approach:

@Configuration
public class MyConfClass {

    @Bean
    @Primary
    @ConditionalOnProperty(name = "shouldBeDefault", havingValue = "true", matchIfMissing = true)
    public MySpringBean buildMySpringBeanPrimary() {
        return new MySpringBean();
    }

    @Bean
    @ConditionalOnProperty(name = "shouldBeDefault", havingValue = "false", matchIfMissing = false)
    public MySpringBean buildMySpringBeanNotPrimary() {
        return new MySpringBean();
    }

Frankly I didn't understand what is property.use-default property, but if you also have to be dependent on this condition, then probably you'll have to prepare "compound conditional" that will evaluate to "true" only if both "underlying" conditions are true.

This can be done easily as explained Here

Update

Since it looks like you're going to use BeanFactoryPostProcessor here, this is the example that should work (probably with minor changes):

@Component // or register it in @Configuration as if its a regular bean
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  private final Environment env;

  public MyBeanFactoryPostProcessor(Envrionment env) {this.env = env;}

  public void postProcessBeanFactory(ConfiguratbleListableBeanFactory beanFactory) throws BeansException {

      boolean shouldBePrimary = resolveShouldBePrimary();

      if(shouldBePrimary) {
        BeanDefinition bd = beanFactory.getBeanDefinition("yourBeanName");
        bd.setPrimary(true);
      }            
   }

   private boolean resolveShouldBePrimary() {
      // here you can read properies directly or if you work with @ConfigurationProperties annotated class you can do:
      MyConfigProperties myConfigProperties = Binder.get(env).bind("prefix.in.config", MyConfigProperties.class).get()
      // now resolve from the mapped class     
   }
}

Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
  • Aye I thought about that, the caveat is I want to only have one method, as I've the same pattern of property (with different root), and I want to avoid having to copy multiple methods. – TheBakker Feb 27 '20 at 10:29
  • Well, in this case you'll have to use BeanFactoryPostProcessor I believe. `@Configuration` classes should not contain an arbitrary Java code, so you can't really go far with that approach, its more like a DSL for beans configurations in Java. BeanFactoryPostProcessor will do the job but not as easy as having two methods in my opinion... – Mark Bramnik Feb 27 '20 at 10:36
  • @TheBakker please check out the update on my answer. – Mark Bramnik Feb 27 '20 at 10:55