I have a project split into 3 modules (so far) - core (Model 1), user-management (model 2) and web (View and Controller). My project structure (simplified to only relevant classes for the sake of getting to the point) is as follows:
Project
|-- core
| |-- src.main.java.com.romco.example
| | |-- config.CoreDataSourceConfiguration
| | |-- persistence.daoimpl.SomeCoreDaoImpl
|-- user-management
| |-- src.main.kotlin.com.romco.example
| | |-- config.UserManagementConfiguration
| | |-- persistence.daoimpl.SomeUserManagementDaoImpl
|-- web
| // not important right now
My classes are as follows (while debugging my previous issue, I had to move some value initialization directly to code instead of using application.properties, as noted by the TODO, so please ignore it for the sake of the problem at hand)
- CoreDataSourceConfiguration:
@Configuration
public class CoreDataSourceConfiguration {
@Bean
@Primary
public DataSourceProperties coreDataSourceProperties() {
return new DataSourceProperties();
}
//TODO values should be retrieved from application.properties
@Bean(name = "coreDataSource")
@Primary
public DataSource coreDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName("com.mysql.cj.jdbc.Driver");
dataSourceBuilder.url("...");
dataSourceBuilder.username("...");
dataSourceBuilder.password("...");
return dataSourceBuilder.build();
}
@Bean(name = "coreTransactionManager")
@Autowired
DataSourceTransactionManager coreTransactionManager(@Qualifier("coreDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
- SomeCoreDaoImpl:
@Repository
public class SomeCoreDaoImpl implements SomeCoreDao {
// some constants here
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Autowired
@Override
public void setDataSource(DataSource dataSource) {
namedParameterJdbcTemplate = NamedParameterJdbcTemplateHolder.get(dataSource);
}
// DB code here - create, update, etc.
}
- UserManagementConfiguration:
@Configuration
open class UserManagementDataSourceConfiguration {
@Bean
open fun userManagementDataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
@Bean(name = ["userManagementDataSource"])
open fun userManagementDataSource(): DataSource {
val dataSourceBuilder = DataSourceBuilder.create()
dataSourceBuilder
.driverClassName("com.mysql.cj.jdbc.Driver")
.url("...")
.username("...")
.password("...")
return dataSourceBuilder.build()
}
@Bean(name = ["userManagementTransactionManager"])
@Autowired
open fun userManagementTransactionManager(@Qualifier("userManagementDataSource") dataSource: DataSource): DataSourceTransactionManager {
return DataSourceTransactionManager(dataSource)
}
}
- SomeUserManagementDaoImpl:
@Repository
open class SomeUserManagementDaoImpl: SomeUserManagementDao{
// constants are here
private lateinit var namedParameterJdbcTemplate: NamedParameterJdbcTemplate
@Autowired
fun setDataSource(@Qualifier("userManagementDataSource") dataSource: DataSource) {
namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
}
// DB code here
}
As you can see, the way I made it work is by specifying which bean to use in the autowired setDataSource method inside my SomeUserManagementDaoImpl class.
I would obviously prefer to avoid having to do this in every daoImpl class, and while I can think of extracting this to a single class, it doesn't seem like that's the "spring" intended solution.
Now (again, obviously) - The data sources are module-specific, and initially, I even assumed spring would somehow figure it out under the hood and, instead of using the @Primary datasource, would use the one defined in a given module (unless that module had none, in which case I assumed it would fall back to the @Primary one).
However, that was not the case, and I'm left wondering if there is some way to tell spring to use a given data source configuration across that entire module...
I've been looking at many similiar threads and guides that deal with multi-datasource projects, but I actually never found the answer. In fact, the guides which I consulted when I was implementing my multi-datasource solution never mentioned this at all (unless I missed it), eg.
https://www.baeldung.com/spring-boot-failed-to-configure-data-source
https://www.baeldung.com/spring-data-jpa-multiple-databases
It is also entirely possible that I'm doing something else terribly wrong, and that is the root cause, in which case, please, also help me out.