我正在创建一个使用多租户的 Spring Kotlin 应用程序。我想向我的应用程序添加第二个数据源。
使用 Spring Boot JPA 自动配置,多租户可以在单个数据源上正常工作。我不需要创建任何 DatasourceConfiguration 类。
由于我想添加第二个数据源,所以我不能再依赖自动配置,而是必须为每个数据源创建配置类,如下所示:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
transactionManagerRef = "transactionManagerA",
entityManagerFactoryRef = "entityManagerFactoryA",
basePackages = ["com.myapp.repository.a"]
)
class DataSourceConfigA {
}
多租户是通过
TenantConnectionProvider
类启用的,如下所示:
@Component
class TenantConnectionProvider :
MultiTenantConnectionProvider,
HibernatePropertiesCustomizer {
@Autowired
private lateinit var datasource: DataSource
override fun getAnyConnection(): Connection = datasource.connection
...
}
由于我添加了
DataSourceConfig
类来配置多个数据源,datasource
中的 TenantConnectionProvider
不再自动装配,并且使用多租户的数据库查询失败。
我收到以下错误:
lateinit property dataSource has not been initialized
为什么禁用 JPA 自动配置会破坏我的
TenantConfigProvider
中的数据源自动装配?
如何在 Spring Boot Kotlin 应用程序中结合多租户和多个数据源?
在 MultiTenantConnectionProviderInitializor 类上取得峰值,它为您的应用程序提供
TenantConnectionProvider
。
它从
hibernate.multi_tenant_connection_provider
中搜索 application.yml
配置值。如果它能找到它,它会检查该类是否是 MultiTenantConnectionProvider
的实例,然后返回该类。
在上面的代码中,配置是一个字符串(
com.myapp.config.TenantConnectionProvider
),发起者最终尝试使用implClass.newInstance()
实例化该类,而不自动装配任何bean。 datasource
未初始化,以后的任何连接都将失败。
在数据源配置类中,您可以覆盖
hibernate.multi_tenant_connection_provider
属性以使用使用注入 bean 的 TenantConnectionProvider
实例,如下所示:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
transactionManagerRef = "transactionManagerA",
entityManagerFactoryRef = "entityManagerFactoryA",
basePackages = ["com.myapp.repository.a"]
)
class DataSourceConfigA {
...
@Bean
@Primary
fun tenantConnectionProvider(): MultiTenantConnectionProvider = TenantConnectionProvider()
@Bean(name = ["entityManagerFactoryA"])
@Primary
fun postgresEntityManagerFactory(
dataSource: DataSource,
builder: EntityManagerFactoryBuilder
): LocalContainerEntityManagerFactoryBean {
return builder.dataSource(dataSource)
.packages("com.myapp.domain.a")
// Overwrite hibernate.multi_tenant_connection_provider to use a class instance
.properties(mapOf(Pair("hibernate.multi_tenant_connection_provider", tenantConnectionProvider())))
.build()
}
...
}
这将导致发起者使用您自己的实例,而不是尝试实例化没有自动装配 bean 的类。