Issue
I am trying to register Datasource instance as a bean in java code(spring-boot project)
Here is what I wrote. (This code is not working.)
@Configuration
public class DatabaseConfig {
private Logger logger = Logger.getLogger(DatabaseConfig.class);
@Autowired
ApplicationContext context;
private Map<String, Map<String, String>> dsMap;
private Map<String, String> getTestDataSourceInfo () {
Map<String, String> ds = new HashMap<String, String> ();
ds.put("driverClassName", "com.mysql.jdbc.Driver");
ds.put("url", "jdbc:mysql://123.456.78.912:3306/test");
ds.put("username", "testuser");
ds.put("password", "testuser");
return ds;
}
public DatabaseConfig () {
this.dsMap = new HashMap<String, Map<String, String>>();
dsMap.put("sampleDs", getTestDataSourceInfo());
}
@PostConstruct
public void loadDataSource () {
logger.info("DS ================================ :: " + String.valueOf(this.dsMap));
this.dsMap.forEach((k,v) -> {
logger.info("value ========================== :: " + String.valueOf(v));
DataSource aSource = DataSourceBuilder.create()
.driverClassName(v.get("driverClassName"))
.url(v.get("url"))
.username(v.get("username"))
.password(v.get("password"))
.build();
// PROBLEM STARTS ..............
// Add datasource instance with name to context
context.getAutowireCapableBeanFactory().autowireBean(aSource);
});
}
}
Is there any proper way to register bean with an instance? I could not find any fine samples for this.
FYI, What I have expected in above code is...
- Spring boot application will read above class as a
Configure
- It will make an Java instance in its constructor
- And it will add the instance as a bean to application context in
loadDatasource
method
However, it is not working. So I am curious about how to add an java instance as a bean to current Spring boot application context.
Solution
Actually, it could be more easier if I did not do this with DataSource
.
Since, Spring-boot automatically do configure dataSource
, I have to disable this settings first.
Here is what I did to achieve the goal
In @Configuration
Class...
@Configuration
public class DatabaseConfig {
private Logger logger = Logger.getLogger(DatabaseConfig.class);
@Autowired
ApplicationContext context;
private Map<String, Map<String, String>> dsMap;
private Map<String, String> getTestDataSourceInfo () {
Map<String, String> ds = new HashMap<String, String> ();
ds.put("driverClassName", "${ your driverClassName }");
ds.put("url", "${ your url }");
ds.put("username", "${ your user }");
ds.put("password", "${ your password }");
return ds;
}
public DatabaseConfig () {
this.dsMap = new HashMap<String, Map<String, String>>();
dsMap.put("sampleDs1", getTestDataSourceInfo());
dsMap.put("sampleDs2", getTestDataSourceInfo());
}
@PostConstruct
public void loadDataSource () {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
this.dsMap.forEach((k,v) -> {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(BasicDataSource.class);
v.forEach((ds_key, ds_val) -> {
builder.addPropertyValue(ds_key, ds_val);
});
BeanDefinition def = builder.getBeanDefinition();
if(!registry.containsBeanDefinition(k)) registry.registerBeanDefinition(k, def);
});
}
}
In above class, I could add java instances to spring bean with BeanDefinitionRegistry
and BeanDefinitionBuilder
.
If this is just a bean, it would be end here, but what you are trying to add is DataSource
bean, have to do some extra work.
Since, boot automatically setting DataSource
, we have to disable that setting to register customized datasource.
In your @SpringbootApplication
class, add @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
.
Now, you are able to user those bean in other beans via @Autowired
and @Qualifier
.
Thanks.
Answered By - Juneyoung Oh