4

I have some spring component:

@Component
@ConditionalOnBean(value={JdbcTemplate.class})
public class DictionaryHandler implements Handler {
 private final JdbcTemplate jdbcTemplate;
 @Autowired
 public DictionaryHandler(JdbcTemplate jdbcTemplate) {
 this.jdbcTemplate = jdbcTemplate;
 }
 //some methods
}

In debug, I see, that JdbcTemplate bean was created: enter image description here

But, my bean not created.It doesn't go into the constructor. But why? Bean JdbcTemplate is exist, but my bean not created.

Does the condition work wrong? I don't want create DictionaryHandler if JdbcTemplate is missing. Without this I get an error.

asked Jun 21, 2019 at 10:02
2
  • Did DictionaryHandler created when you remove the conditional? Commented Jun 21, 2019 at 10:08
  • @AdhikaSetyaPramudita, Yes, DictionaryHandler was created succesfully Commented Jun 21, 2019 at 10:10

3 Answers 3

3

You should use @ConditionalOnBean on auto configuration classes only (otherwise the order is unspecified)

The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only. If a candidate bean may be created by another auto-configuration, make sure that the one using this condition runs after.

Since your JdbcTemplate bean is defined inside JdbcTemplateAutoConfiguration class so I assume that JdbcTemplateAutoConfiguration is marked with @Configuration.

In that case, you can ensure the instantiate of your bean by config:

@Configuration
@AutoConfigureAfter(JdbcTemplateAutoConfiguration.class)
public class DicationaryHandlerConfiguration {
 @Bean
 @ConditionalOnBean(JdbcTemplate.class)
 public DictionaryHandler handler(JdbcTemplate jdbcTemplate) {
 return new DictionaryHandler(jdbcTemplate)
 }
}
public class DictionaryHandler implements Handler {
 private final JdbcTemplate jdbcTemplate;
 public DictionaryHandler(JdbcTemplate jdbcTemplate) {
 this.jdbcTemplate = jdbcTemplate;
 }
 //some methods
}
answered Jun 21, 2019 at 10:17
Sign up to request clarification or add additional context in comments.

Comments

2

Check the documentation for ConditionalOnBean. It runs once and if the bean it requires not yet created - it will not trigger. The order of bean creation matters. You can try to lower priority of your component with @Order annotation or increase priority of you configuration/component class which holds JdbcTemplate bean.

answered Jun 21, 2019 at 10:15

Comments

1

From Annotation Type ConditionalOnBean:

The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only. If a candidate bean may be created by another auto-configuration, make sure that the one using this condition runs after.

In your case, the problem is DictionaryHandler bean is attempted to be created before processing the configuration class and given that JdbcTemplate bean is not yet in DI container, your DictionaryHandler is not getting instantiated.
One workaround could be to initialize DictionaryHandler in the same configuration class as JdbcTemplate.
Also, you can use different configuration class, but you'll have to use @DependsOn annotation.

An example:

@Component
@ConditionalOnBean(name = "bean1")
class AnotherBean {
}
@Configuration
class Config {
 @Bean
 public Object bean1() {
 return new Object();
 }
}

In the previous example AnotherBean will not be created, but it will be in this way:

@Configuration
class Config {
 @Bean
 public Object bean1() {
 return new Object();
 }
 @Bean
 @ConditionalOnBean(name = "bean1")
 public AnotherBean anotherBean() {
 return new AnotherBean();
 }
}
answered Jun 21, 2019 at 10:06

3 Comments

Tell please, I can take out my beans like in the separate starter and already in it to use autoconfiguration? How to keep the business logic in the starters?
Sorry, I didn't get your question, could you please clarify what do you mean by take out my beans like in the separate starter and already in it to use autoconfiguration?
I think what he means is: what if you have different modules (and configuration classes) and bring them all together as dependencies in a spring-starter? If that's not what he's asking, it's what I'm asking, because I'm having that exact problem. The two beans are in different dependencies, and I can't control the order they are loaded. DependsOn and Order annotations don't seem to be working. How can I guarantee the order if the two beans are in different configuration files (and different codebases altogether)?

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.