'Spring @Conditional based on a value in database table
Condition evaluation depends on a value provided in data base table
@Component
public class XYZCondition implements Condition{
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//based on value defined in DB should return true/false
}
}
As Condition is executing very early, unable to fetch db value is there any alternate way to achieve this ?
Solution 1:[1]
Well, you're trying to do something that doesn't map well to spring boot in this form.
I suggest to slightly change the requirement:
Instead of trying to access the database in the custom condition, create a custom source of configuration and load the property from the database into the Environment so that when the conditionals get evaluated later on during the startup process, the property with an associated value (previously resolved from the database) is already available.
Examples of following such an approach are: - Spring boot cloud config that reads the configuration properties from "remote" config service (via REST) - Spring boot consul integration (that reads from consul obviously)
This approach is much more spring-friendly, and also has can save the application from calling the database multiple times (what if you have 100 beans with this custom conditional) - will it do 100 queries?
Now, this will mean probably that you won't need a custom conditional - probably it will be @Condition on property.
Another caveat is that you won't be able to use JPA/Spring Data to load this property, probably you'll have to go with a Plain JDBC here.
Solution 2:[2]
Hmm, maybe you can just create a Configuration Class and Inject your Repository then create a Bean. Then inside the bean method fetch the value from the database and return conditional instance. something like this
@Configuration
public class Config {
@Autowired
private Repository repository;
@Bean
public Interface interface(){
boolean val = reposiory.getDBValue();
if(val)
return new Impl1();
else
return new Impl2();
}
}
Solution 3:[3]
sadly you cannot inject a lot into condition: so try with plain url and make manual connection to server, but in my case this didn't work as I had flyway migration that was adding the same configuration value into the database (chicken and egg problem)
class EnableXXXCondition implements Condition {
private Environment environment;
@SneakyThrows
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
environment = context.getBeanFactory().getBean(Environment.class);
final String url = environment.getProperty("spring.datasource.url");
final String user = environment.getProperty("spring.datasource.username");
final String password = environment.getProperty("spring.datasource.password");
String x;
//we have problems with flyway before
try (Connection connection = DriverManager.getConnection(url, user, password)) {
try (Statement statement = connection.createStatement()) {
try (final ResultSet resultSet = statement.executeQuery("select x from y")) {
resultSet.next();
x = resultSet.getString("x");
}
}
}
return Boolean.valueOf(x);
}
}
Solution 4:[4]
You can try defining your condition in your configuration file and use it like below :
@ConditionalOnProperty(name="filter.enabled", havingValue="true")
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Mark Bramnik |
| Solution 2 | Ryan Guamos |
| Solution 3 | user3423 |
| Solution 4 | Elikill58 |
