Reputation: 492
Hy all,
in my current application, I need to be able to load a number of database connections into my context (they are then used in camel routes, but thats not part of this question).
For this I have a List of settings in my application.yml file, where each entry is all that is needed for one connection:
- name: mysql1
jdbcUrl: "jdbc:mysql://localhost:3306/dbScheme"
username: a
password: a
- name: mssql1
jdbcUrl: "jdbc:sqlserver://localhost:1433;databaseName=dbScheme"
username: a
password: a
There is a variable amount of connections, that can be configured this way.
I need each of those configurations as a javax.sql.DataSource
object/bean in the registy (bean name would be the name property from the configuration object):
DataSource dataSourceBean = DataSourceBuilder.create()
.driverClassName(driverClassName) // Resolved automatically from the jdbcUrl
.url(dataSourceFromYaml.getJdbcUrl())
.username(dataSourceFromYaml.getUsername())
.password(dataSourceFromYaml.getPassword())
.build();
The question now is, how I do put those objects into the context as beans?
As I see it, its not possible with annotations, because we have a variable amount of objects and they are also not loaded into the context directly, but have to be created first. (Or am I wrong here?)
Thanks in advance for any ideas
Chris
Edit:
To clarify: The two connections I put here are not the connections used in production, they are just an example.
The issue is, that they are configured in production and there can be any amount of them.
I have no way of predicting how many there are and how they are named.
Upvotes: 2
Views: 959
Reputation: 2293
If you don't have list of datasources beforehand and want to configure this dynamically you can do following thing:
1) In your application.yml:
datasources:
ds1:
name:
pw:
ds2:
name:
pw:
2) Create properties class:
@Configuration
@ConfigurationProperties(prefix = "datasources")
public class DataSourcesInfo {
Map<String, DataSourceInfo> dataSources;
public @Data static class DataSourceInfo {
private String pw;
private String name;
}
}
In this map you will have list of entries for all datasources defined.
3) And now you can create beans dynamically:
@Configuration
public class Config {
@Autowired
private GenericApplicationContext genericApplicationContext;
@Autowired
DataSourcesInfo properties;
@PostConstruct
public void createDataSources() {
// iterate through properties and register beans
genericApplicationContext.registerBean(dataSourceName,
DataSource.class,
() -> {
DataSource ds = new DataSource();
ds.set(...);
....
return ds;
})
}
}
Upvotes: 0
Reputation: 492
After trying a lot of different spring context objects I finally found one, that worked.
Here is the solution:
@Configuration
@ConfigurationProperties(prefix = "jdbc")
@RequiredArgsConstructor // Lombok
public class DataSourceBeanFactory {
// The DataSourceConfiguration holds everything from one property object
@Setter // Lombok
private List<DataSourceConfiguration> dataSources;
private final ConfigurableApplicationContext applicationContext;
@PostConstruct
public void resolveAndCreateDataSourceBeans() {
dataSources.forEach(dataSourceFromYaml -> {
/*
* Code to resolve driver class name
*/
String driverClassName = ....
DataSource dataSourceBean = DataSourceBuilder.create()
.driverClassName(driverClassName)
.url(dataSourceFromYaml.getJdbcUrl())
.username(dataSourceFromYaml.getUsername())
.password(dataSourceFromYaml.getPassword())
.build();
applicationContext
.getBeanFactory()
.registerSingleton(dataSourceFromYaml.getName(), dataSourceBean);
});
}
Thank to everybody, that answered my question.
Chris
Upvotes: 2
Reputation: 991
You could use the following approach
create properties file application-dev.properties
mysql1.jdbc.jdbcUrl=jdbc:mysql://localhost:3306/dbScheme
mysql1.jdbc.username=a
mysql1.jdbc.password=a
mssql1.jdbc.jdbcUrl=jdbc:sqlserver://localhost:1433;databaseName=dbScheme
mssql1.jdbc.username=a
mssql1.jdbc.password=a
Create configuration class
@Configuration
public class JDBCConfigExample {
@Bean(name = "mysql1DataSource")
@ConfigurationProperties(prefix = "mysql1.jdbc")
public DataSource mysql1DataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "mssql1DataSource")
@ConfigurationProperties(prefix = "mssql1.jdbc")
public DataSource mssql1DataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "mysql1JdbcTemplate")
public JdbcTemplate mysql1JdbcTemplate(@Qualifier("mysql1DataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean(name = "mssql1JdbcTemplate")
public JdbcTemplate mssql1JdbcTemplate(@Qualifier("mssql1DataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
After that you could use both JdbcTemplate and DataSource in any Spring managed bean by using Qualifier or name convention:
private final JdbcTemplate mssql1JdbcTemplate;
Upvotes: 1