I am implementing a multi-tenant architecture in my Spring application. The ConfigurationDataSource class is used to provide a DataSource when the application starts. Below is the detailed implementation of the class:
ConfigurationDataSource
import com.example.hikaricp_demo.domain.TenantConfig;
import com.example.hikaricp_demo.repository.TenantConfigRepository;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Configuration
public class ConfigurationDataSource {
@Autowired
private TenantConfigRepository repository;
private List<TenantConfig> getListTenant(){
return repository.findAll();
}
TenantConfig tenantDefault() {
return repository.findByTenantId("tenantDefault");
}
@Bean
public DataSource dataSource() {
Map<Object, Object> resolvedDataSources = new HashMap<>();
List<TenantConfig> listTenant = getListTenant();
for (TenantConfig item : listTenant) {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setDriverClassName(item.getDriverClassName());
hikariConfig.setJdbcUrl(item.getUrl());
hikariConfig.setUsername(item.getUsername());
hikariConfig.setPassword(item.getPassword());
hikariConfig.setSchema(item.getSchema());
HikariDataSource dataSource = new HikariDataSource(hikariConfig);
resolvedDataSources.put(item.getTenantId(), dataSource);
}
AbstractRoutingDataSource dataSource = new MultiTenantDataSource();
dataSource.setDefaultTargetDataSource(tenantDefault());
dataSource.setTargetDataSources(resolvedDataSources);
dataSource.afterPropertiesSet();
return dataSource;
}
}
The TenantConfigRepository is a Spring Data JPA repository that interacts with the database to fetch tenant configurations. When I run the application, I get the following error:
Description:
The dependencies of some of the beans in the application context form a cycle:
entityManagerFactory defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]
┌─────┐
| dataSourceScriptDatabaseInitializer defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]
↑ ↓
| configurationDataSource (field private com.example.hikaricp_demo.repository.TenantConfigRepository com.example.hikaricp_demo.config.ConfigurationDataSource.repository)
↑ ↓
| tenantConfigRepository defined in com.example.hikaricp_demo.repository.TenantConfigRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration
↑ ↓
| jpaSharedEM_entityManagerFactory
└─────┘
I suspect this happens because:
The dataSource bean depends on TenantConfigRepository (to fetch tenant configurations using repository.findAll()).
The TenantConfigRepository might also depend on DataSource, creating a circular dependency.