Reputation: 667
I have been searching for this for a while.
Till now, I found this blog very useful but did not solve my problem.
I want to @Autowired
a bean only if a flag
is true, else I want that to be null
Use Case:
If one of the DB is under maintenance, I do not want my app to fail.
@Bean("sqlDatabase")
public Database getSqlDatabase(@Value("${datasource.sql.url}") String url,
@Value("${datasource.sql.username}") String username, @Value("${datasource.sql.password}") String password,
@Value("${datasource.poolsize.min}") int minPoolSize, @Value("${datasource.poolsize.max}") int maxPoolSize,
@Value("${database.enable-sql}") boolean isSqlEnabled) {
if (isSqlEnabled)
return Database.builder().url(url).pool(minPoolSize, maxPoolSize).username(username).password(password)
.build();
else
return null;
}
Now, in this case, its throwing error as I cannot autowire
a null
bean.
I wanted to use @Conditional
but my case is a bit complex. I already need all 3 databases to be updated. I just want to skip
one of them if conditions are not met.
Upvotes: 2
Views: 5580
Reputation: 3457
We can leverage @Conditional
property during the initial component scan
to avoid error while initializing based on the environment properties.
A valid use case would be enable a repository to be scanned for bean initialization when the environment db.enabled
property is true
example: https://javapapers.com/spring/spring-conditional-annotation/
Conditional helper class
public class DocumentDBInitializerPresence implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
DocumentDBInitializerInfo employeeBeanConfig = null;
try {
employeeBeanConfig = (DocumentDBInitializerInfo)context.getBeanFactory().getBean("DocumentDBInitializerInfo");
} catch(NoSuchBeanDefinitionException ex) {
System.out.println("BEAN NOT FOUND:: " + employeeBeanConfig != null );
}
System.out.println("BEAN FOUND :: " + employeeBeanConfig != null );
boolean matches = Boolean.valueOf(context.getEnvironment().getProperty("db.enabled"));
System.out.println("CONFIG ENABLED :: " + employeeBeanConfig != null );
return employeeBeanConfig != null && matches;
}
}
Using in service
@Service
@RefreshScope
@Conditional(value= DocumentDBInitializerPresence.class)
public class RepositoryDocumentDB {
private static Logger LOGGER = LoggerFactory.getLogger(RepositoryDocumentDB.class);
public static final String DOCUMENT_DB_LOCAL_HOST = "localhost";
DocumentDBInitializerInfo documentDbConfig;
@Autowired
public RepositoryDocumentDB(final DocumentDBInitializerInfo documentDbConfig) {
this.documentDbConfig = documentDbConfig;
}
}
This will not throw error on application startup if you are not autowiring RepositoryDocumentDB anywhere yet and the db.enabled is set to false.
Hope this helps!
Upvotes: 1
Reputation: 9516
You can use profiles. One profile for every database
Than annotate the bean class or the bean method with the profile that must be activated to use that bean like
@Profile("db1")
@Bean("db1")
public Database getSqlDatabase(...){...}
When you start your app, beans annotated with @Profile will only be created, if the regarding profile is activated.
You activate a profile by setting the property 'spring.profiles.active'. To activate db1 and db2 :
spring.profiles.active=db1,db3
You can set that property in a properties file or as a command line parameter.
Profiles give you a lot of flexibility to change you spring context by configuration
Please note : If you use do not use component scan or xml configuration, the annotation @Profile at a bean class has no effect. You need to annotate the bean method with @Profile or the whole configuration class instead.
Upvotes: 3