Spring Boot如何动态配置多个Hikari数据源?
动态配置多环境下的Hikari数据源问题
单个Hikari数据源的正常配置
如果只需要配置单个Hikari数据源,直接在application.yml中配置即可:
spring: datasource: app: platform: POSTGRESQL url: jdbc:postgresql://localhost:5432/mydb username: mydbuser password: mydbpass hikari: maximum-pool-size: 15 leak-detection-threshold: 15000 max-lifetime: 900000 data-source-properties: stringtype=unspecified pool-name: defaultHikariPool
对应的Kotlin配置类代码如下:
@Bean @Primary @ConfigurationProperties("spring.datasource.app") fun appDataSourceProperties(): DataSourceProperties { return DataSourceProperties() } @Bean @ConfigurationProperties(prefix = "spring.datasource.app.hikari") fun appDataSource(): HikariDataSource { return appDataSourceProperties() .initializeDataSourceBuilder() .type(HikariDataSource::class.java) .build() }
这种方式可以正常运行,但当数据源数量随部署环境动态变化时,就需要另一种实现方式。
动态多数据源的配置困境
针对数据源数量动态变化的场景,我在application.yml中定义了自定义配置块:
my-custom-parties: parties: - my-custom-party-id: 1 datasource: platform: POSTGRESQL url: jdbc:postgresql://localhost:5432/my-db-1 username: user1 password: pass1 hikari: pool-name: db1HikariPool maximum-pool-size: 3 leak-detection-threshold: 5000 max-lifetime: 900000 data-source-properties: stringtype=unspecified - my-custom-party-id: 2 datasource: platform: POSTGRESQL url: jdbc:postgresql://localhost:5432/my-db-2 username: user2 password: pass2 hikari: pool-name: db2HikariPool maximum-pool-size: 10 leak-detection-threshold: 20000 max-lifetime: 900000 data-source-properties: stringtype=unspecified
同时编写了对应的配置类:
@Component @ConfigurationProperties(prefix = "my-custom-parties") class MyCustomParties { private var parties: List<MyCustomParty> = listOf() fun setParties(parties: List<MyCustomParty>) { this.parties = parties } fun getParties() = parties } class MyCustomParty { lateinit var myCustomPartyId: String private var datasource: DataSourceProperties? = null fun setDatasource(datasource: DataSourceProperties) { this.datasource = datasource } fun getDatasource() = datasource?.initializeDataSourceBuilder()?.type(HikariDataSource::class.java)?.build() }
现在的问题是:代码能初始化Hikari数据源,但无法读取配置文件中的Hikari配置项,而且因为数据源数量随环境变化,不能给每个数据源硬编码@Bean。
正确实现动态配置的方案
1. 拆分配置绑定,单独承接Hikari属性
DataSourceProperties不会自动绑定hikari节点下的配置,所以需要单独定义一个类来承接Hikari的配置项:
class HikariCustomProperties { var poolName: String? = null var maximumPoolSize: Int? = null var leakDetectionThreshold: Long? = null var maxLifetime: Long? = null var dataSourceProperties: String? = null }
然后修改MyCustomParty类,让它同时持有数据源基础配置和Hikari专属配置,并在构建数据源时手动应用Hikari配置:
class MyCustomParty { lateinit var myCustomPartyId: String private var datasource: DataSourceProperties? = null private var hikari: HikariCustomProperties? = null fun setDatasource(datasource: DataSourceProperties) { this.datasource = datasource } fun setHikari(hikari: HikariCustomProperties) { this.hikari = hikari } fun getDatasource(): HikariDataSource? { val dataSource = datasource?.initializeDataSourceBuilder()?.type(HikariDataSource::class.java)?.build() hikari?.let { hikariProps -> dataSource?.apply { // 逐个设置Hikari配置项 hikariProps.poolName?.let { poolName = it } hikariProps.maximumPoolSize?.let { maximumPoolSize = it } hikariProps.leakDetectionThreshold?.let { leakDetectionThreshold = it } hikariProps.maxLifetime?.let { maxLifetime = it } // 处理数据源属性字符串 hikariProps.dataSourceProperties?.let { dsPropsStr -> dsPropsStr.split("&").forEach { prop -> val (key, value) = prop.split("=") addDataSourceProperty(key, value) } } } } return dataSource } }
2. 动态注册数据源到Spring容器(可选)
如果需要在Spring中通过依赖注入使用这些动态数据源,可以实现BeanDefinitionRegistryPostProcessor来动态注册Bean:
@Component class DynamicDataSourceRegistrar( private val myCustomParties: MyCustomParties ) : BeanDefinitionRegistryPostProcessor { override fun postProcessBeanDefinitionRegistry(registry: BeanDefinitionRegistry) { myCustomParties.parties.forEach { party -> val dataSource = party.getDatasource() ?: return@forEach // 定义Bean名称,格式为dataSource-{partyId} val beanName = "dataSource-${party.myCustomPartyId}" val beanDefinition = GenericBeanDefinition().apply { beanClass = HikariDataSource::class.java scope = ConfigurableBeanFactory.SCOPE_SINGLETON // 将构建好的数据源作为构造参数传入 addConstructorArgValue(dataSource) } registry.registerBeanDefinition(beanName, beanDefinition) } } override fun postProcessBeanFactory(beanFactory: ConfigurableListableBeanFactory) { // 无额外处理逻辑 } }
这样Spring启动时会自动读取配置文件中的所有数据源配置,构建对应的HikariDataSource并注册为Bean,后续可以通过@Qualifier("dataSource-1")这样的方式注入指定的数据源。
关键说明
- Spring Boot配置绑定默认支持短横线命名转驼峰,比如配置文件中的
maximum-pool-size会自动映射到Kotlin类的maximumPoolSize属性。 - 如果不需要将数据源注册为Spring Bean,直接通过
MyCustomParties.getParties()获取每个party的数据源即可使用。
内容的提问来源于stack exchange,提问作者Tarmo
相关产品推荐
相关产品推荐

