package com.qianwen.core.tenant.config; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.dynamic.datasource.aop.DynamicDataSourceAnnotationAdvisor; import com.baomidou.dynamic.datasource.creator.DruidDataSourceCreator; import com.baomidou.dynamic.datasource.processor.DsHeaderProcessor; import com.baomidou.dynamic.datasource.processor.DsProcessor; import com.baomidou.dynamic.datasource.processor.DsSessionProcessor; import com.baomidou.dynamic.datasource.processor.DsSpelExpressionProcessor; import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceCreatorAutoConfiguration; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; import javax.sql.DataSource; import com.qianwen.core.tenant.constant.TenantBaseConstant; import com.qianwen.core.tenant.dynamic.DsTenantIdProcessor; import com.qianwen.core.tenant.dynamic.TenantDataSourceAnnotationInterceptor; import com.qianwen.core.tenant.dynamic.TenantDataSourceGlobalAdvisor; import com.qianwen.core.tenant.dynamic.TenantDataSourceGlobalInterceptor; import com.qianwen.core.tenant.dynamic.TenantDataSourceHolder; import com.qianwen.core.tenant.dynamic.TenantDataSourceJdbcProvider; import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Role; import org.springframework.core.annotation.Order; import org.springframework.jdbc.core.JdbcTemplate; @AutoConfigureBefore({DruidDataSourceAutoConfigure.class, DynamicDataSourceAutoConfiguration.class}) @EnableConfigurationProperties({DataSourceProperties.class, DynamicDataSourceProperties.class}) @Configuration(proxyBeanMethods = false) @ConditionalOnProperty(value = {TenantBaseConstant.TENANT_DYNAMIC_DATASOURCE_PROP}, havingValue = "true") @Import({DynamicDataSourceCreatorAutoConfiguration.class}) public class TenantDataSourceConfiguration { @Bean @Primary public DynamicDataSourceProvider dynamicDataSourceProvider(DataSourceProperties dataSourceProperties, DynamicDataSourceProperties dynamicDataSourceProperties) { String driverClassName = dataSourceProperties.getDriverClassName(); String url = dataSourceProperties.getUrl(); String username = dataSourceProperties.getUsername(); String password = dataSourceProperties.getPassword(); DataSourceProperty master = (DataSourceProperty) dynamicDataSourceProperties.getDatasource().get(dynamicDataSourceProperties.getPrimary()); if (master != null) { driverClassName = master.getDriverClassName(); url = master.getUrl(); username = master.getUsername(); password = master.getPassword(); } return new TenantDataSourceJdbcProvider(dynamicDataSourceProperties, driverClassName, url, username, password); } @Bean @Primary public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider, DynamicDataSourceProperties dynamicDataSourceProperties) { DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(); dataSource.setPrimary(dynamicDataSourceProperties.getPrimary()); dataSource.setStrict(dynamicDataSourceProperties.getStrict()); dataSource.setStrategy(dynamicDataSourceProperties.getStrategy()); dataSource.setProvider(dynamicDataSourceProvider); dataSource.setP6spy(dynamicDataSourceProperties.getP6spy()); dataSource.setSeata(dynamicDataSourceProperties.getSeata()); return dataSource; } @ConditionalOnMissingBean @Bean public TenantDataSourceAnnotationInterceptor tenantDataSourceAnnotationInterceptor(DsProcessor dsProcessor, DynamicDataSourceProperties dynamicDataSourceProperties) { return new TenantDataSourceAnnotationInterceptor(Boolean.valueOf(dynamicDataSourceProperties.isAllowedPublicOnly()), dsProcessor); } @ConditionalOnMissingBean @Bean @Role(2) public DynamicDataSourceAnnotationAdvisor dynamicDatasourceAnnotationAdvisor(TenantDataSourceAnnotationInterceptor tenantDataSourceAnnotationInterceptor, DynamicDataSourceProperties dynamicDataSourceProperties) { DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(tenantDataSourceAnnotationInterceptor); advisor.setOrder(dynamicDataSourceProperties.getOrder().intValue()); return advisor; } @ConditionalOnMissingBean @ConditionalOnProperty(value = {TenantBaseConstant.TENANT_DYNAMIC_GLOBAL_PROP}, havingValue = "true") @Bean public TenantDataSourceGlobalInterceptor tenantDataSourceGlobalInterceptor() { return new TenantDataSourceGlobalInterceptor(); } @ConditionalOnMissingBean @ConditionalOnProperty(value = {TenantBaseConstant.TENANT_DYNAMIC_GLOBAL_PROP}, havingValue = "true") @Bean @Role(2) public TenantDataSourceGlobalAdvisor tenantDataSourceGlobalAdvisor(TenantDataSourceGlobalInterceptor tenantDataSourceGlobalInterceptor, DynamicDataSourceProperties dynamicDataSourceProperties) { TenantDataSourceGlobalAdvisor advisor = new TenantDataSourceGlobalAdvisor(tenantDataSourceGlobalInterceptor); advisor.setOrder(dynamicDataSourceProperties.getOrder().intValue() + 1); return advisor; } @ConditionalOnMissingBean @Bean public DsProcessor dsProcessor() { DsHeaderProcessor headerProcessor = new DsHeaderProcessor(); DsSessionProcessor sessionProcessor = new DsSessionProcessor(); DsTenantIdProcessor tenantIdProcessor = new DsTenantIdProcessor(); DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor(); headerProcessor.setNextProcessor(sessionProcessor); sessionProcessor.setNextProcessor(tenantIdProcessor); tenantIdProcessor.setNextProcessor(spelExpressionProcessor); return headerProcessor; } @Configuration(proxyBeanMethods = false) @ConditionalOnProperty(value = {TenantBaseConstant.TENANT_DYNAMIC_DATASOURCE_PROP}, havingValue = "true") @Order public static class TenantDataSourceAnnotationConfiguration implements SmartInitializingSingleton { private final TenantDataSourceAnnotationInterceptor tenantDataSourceAnnotationInterceptor; private final DataSource dataSource; private final DruidDataSourceCreator dataSourceCreator; private final JdbcTemplate jdbcTemplate; public TenantDataSourceAnnotationConfiguration(final TenantDataSourceAnnotationInterceptor tenantDataSourceAnnotationInterceptor, final DataSource dataSource, final DruidDataSourceCreator dataSourceCreator, final JdbcTemplate jdbcTemplate) { this.tenantDataSourceAnnotationInterceptor = tenantDataSourceAnnotationInterceptor; this.dataSource = dataSource; this.dataSourceCreator = dataSourceCreator; this.jdbcTemplate = jdbcTemplate; } public void afterSingletonsInstantiated() { TenantDataSourceHolder tenantDataSourceHolder = new TenantDataSourceHolder(this.dataSource, this.dataSourceCreator, this.jdbcTemplate); this.tenantDataSourceAnnotationInterceptor.setHolder(tenantDataSourceHolder); } } @Configuration(proxyBeanMethods = false) @ConditionalOnProperty(value = {TenantBaseConstant.TENANT_DYNAMIC_GLOBAL_PROP}, havingValue = "true") @Order public static class TenantDataSourceGlobalConfiguration implements SmartInitializingSingleton { private final TenantDataSourceGlobalInterceptor tenantDataSourceGlobalInterceptor; private final DataSource dataSource; private final DruidDataSourceCreator dataSourceCreator; private final JdbcTemplate jdbcTemplate; public TenantDataSourceGlobalConfiguration(final TenantDataSourceGlobalInterceptor tenantDataSourceGlobalInterceptor, final DataSource dataSource, final DruidDataSourceCreator dataSourceCreator, final JdbcTemplate jdbcTemplate) { this.tenantDataSourceGlobalInterceptor = tenantDataSourceGlobalInterceptor; this.dataSource = dataSource; this.dataSourceCreator = dataSourceCreator; this.jdbcTemplate = jdbcTemplate; } public void afterSingletonsInstantiated() { TenantDataSourceHolder tenantDataSourceHolder = new TenantDataSourceHolder(this.dataSource, this.dataSourceCreator, this.jdbcTemplate); this.tenantDataSourceGlobalInterceptor.setHolder(tenantDataSourceHolder); } } }